在Ubuntu上,使用CMake编译C++工程文件时,报错:
解决办法是:在子工程中所有生成了库(除INTERFACE_LIBRARY之外的库)的工程的CMakeList中设置-fPIC参数,具体操作方法为在生成库文件的代码
add_library(XXX
a.cc
b.cc
)
语句后添加一行代码,为:
set_property(TARGET XXX PROPERTY POSITION_INDEPENDENT_CODE ON)
其中,XXX为库的名字。
详细原理个人理解如下:
当前工程的需求是把调用了boost库的C++工程编译成为一个动态链接库以供Python调用,(boos
的使用过程也有些曲折,详细过程及模板伪代码请见本人的这篇博客: ),但是在调整完成wrapper.cc后,编译,报错提示
/usr/bin/ld: ../lib/libXXX.a(XXX.cc.o): relocation R_X86_64_PC32 against symbol `_ZN8planning4eudm31_LonSimDetail_default_instance_E' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status
然后查询一些资料之后,因为编译动态链接库时需要设置-fPIC参数,目的是使得生成的动态链接库与位置无关
gcc编译参数-fPIC的一些问题_逐鹿之城的博客-CSDN博客_fpic
(先放个链接吧,挖个坑,之后补上我的理解~)
而要想生成这样的链接库,那它所链接的库都必须是位置无关的,即有-fPIC参数设置,所以就要在链接库的工程中进行设置了。
同理,后面在生成动态链接库时,因为用到了boost_python库,所以要在CMakeList里加上对应的链接库,如果库名是boost_python,则会寻找到libboost_python.a,结果也会报如上错误
target_link_libraries(py_solver_util
(其他库)
boost_python39)
如果不加这boost_python这个依赖库,那编译时不会报错,但Python调用就会报错
ImportError: /home/jp/ego_solver/lib/XXX(生成的库名).so: undefined symbol: _ZTIN5boost6python15instance_holderE
而且注意要用来调用C++的Python的版本必须与这个依赖库指定的版本一致,否则会报错:
ImportError: /lib/x86_64-linux-gnu/libboost_python39.so.1.71.0: undefined symbol: _Py_tracemalloc_config
如果像我一样,boost是用apt-get install的最新版,那可能出现boost的python版本与系统版本不一致的问题,如果要源码编译重新安装boost的话,一定要注意自己安装的头文件和库的位置,如果安装失败了的话记得清理,否则可能会导致环境里面boost版本混乱,出现玄学问题(就比如我之前博客里的那个只有boost头文件,没有lib带来的玄学问题),建议可以用conda重新建立一个环境,再用
conda install boost
命令安装一个boost,就可以避免这个问题啦,但是需要注意两个问题,分别是Python和boost的问题:
一是Python,要在自己工程的CMakeList里的include_directories里面指定Python的库(pyconfig.h)路径,否则会报找不到这个头文件的错误。
二是boost,由于我使用的是conda里的libboost_python39.so动态链接库,所以它的路径是不在gcc的默认编译路径里的,所以需要修改环境变量,否则会报错
/usr/bin/ld: cannot find -lboost_python39
collect2: error: ld returned 1 exit status
具体修改方法为
首先寻找库的路径,可以在文件中搜索libboost_python39.so,找到路径后,执行
$ sudo gedit ~/.bashrc
在文件中加上这一行:
export LD_LIBRARY_PATH=/上文找到的库路径/lib/:$LD_LIBRARY_PATH
或者执行:
$ echo 'export LD_LIBRARY_PATH=/上文找到的库路径/lib/:$LD_LIBRARY_PATH' >> ~/.bashrc
$ source ~/.bashrc
来修改环境变量 LD_LIBRARY_PATH,加入库文件所在路径。
若修改变量 LD_LIBRARY_PATH 不奏效,则修改变量 LIBRARY_PATH 。(重点!!!而且我亲测只修改LD_LIBRARY_PATH 不得行~所以还要修改LIBRARY_PATH)
$ sudo gedit ~/.bashrc
在文件中加上这一行:
export LIBRARY_PATH=/上文找到的库路径/lib/:$LIBRARY_PATH
或者执行:
$ echo 'export LIBRARY_PATH=/上文找到的库路径/lib/:$LIBRARY_PATH' >> ~/.bashrc
$ source ~/.bashrc
ps:conda建虚拟环境确实不错哎,我过程中本来用的是Python3.8,下载的boost也是,但是后续发现要用到我生成的链接库的那个工程只能用Python3.9,所以我只能重新再编,本来以为要重新配环境,后来发现conda里面重新安装Python很方便,只需要执行
conda install python==3.9 -n xxx(虚拟环境名字)
就可以,而且对应的其他库(比如boost)也会重新安装,确实不错,打call!!