1 关键字

gn文件,ldflags

2 问题描述

代码版本:OpenHarmony-v3.1-Release

问题现象:在需要第三方so库文件的gn文件中使用ldflags = [ "-l//目录路径//库文件名" ] 使用这个库文件,并未编译成功提示链接找不到。

3 问题原因

3.1 正常机制

在需要第三方so库文件的gn文件中使用ldflags = [ "-l//目录路径//库文件名" ] 使用这个库文件,能成功编译。

3.2 异常机制

编译时提示链接找不到

4 解决方案

以编译和链接使用tinyalsa库为例进行示范说明:

1、OpenHarmony系统中要链接使用tinyalsa库的BUILD.gn添加信息,信息包含tinyalsa库的搜索路径和库名称:

举例:

ldflags = [ "-L../../third_party/tinyalsa/src/" ]
ldflags += [ "-ltinyalsa" ]

 

2、修改tinyalsa库源码中的库输出Makefile文件,将编译输出名称改为libtinyalsa.z.so:

tinyalsa库源码中的库输出Makefile文件要修改的部分,主要包含两个方面:修改文件名和修改库文件中内嵌的soname字段:

libtinyalsa.a: $(OBJECTS)
$(AR) $(ARFLAGS) $@ $^
​
libtinyalsa.z.so: libtinyalsa.so #1、这里新增了两行,建立一个软连接目标,将libtinyalsa.so库软链接为libtinyalsa.z.so
ln -sf $< $@
​
libtinyalsa.so: libtinyalsa.so.$(LIBVERSION_MAJOR)
ln -sf $< $@
​
libtinyalsa.so.$(LIBVERSION_MAJOR): libtinyalsa.so.$(LIBVERSION)
ln -sf $< $@
​
libtinyalsa.so.$(LIBVERSION): $(OBJECTS)
$(LD) $(LDFLAGS) -shared -Wl,-soname,libtinyalsa.z.so $^ -o $@ #2、这里将原来的libtinyalsa.so.$(LIBVERSION_MAJOR)更改为libtinyalsa.z.so

 

 

5 定位过程

1、链接失败原因定位分析:

默认gn语法中在gn文件中使用shared_library库模板时,ldflags依赖的定义直接为被依赖的库名称(例如:ldflags = [ "-la" ]表示链接a.so)

shared_library("a") {
...
}
shared_library("b") {
...
ldflags = [ "-la" ]
deps = []
...
}

OpenHarmony中gn定制了OpenHarmony共享库模板ohos_shared_library,该库模板编译默认生成的so文件会在文件名前添加lib前缀,文件名后缀会补充.z.so。经过实践检验确认该库模板通过ldflags链接so库时,-l后面跟着的指定的文件名,实际指向的文件也是默认会在该文件名添加lib前缀和.z.so后缀:

举例:ldflags = [ "-la" ],编译时ohos_shared_library模板会去寻找liba.z.so库文件进行链接。

而通常Linux下的Makefile文件编译出来的文件名默认时不会添加.z字段进去的,而且库文件中内嵌的用于查找验证的soname文件名也没有添加进.z字段。因此编译出来的so在gn中链接时会提示链接找不到。解决了这两个问题,以及gn使用时指定了正确的库文件搜索路径,就不会提示链接找不到了。

6 知识分享

soname的目的主要是允许系统中多个版本的库文件共存,习惯上在命名库文件的时候通常与soname相同

soname提供了库链接的兼容性的标准,当要升级系统中的一个库时,新库的soname和老库的soname一样,用旧库链接生成的程序使用新库依然能正常运行。这使得在Linux下,升级使用共享库的程序和定位错误更简单。

在Linux中,应用程序通过使用soname,来指定所希望库的版本,库作者可以通过保留或改变soname来声明,哪些版本是兼容的,这使得程序员摆脱了共享库版本冲突问题的困扰。当库作者不想老的程序使用新库时,改变新库soname名称,使之不与老库的soname名称相同。

查看soname的命令:

可以通过readelf -d来查看每个动态库的SONAME。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐