啃论文俱乐部——移植 speexdsp 到 OpenHarmony 标准系统②
大家好!我来自南京,在 OpenHarmony 成长计划啃论文俱乐部,与
华为、软通动力、润和软件、拓维信息、深开鸿
等公司一起,学习和研究操作系统技术
,从今年 1 月 11 日加入 OpenHarmony 俱乐部已经有接近 8 个月时间了。笔者一直在思考啃论文给我带来了些什么,通过啃论文能为 OpenHarmony 做些什么。笔者利用大二升大三暑假两个月时间移植了 Speexdsp 这个三方库到 OpenHarmony 标准系统,而关于前面的问题我似乎找到了答案,现将啃论文和三方库移植分享经验如下:
由于想要分享的内容较多,为避免读者姥爷们失去看下去的耐心,分享将以连载的方式进行。

在 linux 上生成 speexdsp 的 so 动态链接库和.a 静态链接库
make 和 make install 后会生成 speexdsp 的.so 动态链接库和.a 静态链接库

其中 build/lib 目录下:
linux 下的 so、o、lo、a、la 文件
o: 编译的目标文件
a: 静态库,其实就是把若干 o 文件打了个包
so: 动态链接库(共享库) 动态库文件必须以 lib 开头,以.so 结尾
lo: 使用 libtool 编译出的目标文件,其实就是在 o 文件中添加了一些信息
la: 使用 libtool 编译出的库文件,其实是个文本文件,记录同名动态库和静态库的相关信息
知识拓展:
函数库分为静态库*a 和动态库*.so 两种:①静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。②动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。
符号链接(symbolic link)是 Linux 系统中的一种文件,它指向系统中的另一个文件或目录。符号链接类似于 Windows 系统中的快捷方式。
在 linux 中,*.la 是记录同名动态库和静态库相关信息的文本文件。
三、分析 speexdsp 在标准 Linux 系统的编译过程文件
分析 speexdsp 在标准 Linux 系统的编译过程文件,找到生成 so 库和测试用的可执行文件所需的.c 源代码,头文件路径,cflags 编译器标志,所依赖的库。
对比编译前后的 speexdsp 原生库结构
tree 工具能以树形的方式显示指定目录的层级结构。非绿色字体是编译后生成的文件。
├── ├── #speexdsp 项目作者信息├── #autogen.sh 脚本配置文件├── aclocal.m4 #运行 aclocal 后生成的 aclocal.m4 文件和一个缓冲文件夹 autom4te.cache├── autom4te.cache│ ├── output.0│ ├── output.1│ ├── output.2│ ├── requests│ ├── traces.0│ ├── traces.1│ └── traces.2├── build│ ├── include│ │ └── speex│ │ ├── speexdsp_config_types.h│ │ ├── speexdsp_types.h│ │ ├── speex_echo.h│ │ ├── speex_jitter.h│ │ ├── speex_preprocess.h│ │ └── speex_resampler.h│ ├── lib│ │ ├── libspeexdsp.a│ │ ├── libspeexdsp.la│ │ ├── libspeexdsp.so -> libspeexdsp.so.1.5.2│ │ ├── libspeexdsp.so.1 -> libspeexdsp.so.1.5.2│ │ ├── libspeexdsp.so.1.5.2│ │ └── pkgconfig│ │ └── speexdsp.pc│ └── share│ └── doc│ └── speexdsp│ └── manual.pdf├── #spexxds 原生库更新日志(和本次移植无关信息)├── ├── #这个是在构建环境上运行的一个脚本,它用来猜测构建机的配置环境,因为这个脚本是在构建机上运行,所以它可以动态执行 uname 等命令来获得构建机的环境,所以我们一般不要指定这个变量,从而让脚本自动获得。├── config.h#Config.h 是自动生成的头文件,是根据配置文件 Config.h.in 生成的。config.h 主要用于代码移植,产生可移植代码。├── config.h.in#autoheader 后形成 config.h.in├── config.log#该文件在执行 configure 文件时动态生成,包含了一些行号信息,表示一个文件在哪一行执行,以及执行的什么命令,因此可以知道测试是在哪个位置中完成。├── #这是脚本文件,运行该脚本可以生成一个当前相同的配置,从而避免再次执行 configure 这个比较庞大的代码。也就是 config.log 生成的是文本文件,而 config.status 生成的则是命令脚本文件。├── #这个是将 host target build 变量正则化的一个脚本,它的 sub 就是 substitute 的缩写。因为用户提供的 build 可能并不符合脚本正规的四元组或者三元组的结构,所以这个脚本将它转换为标准的格式,从而可以进行格式化处理。├── #这个是我们需要监测环境的主要入口文件,使用该文件可以生成 Makefile 文件,它会替换 Makefile 中需要替换的变量。├── #该文件为 autoconfigure 文件使用的一个文件,该文件用来生成 configure 文件,这个文件一般是开发者维护,我们安装该软件的时候只需要执行 configure 就可以,这个 configure.ac 我们一般不用理会├── ├── #automake --add-missing 命令生成 install-sh, missing, depcomp 文件├── │ ├── │ ├── │ ├── │ ├── │ ├── │ ├── │ ├── Makefile│ ├── │ ├── Makefile.in│ ├── │ ├── │ ├── │ ├── │ ├── │ ├── │ ├── │ ├── │ ├── │ └── ├── ├── │ ├── │ ├── │ └── ├── │ ├── Makefile│ ├── │ ├── Makefile.in│ └── │ ├── Makefile│ ├── │ ├── Makefile.in│ ├── │ ├── speexdsp_config_types.h│ ├── │ ├── │ ├── │ ├── │ ├── │ └── ├── ├── #automake --add-missing 命令生成 install-sh, missing, depcomp 文件├── │ ├── │ ├── │ ├── │ ├── buffer.lo│ ├── buffer.o│ ├── │ ├── │ ├── │ ├── fftwrap.lo│ ├── fftwrap.o│ ├── │ ├── │ ├── filterbank.lo│ ├── filterbank.o│ ├── │ ├── │ ├── │ ├── │ ├── │ ├── │ ├── jitter.lo│ ├── jitter.o│ ├── │ ├── │ ├── │ ├── │ ├── │ ├── libspeexdsp.la│ ├── Makefile│ ├── │ ├── Makefile.in│ ├── │ ├── │ ├── mdf.lo│ ├── mdf.o│ ├── │ ├── │ ├── │ ├── preprocess.lo│ ├── preprocess.o│ ├── │ ├── │ ├── resample.lo│ ├── │ ├── resample.o│ ├── │ ├── │ ├── scal.lo│ ├── scal.o│ ├── │ ├── │ ├── smallft.lo│ ├── smallft.o│ ├── │ ├── #测试噪音抑制的文件│ ├── testdenoise.o│ ├── │ ├── #测试声学回音消除的文件│ ├── testecho.o│ ├── # 测试抖动的文件│ ├── │ ├── testjitter.o│ ├── │ ├── │ ├── #测试重采样的文件│ ├── testresample2.o│ ├── #测试重采样的文件│ ├── testresample.o│ └── ├── ├── ltmain.sh├── m4│ ├── libtool.m4│ ├── lt~obsolete.m4│ ├── ltoptions.m4│ ├── ltsugar.m4│ └── ltversion.m4├── │ ├── │ │ └── │ ├── │ ├── │ ├── │ │ └── │ └── │ └── ├── Makefile├── ├── Makefile.in├── #automake --add-missing 命令生成 install-sh, missing, depcomp 文件├── ├── ├── #汇聚式处理器 Blackfin 是由 ADI 和 Intel 公司联合开发的微信号架构(MSA)├── #Trimedia 是由 Philips 公司 1996 年推出的新一代媒体处理器(Media Processor)芯片。├── #Win32 是指 Microsoft Windows 操作系统的 32 位环境├── │ └── ├── ├── ├── speexdsp.pc├── ├── SpeexDSP.spec├── ├── stamp-h1├── │ ├── │ ├── │ ├── Makefile│ ├── │ ├── Makefile.in│ └── ├── #TI 公司 DSP 芯片│ ├── │ ├── Makefile│ ├── │ ├── Makefile.in│ ├── │ ├── │ │ ├── Makefile│ │ ├── │ │ ├── Makefile.in│ │ ├── │ │ └── │ ├── │ │ ├── Makefile│ │ ├── │ │ ├── Makefile.in│ │ ├── │ │ └── │ └── │ ├── Makefile│ ├── │ ├── Makefile.in│ ├── │ └── ├── │ ├── │ ├── │ ├── │ ├── │ ├── │ ├── │ ├── │ ├── │ ├── │ ├── │ ├── │ └── ├── └── ├── ├── │ ├── │ ├── │ ├── │ ├── Makefile│ ├── │ └── Makefile.in├── ├── Makefile├── ├── Makefile.in├── ├── │ ├── │ │ ├── │ │ ├── Makefile│ │ ├── │ │ └── Makefile.in│ ├── │ ├── Makefile│ ├── │ ├── Makefile.in│ └── │ ├── Makefile│ ├── │ ├── Makefile.in│ ├── │ ├── │ └── ├── │ ├── │ │ ├── │ │ ├── Makefile│ │ ├── │ │ └── Makefile.in│ ├── │ ├── Makefile│ ├── │ ├── Makefile.in│ └── │ ├── Makefile│ ├── │ ├── Makefile.in│ ├── │ ├── │ └── └── ├── │ ├── │ ├── Makefile│ ├── │ └── Makefile.in├── ├── Makefile├── ├── Makefile.in└── ├── Makefile├── ├── Makefile.in├── ├── └──
分析原生库下 make.am 文件
make.am 是一种比 Makefile 文件抽象程序更高的编译规则文件。 在里面可以指定生成目录,编译用的源码,编译的时候依赖哪些库,要安装到什么目录。
原生库根目录下的 make.am 如下
父目录需要包含子目录,在父目录下的 Makefile.am 中需要添加: SUBDIRS = 子目录。可知 speexdsp 子目录为 libspeexdsp include doc win32 symbian ti 。再逐步查看各个文件夹源码可知只有libspeexdsp
include
文件夹与本次移植有关。所以接下来查看 libspeexdsp 目录下的 make.am 文件
子目录 libspeexdsp 下的 make.am
通过分析 libspeexdsp 下的 make.am 可以知道:
编译出 so 库需要的.c 源文件有 preprocess.c jitter.c mdf.c fftwrap.c filterbank.c resample.cbuffer.c scal.c、smallft.c
编译出 so 库需要的.h 源文件有 arch.h bfin.h fixed_arm4.h fixed_arm5e.h fixed_bfin.h fixed_debug.h math_approx.h misc_bfin.h fftwrap.h filterbank.h fixed_generic.h os_support.h pseudofloat.h smallft.h vorbis_psy.h resample_sse.h resample_neon.h
编译出测试用的 testdenoise testecho testjitter testresample testresample2 可执行文件需要的.c 源文件有 testdenoise.c testec.c hotestjitter.c testresample.c testresample2.c
分析原生库下 Makefile 文件
Makefile 里有什么?Makefile 里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。
显式规则。显式规则说明了如何生成一个或多个目标文件。这是由 Makefile 的书写者明显指出要生成的文件、文件的依赖文件和生成的命令。
隐晦规则。由于我们的 make 有自动推导的功能,所以隐晦的规则可以让我们比较简略地书写 Makefile,这是由 make 所支持的。
变量的定义。在 Makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点像你 C 语言中的宏,当 Makefile 被执行时,其中的变量都会被扩展到相应的引用位置上。
文件指示。其包括了三个部分,一个是在一个 Makefile 中引用另一个 Makefile,就像 C 语言中的 include 一样;另一个是指根据某些情况指定 Makefile 中的有效部分,就像 C 语言中的预编译 #if 一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。
注释。Makefile 中只有行注释,和 UNIX 的 Shell 脚本一样,其注释是用 # 字符,这个就像 C/C++中的 // 一样。如果你要在你的 Makefile 中使用 # 字符,可以用反斜杠进行转义,如: # 。
笔者在 speexdsp 根目录下的 makefile(最基本的 Makefile)文件中搜索关键字CFLAGS
找到 CFLAGS = -g -O2 -fvisibility=hidden 这条语句

分析“make”过程 log
以下是执行 make 命令后在终端显示的部分 log,通过分析也可以知道编译 so 库需要的.c 文件均位于 libspeexdsp 目录。
分析 build 安装目录下生成的.pc 文件
下图为 build/lib/pkgconfig 目录的 speexdsp.pc 文件

*.pc 文件的所有参数:Name: 该模块的名字,比如你的 pc 名字是 xxxx.pc,那么名字最好也是 xxxx。Description: 模块的简单描述。上文 pkg-config –list-all 命令出来的结果,每个名字后面就是 description。URL: 用户可以通过该 URL 获得更多信息,或者下载信息。也是辅助的,可要可不要。Version: 版本号。Requires: 该模块有木有依赖于其他模块。一般没有。Requires.private: 该模块有木有依赖于其他模块,并且还不需要第三方知道的。一般也没有。Conflicts: 有没有和别的模块冲突。常用于版本冲突。比如,Conflicts: bar < 1.2.3,表示和 bar 模块的 1.2.3 以下的版本有冲突。Cflags: 这个就很重要了。pkg-config 的参数–cflags 就指向这里。主要用于写本模块的头文件的路径。Libs: 也很重要,pkg-config 的参数–libs 就指向这里。主要用于写本模块的库/依赖库的路径。Libs.private: 本模块依赖的库,但不需要第三方知道。
在文件中的第 14 行中清楚的指出 speexdsp 依赖-lm 这个库。
分析运行 configure 命令后生成的 config.log

从中也可以分析出 speexdsp 依赖的库-lm
和编译器需要添加的 C_FLAGS 标记-g -O2 -fvisibility=hidden
结论
speexdsp 依赖的库为-lm
编译出 speexdsp 动态链接库需要的.c 源文件为 preprocess.c jitter.c mdf.c fftwrap.c filterbank.c resample.c buffer.c scal.c、smallft.c。
编译出 speexdsp 动态链接库需要的.h 源文件目录为 libspeexdsp
编译出测试用的 testdenoise testecho testjitter testresample testresample2 可执行文件需要的.c 源文件有 testdenoise.c testec.c hotestjitter.c testresample.c testresample2.c
编译出测试用的 testdenoise testecho testjitter testresample testresample2 可执行文件需要的.h 源文件目录为根目录下 include
编译时需要添加的 cflags 编译器标志为
-o
-g
-O2
-fvisibility=hidden
。
下期分享内容:将三方库加入到 OpenHarmony 的编译体系
版权声明: 本文为 InfoQ 作者【离北况归】的原创文章。
原文链接:【http://xie.infoq.cn/article/311cf42e097505213c4bc535e】。文章转载请联系作者。
评论