GNU链接器ld指定特定路径库及libmetis链接错误问询
一、让ld优先选择/opt/lib下的libxxx.so
要让GNU ld(链接器,不是动态链接器ld.so)指定使用/opt/lib下的目标库,有两种可靠的方式:
直接指定库的绝对路径(最稳妥,无歧义):
链接时直接用库的完整路径替代-lxxx参数,比如:/opt/lib/libxxx.so这样ld会直接使用这个特定文件,不会去搜索其他路径。
调整
-L参数的顺序:
ld会按照遇到-L参数的先后顺序搜索库路径,所以把-L/opt/lib放在所有可能包含同名库的路径(比如-L/usr/local/lib、系统默认路径)之前,并且要放在-lxxx参数的前面。例如:-L/opt/lib -L/usr/local/lib -lxxx这样ld在找
libxxx.so时会先检查/opt/lib,找到后就不会再去后面的路径搜索。
二、解决libmetis的TLS/非TLS符号冲突问题
你遇到的错误是因为两个不同版本的libmetis.so被同时链接:一个是系统/usr/lib/x86_64-linux-gnu/libmetis.so.5(TLS定义在.tdata段),另一个是Petsc路径下的/opt/moose/petsc-3.7.6/mpich-3.2_gcc-7.2.0-opt/lib/libmetis.so(非TLS定义在.data段),两者的符号定义不兼容导致报错。
为什么ld会同时搜索这两个路径?
你的链接选项里同时包含了-L/opt/moose/petsc-3.7.6/mpich-3.2_gcc-7.2.0-opt/lib和-L/usr/lib/x86_64-linux-gnu,而且可能存在两种情况:
- 显式的
-lmetis参数在链接选项中,ld按顺序搜索路径时,可能先找到其中一个版本,但后续某个已链接的库(比如libpetsc.so)又依赖了另一个路径的libmetis,导致ld加载第二个版本。 - 链接选项中可能存在重复的
-lmetis引用,或者依赖链中引入了不同版本的库。
解决方法:
调整链接顺序,优先使用Petsc版本的metis:
把-L/opt/moose/petsc-3.7.6/mpich-3.2_gcc-7.2.0-opt/lib放在-L/usr/lib/x86_64-linux-gnu之前,并且让-lmetis紧跟在这个-L参数后面,确保ld优先选择Petsc路径下的版本:-L/opt/moose/petsc-3.7.6/mpich-3.2_gcc-7.2.0-opt/lib -lmetis -L/usr/lib/x86_64-linux-gnu ...直接指定Petsc版本的metis绝对路径:
用完整路径替代-lmetis,彻底避免路径搜索的歧义:/opt/moose/petsc-3.7.6/mpich-3.2_gcc-7.2.0-opt/lib/libmetis.so避免不必要的库链接:
添加-Wl,--as-needed参数,让ld只链接真正被依赖的库,防止依赖链中意外引入系统版本的libmetis:-Wl,--as-needed ... -lpetsc -lmetis ...检查依赖链定位冲突来源:
用ldd命令查看Petsc库的依赖,确认它是否依赖系统版本的metis:ldd /opt/moose/petsc-3.7.6/mpich-3.2_gcc-7.2.0-opt/lib/libpetsc.so如果发现它依赖
/usr/lib/x86_64-linux-gnu/libmetis.so,可能需要重新编译Petsc,让它使用自身附带的metis版本。
内容的提问来源于stack exchange,提问作者stl

