写点什么

啃论文俱乐部——移植 speexdsp 到 OpenHarmony 标准系统②

作者:离北况归
  • 2022-10-12
    江苏
  • 本文字数:10892 字

    阅读完需:约 36 分钟

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

由于想要分享的内容较多,为避免读者姥爷们失去看下去的耐心,分享将以连载的方式进行。





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


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


makemake install
复制代码



其中 build/lib 目录下:


├── libspeexdsp.a                              /*静态库*/├── libspeexdsp.la                             /*记录同名动态库和静态库相关信息的la文本文件*/├── libspeexdsp.so -> libspeexdsp.so.1.5.2  ├── libspeexdsp.so.1 -> libspeexdsp.so.1.5.2   /*符号链接*/├── libspeexdsp.so.1.5.2                       /*动态库*/└── pkgconfig                                  /*pkgconfig 的 *.pc文件*/    └── speexdsp.pc
复制代码


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 如下

## Process this file with automake to produce Makefile.in. -*-Makefile-*-
# To disable automatic dependency tracking if using other tools than# gcc and gmake, add the option 'no-dependencies'AUTOMAKE_OPTIONS = 1.8ACLOCAL_AMFLAGS = -I m4
pkgconfigdir = $(libdir)/pkgconfigpkgconfig_DATA = speexdsp.pc
EXTRA_DIST = SpeexDSP.spec SpeexDSP.spec.in SpeexDSP.kdevelop speexdsp.pc.in README.blackfin
#Fools KDevelop into including all filesSUBDIRS = libspeexdsp include doc win32 symbian ti
DIST_SUBDIRS = libspeexdsp include doc win32 symbian ti
rpm: dist rpmbuild -ta ${PACKAGE}-${VERSION}.tar.gz
复制代码


父目录需要包含子目录,在父目录下的 Makefile.am 中需要添加: SUBDIRS = 子目录。可知 speexdsp 子目录为 libspeexdsp include doc win32 symbian ti 。再逐步查看各个文件夹源码可知只有libspeexdsp include文件夹与本次移植有关。所以接下来查看 libspeexdsp 目录下的 make.am 文件

子目录 libspeexdsp 下的 make.am

# Disable automatic dependency tracking if using other tools than gcc and gmake#AUTOMAKE_OPTIONS = no-dependencies
EXTRA_DIST=echo_diagnostic.m
AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include/speex -I$(top_builddir) @FFT_CFLAGS@/*top_srcdir工程最顶层目录*//*top_builddir定义生成目标文件的最上层目录*/
lib_LTLIBRARIES = libspeexdsp.la
# Sources for compilation in the libraryif BUILD_KISS_FFT FFTSRC=kiss_fft.c _kiss_fft_guts.h kiss_fft.h kiss_fftr.c kiss_fftr.h elseif BUILD_SMALLFT FFTSRC=smallft.celse FFTSRC=endifendif
libspeexdsp_la_SOURCES = preprocess.c jitter.c mdf.c fftwrap.c filterbank.c resample.c buffer.c scal.c $(FFTSRC)/*编译libspeexdsp.so需要preprocess.c jitter.c mdf.c fftwrap.c filterbank.c resample.c buffer.c scal.c、smallft.c源文件(特别需要注意$(FFTSRC)的存在,因为FFTSRC=smallft.c)*/
/*noinst_HEADERS:这个表示该头文件只是参加可执行文件的编译,而不用安装到安装目录下。如果需要安装到系统中,可以用 include_HEADERS来代替。*/noinst_HEADERS = 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
libspeexdsp_la_LDFLAGS = -no-undefined -version-info/*LDFLAGS:编译时的选项*/ @SPEEXDSP_LT_CURRENT@:@SPEEXDSP_LT_REVISION@:@SPEEXDSP_LT_AGE@libspeexdsp_la_LIBADD = $(LIBM)
if BUILD_EXAMPLES /*编译测试文件*/ noinst_PROGRAMS = testdenoise testecho testjitter testresample testresample2testdenoise_SOURCES = testdenoise.ctestdenoise_LDADD = libspeexdsp.la@FFT_LIBS@ /*链接需要libspeexdsp.la库文件*/testecho_SOURCES = testecho.c /*需要的testecho_LDADD = libspeexdsp.la @FFT_LIBS@ /*链接需要libspeexdsp.la库文件*/testjitter_SOURCES = testjitter.ctestjitter_LDADD = libspeexdsp.la @FFT_LIBS@ /*链接需要libspeexdsp.la库文件*/testresample_SOURCES = testresample.ctestresample_LDADD = libspeexdsp.la @FFT_LIBS@ @LIBM@ /*链接需要libspeexdsp.la库文件*/testresample2_SOURCES = testresample2.ctestresample2_LDADD = libspeexdsp.la @FFT_LIBS@ @LIBM@ /*链接需要libspeexdsp.la库文件*/endif
复制代码


通过分析 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 目录。


jiajiahao@ubuntu:~/Desktop/speexdsp-SpeexDSP-1.2.1$ makemake  all-recursivemake[1]: 进入目录“/home/jiajiahao/Desktop/speexdsp-SpeexDSP-1.2.1”Making all in libspeexdspmake[2]: 进入目录“/home/jiajiahao/Desktop/speexdsp-SpeexDSP-1.2.1/libspeexdsp”  CC       preprocess.lo  CC       jitter.lo  CC       mdf.lo  CC       fftwrap.lo  CC       filterbank.lo  CC       resample.lo  CC       buffer.lo  CC       scal.lo  CC       smallft.lo  CCLD     libspeexdsp.lamake[2]: 离开目录“/home/jiajiahao/Desktop/speexdsp-SpeexDSP-1.2.1/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


configure:9932: checking for cos in -lmconfigure:9957: gcc -o conftest -g -O2 -fvisibility=hidden   conftest.c -lm   >&5
复制代码

结论

  • 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 的编译体系

发布于: 刚刚阅读数: 3
用户头像

离北况归

关注

还未添加个人签名 2022-03-26 加入

OpenHarmony啃论文俱乐部PIMF团队。 位于南京一学生,可私信。

评论

发布
暂无评论
啃论文俱乐部——移植speexdsp到OpenHarmony标准系统②_OpenHarmony_离北况归_InfoQ写作社区