使用ldflags时链接找不到的问题分析报告
1 关键字 gn文件,ldflags 2 问题描述 代码版本:OpenHarmony-v3.1-Release 问题现象:在需要第三方so库文件的gn文件中使用ldflags = [ "-l//目录路径//库文件名" ] 使用这个库文件,并未编译成功提示链接找不到。 3 问题原因 3.1 正常机制 在需要第三方so库文件的gn文件中使用ldflags = [ "-l//目录路径//库文件名" ]
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。
更多推荐
所有评论(0)