我试图理解为什么链接器在编译共享库时缺少一些静态库。我在CentOS 6(使用devtoolset-8安装)上使用gcc 8.3.1编译Makefile时遇到问题。此makefile与OSX上的Homebrew一起安装的gcc 9.1.0可以正常工作。
我有一堆使用以下选项编译的C ++文件:
g++ -Wall -Wno-unused-result -Wsign-compare -Wunreachable-code -fwrapv -std=c++14 -libstdc++ -fPIC -c -g -O0 -I ./cpysim -o sim_core.o sim_core.cpp
这些文件都全部存档到一个静态库中
ar rcs libcpysim.a sim_core.o foo.o bar.o ...
cythonize步骤本质上分为三个部分:
我正在使用distutils,因此第2步和第3步只是生成的命令,可以从命令行运行。举个例子,用Cython生成的C ++是用
编译的gcc -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes -fPIC -DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION -I. -I../build -I../dSFMT-src-2.2.3 -I../build/include -I../cpysim -I/tools/conda/anaconda3/2019.03/lib/python3.7/site-packages/numpy/core/include -I/tools/conda/anaconda3/2019.03/include/python3.7m -c afepma.cpp -o build/temp.linux-x86_64-3.7/afepma.o -libstdc++ -std=c++14 -g -O0
然后将其与
链接g++ -pthread -shared -B /tools/conda/anaconda3/2019.03/compiler_compat -L/tools/conda/anaconda3/2019.03/lib -Wl,-rpath=/tools/conda/anaconda3/2019.03/lib -Wl,--no-as-needed -Wl,--sysroot=/ build/temp.linux-x86_64-3.7/afepma.o -L../build -L../build/lib -lcpysim -o ../build/afepma.cpython-37m-x86_64-linux-gnu.so -g
要注意的重要一点是,静态库是通过-lcpysim
传递的。如果我使用-Wl,-verbose
以详细模式运行此文件,则可以在日志中看到已找到该库:
attempt to open /tools/conda/anaconda3/2019.03/lib/libcpysim.so failed
attempt to open /tools/conda/anaconda3/2019.03/lib/libcpysim.a failed
attempt to open ../build/libcpysim.so failed
attempt to open ../build/libcpysim.a succeeded
当我导入它并在python中运行时(同样,它可以在OSX和相同的Anaconda dist上正常运行),我得到一个未定义的符号:
File "/project/sei/colin/system-model/sim/cpysim.py", line 39, in <module>
import build.afepma as afepma
ImportError: /project/sei/colin/system-model/build/afepma.cpython-37m-x86_64-linux-gnu.so: undefined symbol: _ZN6cpysim3Rng5RandnEv
检查对象,确实缺少它:
[colin:system-model]$ nm -pa build/afepma.cpython-37m-x86_64-linux-gnu.so | grep Randn
U _ZN6cpysim3Rng5RandnEv
显然,它存在于OSX构建的版本中。
我读了一个建议,将库放在主对象之后的链接器命令中: Compile Python code to statically linked executable with Cython
另一个建议包括整个存档: Linking archives (.a) into shared object (.so)
最后,我找到了专门针对Cython的东西: How to statically link a library when compiling a python module extension
对于第一个建议,我已经在这样做了,库位于主要对象之后。至于第二个建议,将整个档案包含在每个共享库中似乎是浪费。
第三个建议有效,distutils生成的链接命令如下:
g++ -pthread -shared -B /tools/conda/anaconda3/2019.03/compiler_compat -L/tools/conda/anaconda3/2019.03/lib -Wl,-rpath=/tools/conda/anaconda3/2019.03/lib -Wl,--no-as-needed -Wl,--sysroot=/ build/temp.linux-x86_64-3.7/afepma.o ../build/libcpysim.a -L../build -L../build/lib -lcpysim -o ../build/afepma.cpython-37m-x86_64-linux-gnu.so -g
具体来说,为什么我的两个平台之间的行为不同(我当然知道这是合理的,但我想确切地知道为什么)。
为什么,当第一个链接命令实际上以libcpysim.a
作为库传递时,链接器没有按我认为的那样拾取_ZN6cpysim3Rng5RandnEv
?