Python和OpenMP C扩展

29

我有一个C扩展,想在其中使用OpenMP。但是当我导入我的模块时,出现了导入错误:


ImportError: /home/.../_entropysplit.so: undefined symbol: GOMP_parallel_end

我已经使用了-fopenmp和-lgomp编译了模块。这是因为我的Python安装没有使用-fopenmp标志进行编译吗?我是否需要从源代码构建Python?或者还有其他可能性吗?这是我在模块中唯一使用openmp的时候:


unsigned int feature_index;
#pragma omp parallel for
for (feature_index = 0; feature_index < num_features; feature_index++) {

如果可能的话,我想坚持使用OpenMP,因为它非常容易并且在这种情况下并行化很适合。

编辑:我咬了咬牙,重新编译了支持OpenMP的Python。 我的模块现在完美运行,但这不是一个很好的解决方案。 如果需要完全重新编译Python才能分发,则无法真正分发此工具包。 那么有人知道绕过这个问题的方法吗? 可能可以使用ctypes吗?

已解决! 这是一个简单的链接问题。(我为此重建了Python?!)在编译模块时没有正确链接OpenMP。 因此,可以加载使用OpenMP的C Python扩展程序。


你可以考虑将你的解决方案复制到这个问题下面的一个“真正的”答案中,这样更容易看到(并且可以得到赞同)。 - Michael Ratanapintha
3个回答

20

只是为了更清晰,这里是你的 setup.py 应该长什么样子:

ext = Extension(
      'milk.unsupervised._som',
      sources = ['milk/unsupervised/_som.cpp'],
      extra_compile_args=['-fopenmp'],
      extra_link_args=['-lgomp'])


...
setup(..., ext_modules = [ext])

3
如何以跨平台的方式实现此功能,使其能够适用于支持OpenMP的gcc、msvc和Clang版本,并在不支持OpenMP时能够优雅地回退? - Colonel Panic
@ColonelPanic:我也很想知道。 - luispedro

8

我知道这是一个过时的帖子,但我将分享我的经验,因为我也遇到了完全相同的问题,但是当我在命令行上使用f2py时。最初,我是使用以下方式编译我的OpenMP启用的Fortran 90子程序:

f2py --fcompiler=gfortran --f90flags='-fopenmp -lgomp' -m sub -c sub.90

成功创建了共享对象sub.so。然而,尝试从Python shell导入此对象时会出现类似的未定义符号ImportError错误。原作者指出,这是因为我试图将-fopenmp和-lgomp同时传递给编译器,而只应该将-fopenmp传递给它,将-lgomp传递给链接器。

因此,我应该执行以下操作:

f2py --fcompiler=gfortran --f90flags='-fopenmp' -lgomp -m sub -c sub.f90

就这样,问题解决了,我现在可以导入我的子程序了。


3

这只是一个简单的链接问题。在模块编译期间,OpenMP未被正确链接。因此,可以加载使用OpenMP的C Python扩展。必须将-fopenmp传递给编译器,并将-lgomp传递给链接器--如果您正在使用distutils,请确保您的setup.py已正确配置。重新构建Python也起作用了,我猜测是因为我已经正确地将OpenMP与Python链接起来,因此当Python加载模块时,库已经正确地链接到了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接