Date Tags 日常

找不到相关符号

因为 cython 链接用到的库在 ~/Anaconda3/lib 中,包括 libstdc++.so,一般来讲这个和/usr/lib/x86_64***/libstdc++.so 的版本是不一样的,看他们后面的链接目标文件名中有详细的版本号

所以链接时用到的库和运行时用到的库是不一样的,会导致符号表不一样,如:新版本中新增了某个函数,这样在运行时加载的老库就会出现找不到符号表

为什么会这样?编译时会同时加载这两个libstdc++.so文件,新版本中有个newfunc。编译的头文件是系统的新stl库,链接时会先找老so文件里,找不到就会找新的so文件,因为是share的,找到了后就会把文件名和函数名记录在输出文件的符号表中。这里有个问题就是只记录文件名,没有记录文件的路径,当然这也是合理的。当python程序运行时会优先找~/Anaconda3/lib中的库,找到libstdc++.so文件了,这样就不会再找系统库中的so文件。所以相应会找符号表中的函数名,当然newfunc就找不到,出现了错误。

解决方案:把python的c++库保持和系统版本一致就行

cd ~/anaconda3/lib
mv libstdc++.so.6 libstdc++.so.6.bak
mv libstdc++.so libstdc++.so.bak
ln -s /usr/lib/x86_64-linux-gnu/libstdc++.so.6 ./libstdc++.so.6
ln -s /usr/lib/x86_64-linux-gnu/libstdc++.so.6 ./libstdc++.so

# 再查看一下当前stdc++库的情况
ll libstdc++*

cython 单线程编译慢

cython 是自己调用的 gcc 一个一个顺序编译的,在官方文档里面其实有一个nthreads,但是这个貌似仅限于编译多个extension时才有用。反正我是没有搞成功。

所以用了cmake来编译cython的接口。

其实python本身可以直接调用c++的库,只要函数名有一定的规范即可。cython其实只是在这个当中做了一个桥梁,把python数据和c++连接起来,自己创建了一套pyx pyd的语法,最后把pyx pyd都翻译成cpp,再编译成so文件。

然后python直接import就行。流程:

  1. pyx接口(python调用的文件)文件编译成cpp文件
  2. 编译成o文件(可以并行)
  3. 链接成最终的so文件

我的纯c++项目用的cmake管理,默认就开了并行编译。cython编译这一套,看似简单,其实操作还是挺复杂,所以有个现成的库,做的还不错 scikit-build 一些示例 scikit-build-sample-projects

  1. 安装必要的工具
pip install scikit-build
pip install ninja   # 支持并行编译的快速编译工具
  1. 建立setup文件,把setup类改成scikit-build
from skbuild import setup  # This line replaces 'from setuptools import setup'
  1. 完善包的信息
setup(
    name="hello-cython",
    version="1.2.3",
    description="a minimal example package (cython version)",
    author='The scikit-build team',
    license="MIT",
    packages=['hello'], # 当前目录要有一个名为hello的package(带__init__.py的文件夹)
    install_requires=['cython'],
    tests_require=['pytest'], # 可以去掉
    setup_requires=setup_requires # 可以去掉
)
  1. 生成CMakeLists.txt

只讲新的东西,文件前面部分要加上下面这两句

find_package(PythonExtensions REQUIRED)
find_package(Cython REQUIRED)
add_cython_target(_hello CXX)
add_library(_hello MODULE ${_hello})
python_extension_module(_hello)
install(TARGETS _hello LIBRARY DESTINATION hello)

add_cython_target(_hello CXX)这一句很重要,作用主就是把_hello.pyx编译成cpp文件

最后 install 中的 hello 要和 setup 信息中 packages 名一样才行。

复杂点的项目我已经测试过了,都可以,比cython自带的编译快了不止一点点,默认是并行编译。