静态库的链接器行为

时间:2019-07-10 15:47:09

标签: c++ gcc cython ld

我试图理解为什么链接器在编译共享库时缺少一些静态库。我在CentOS 6(使用devtoolset-8安装)上使用gcc 8.3.1编译Makefile时遇到问题。此makefile与OSX上的Homebrew一起安装的gcc 9.1.0可以正常工作。

步骤1:创建libcpysim.a

我有一堆使用以下选项编译的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 ...

第2步:对C ++代码进行Cython化以创建共享库

cythonize步骤本质上分为三个部分:

  1. 将Cython转换为C ++
  2. 将C ++编译为对象
  3. 将此对象链接到共享库

我正在使用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

0 个答案:

没有答案