记录一个conda相关的编译与链接错误 "undefined symbol:__cxa_call_terminate"

问题复现

之前在自己电脑上折腾conda环境时,安装了pytorch-quantization这个库之后运行时总会报一个错误:

from pytorch_quantization import cuda_ext ImportError: /home/blackcat/program/anaconda3/envs/modelopt/lib/python3.12/site-packages/pytorch_quantization/cuda_ext.cpython-312-x86_64-linux-gnu.so: undefined symbol: __cxa_call_terminate

这个问题只会在以下条件全部满足时出现:

  • 使用conda环境(python=3.12.11);
  • 使用源码编译安装了pytorch-quantization

之前在安装torch/torch相关的各种库时经常会遇到各种各样的未定义符号错误,一般都是因为运行时的cudart相关链接库版本和编译时的版本不匹配导致的,这种问题可以通过重编译解决。

但是这次的问题本身就是在自己编译后出现的,并且和一般的使用whl安装所导致的ABI不匹配问题也不一样。并且,最奇怪的一点在于,当我手动用python -m构建了一个虚拟环境之后再安装,就不会出现上述错误。

于是开始了一番折腾。

问题分析

首先,undefined symbol: __cxa_call_terminate是什么?

结论很简单,__cxa_call_terminate是一个经过名称修饰后的CPP ABI,一般定义在libstdc++.so内,libstdc++.so是个非常常见的动态链接库,linux环境下/usr/lib都有这个文件(还会有多个版本),因此可以确定这个问题和cudart无关,和cpp的编译相关。

1
2
3
4
$ ls /usr/lib | grep libstdc++.so
libstdc++.so
libstdc++.so.6
libstdc++.so.6.0.34

随后,开始寻找在手动安装库时的输出,看一下其调用g++c++时的输出,发现其调用的是原生系统的g++。

1
2
3
4
5
$ python setup.py install

...
[1/2]g++ -pthread -B ... -gencode=arch=compute_75,code=sm_75 -std=c++17
...

接着使用ldd查看报错的文件的链接依赖:

1
2
3
4
$ ldd build/lib.linux-x86_64-cpython-312/pytorch_quantization/cuda_ext.cpython-312-x86_64-linux-gnu.so 
...
libstdc++.so.6 => /home/blackcat/program/anaconda3/envs/pt-quant/lib/libstdc++.so.6 (0x00007fd2d580b000)
...

发现编译得到的.so文件默认链接的不是系统的libstdc++.so而是在conda环境文件夹内的一个so文件。再通过readelf查看其rpath看看是否强制制定了动态库的寻找路径:

1
2
readelf -d build/lib.linux-x86_64-cpython-312/pytorch_quantization/cuda_ext.cpython-312-x86_64-linux-gnu.so  | grep PATH
0x000000000000000f (RPATH) Library rpath: [/home/blackcat/program/anaconda3/envs/pt-quant/lib]

果不其然,RPATH被指定为了conda路径下的一个文件夹,那么很有可能是这个被强制指定的.so文件的问题。并且,当我们去ldd查看使用-m指令生成的venv环境下编译好的同名文件时,其路径是系统/usr/lib内的文件,更加验证了这个猜想。

1
2
3
4
$ ldd venv/build/lib.linux-x86_64-cpython-312/pytorch_quantization/cuda_ext.cpython-312-x86_64-linux-gnu.so 
...
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f7d12c00000)
...

问题解决

conda会为每个环境单独配置自己的/lib路径,以便在不同操作系统上对环境进行迁移与重现。如果系统本身的g++版本比较新,编译源码得到了所谓的__cxa_call_terminate ABI,而conda为环境提供的libstdc++.so版本较旧,没有__cxa_call_terminate ABI,便会出现上述错误。

而由于系统的/usr/lib和系统的g++一定是匹配的,所以在使用python原生的venv时便不会报错。那解决方案其实有以下可选几种:

  • 推荐使用: 使用conda install -c conda-forge gxx_linux-64指令安装相关编译工具,在编译时也使用conda自带的编译工具并匹配环境的lib;
  • 使用Python原生venv,即使用系统编译器和/usr/lib路径;
  • 手动为编译好的文件修改链接地址,例如使用LD_PRELOAD=/usr/lib/...

在使用方法一,安装编译工具后,再对源码进行编译与安装,可以看到输出的日志内,使用的编译器已经换为了conda自己的编译器。

1
2
3
4
$ python setup.py install
...
[1/2] x86_64-conda-linux-gnu-c++ -MMD ... -DTORCH_EXTENSION_NAME=cuda_ext -std=c++17
...

此时编译后的包可以正常运行,问题解决。

总结

之前从来没想过conda会为每个环境分配各自的动态库环境,并且在某个conda环境内使用python/pip/setuptools进行安装时调用的却是操作系统默认的编译器,如果两者版本不匹配,就很有可能导致ABI问题。感觉在需要大量手动通过源码安装的环境下,conda已经没办法带来什么便捷了,还不如手动去创建一个venv开发(然后就发现自己的venv环境杂乱无章像个垃圾桶)。

同时关于python/pytorch和C++的交叉调用可以看看我博客内的另外两篇文章: 使用Pytorch的cpp_extension调用外部C函数Linux环境下在CPP项目内引用torch相关库完成编译

参考文献

参考了:


记录一个conda相关的编译与链接错误 "undefined symbol:__cxa_call_terminate"
https://blog.bakeneko-kuro.com/2026/01/13/cpp/a-conda-compiler-and-link-error/
作者
迷途黑猫
发布于
2026年1月13日
许可协议