我在 MATLAB MEX 代码中使用 CUDA Thrust 库时遇到问题。
我有一个在外部运行良好的示例,但如果我将它编译并作为 MEX 文件运行,它会在运行时产生“缺少符号”错误。
它似乎特定于 Thrust 库。如果不是 thrust::device_vector
我使用 cudaMalloc
和 cudaMemcpy
或 cublasSetVector
那么一切都很好。
最小示例
推力演示.cu:
#ifdef MATLAB_MEX_FILE
#include "mex.h"
#include "gpu/mxGPUArray.h"
#endif
#include <thrust/device_vector.h>
#include <vector>
void thrustDemo() {
std::vector<double> foo(65536, 3.14);
thrust::device_vector<double> device_foo(foo);
}
#ifdef MATLAB_MEX_FILE
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, mxArray const *prhs[]) {
thrustDemo();
}
#else
int main(void) { thrustDemo(); }
#endif
问题
我可以从命令行 (nvcc thrustDemo.cu
) 编译它并运行生成的可执行文件。
当我尝试将其构建为 MATLAB MEX 文件(来自 MATLAB R2017a 中的 mexcuda thrustDemo.cu
)时,它可以正常编译和链接:
>> mexcuda thrustDemo.cu
Building with 'nvcc'.
MEX completed successfully.
但是当我尝试运行它时,出现以下错误:
>> thrustDemo()
Invalid MEX-file '/home/kqs/thrustDemo.mexa64':
Missing symbol '_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE5c_strEv' required by '/home/kqs/thrustDemo.mexa64'
Missing symbol '_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE5emptyEv' required by '/home/kqs/thrustDemo.mexa64'
Missing symbol '_ZNSt12length_errorC1EPKc' required by '/home/kqs/thrustDemo.mexa64'
Missing symbol '_ZNSt13runtime_errorC2EPKc' required by '/home/kqs/thrustDemo.mexa64'
Missing symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEaSEPKc' required by '/home/kqs/thrustDemo.mexa64'
Missing symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1EPKcRKS3_' required by '/home/kqs/thrustDemo.mexa64'
Missing symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1ERKS4_' required by '/home/kqs/thrustDemo.mexa64'
Missing symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEC1Ev' required by '/home/kqs/thrustDemo.mexa64'
Missing symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEED1Ev' required by '/home/kqs/thrustDemo.mexa64'
Missing symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEpLEPKc' required by '/home/kqs/thrustDemo.mexa64'
Missing symbol '_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEpLERKS4_' required by '/home/kqs/thrustDemo.mexa64'.
这对我来说很陌生;有人可以告诉我这是什么意思吗?这些看起来像链接器错误,但它们是在运行时生成的。另外,我以为Thrust是一个模板库,那有什么可以链接的呢?
最后,将 thrust::device_vector
替换为 cudaMalloc
和 cudaMemcpy
或 cublasSetVector
都可以正常工作。所以现在我的代码中有一堆 cudaMalloc
,这看起来......令人反感。我真的很想能够使用 Thrust。
版本
MATLAB R2017a
nvcc
V8.0.61, gcc
5.4.0, Ubuntu 16.04.2
NVidia 驱动 375.39,GTX 1060 显卡(Compute Capability 6.1)
更新:ldd
输出
根据评论,我使用 ldd thrustDemo.mexa64
检查了 MEX 文件的依赖项:
linux-vdso.so.1 => (0x00007ffdd35ea000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f097eccf000)
libcudart.so.8.0 => /usr/local/cuda-8.0/targets/x86_64-linux/lib/libcudart.so.8.0 (0x00007f097ea69000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f097e852000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f097e489000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f097e180000)
/lib64/ld-linux-x86-64.so.2 (0x0000562df178c000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f097df7b000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f097dd5e000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f097db56000)
我试着寻找其中一个缺失的符号,并找到了它:
$ nm -D /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep "_ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE5c_strEv"
0000000000120be0 W _ZNKSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEE5c_strEv
看来 MATLAB 一定是找错地方了。
最佳答案
事实证明,这与 Thrust 无关,而是 MATLAB 拥有自己版本的 C++ 标准库的问题。
感谢@Navan 和@talonmies 提供的有用评论。
解释错误
首先,MATLAB 在加载 MEX 文件时会引发这些错误。 MEX 文件具有外部依赖项,MATLAB 找不到它们。
在使用Linux工具ldd
检查这些依赖关系后,然后使用nm
列出这些库定义的符号,我发现的系统版本libstdc++
共享库实际上包含这些“缺失的符号”。这就是为什么外部编译版本可以正常工作的原因。
解决问题
那么,根本问题是 MATLAB 附带了它自己的旧版本 libstdc++
,它缺少这些函数。了解根本原因后,我发现了如下问题:
Version GLIBCXX_3.4.11 not found (required by buildW.mexglx)
其中描述了对我的问题确实成功的解决方法。
特别是,我在启动 MATLAB 时使用了 LD_PRELOAD
以强制 MATLAB 使用系统 libstdc++
而不是它自己的副本:
$ LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libstdc++.so.6 /usr/local/MATLAB/R2017a/bin/matlab
更新:更好的解决方案
事实证明,GCC 的人们很清楚这种不兼容性,并且 discuss it here :
In the GCC 5.1 release libstdc++ introduced a new library ABI that includes new implementations of std::string and std::list. These changes were necessary to conform to the 2011 C++ standard which forbids Copy-On-Write strings and requires lists to keep track of their size.
In order to maintain backwards compatibility for existing code linked to libstdc++ the library's soname has not changed and the old implementations are still supported in parallel with the new ones. ... The _GLIBCXX_USE_CXX11_ABI macro (see Macros) controls whether the declarations in the library headers use the old or new ABI.
要告诉 gcc
使用旧的 ABI,我们只需要在包含任何库头之前将 _GLIBCXX_USE_CXX11_ABI
定义为 0
,例如通过将 -D
选项传递给编译器:
-D_GLIBCXX_USE_CXX11_ABI=0
为了完整起见,我会提到我的完整 mexcuda
调用如下所示:
nvcc_opts = [...
'-gencode=arch=compute_30,code=sm_30 ' ...
'-gencode=arch=compute_50,code=sm_50 ' ...
'-gencode=arch=compute_60,code=sm_60 ' ...
'-std=c++11 ' ...
'-D_GLIBCXX_USE_CXX11_ABI=0 ' % MATLAB's libstdc++ uses old library ABI
];
mexcuda_opts = {
'-lcublas' % Link to cuBLAS
'-lmwlapack' % Link to LAPACK
'-lcufft' % Link to cuFFT
['NVCCFLAGS="' nvcc_opts '"']
'-L/usr/local/cuda/lib64' % Location of CUDA libraries
};
mexcuda(mexcuda_opts{:}, src_file);
关于matlab - 在 MATLAB MEX 文件中使用 Thrust 时出现运行时链接器错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43643670/