Python 使用 numpy 和 gdal 的 C 扩展在运行时给出未定义的符号

Python C Extension using numpy and gdal giving undefined symbol at runtime

我正在为 python 编写 C++ 扩展,以加速内部创建的光栅图像查看器。 我有可用的代码,但注意到速度并没有增加那么多,在更深入地分析之后我意识到这是由于 gdal.ReadAsArray 调用,这是来自 C 扩展的 python 回调. 为了在调用 python 对象时绕过 Python C-API 的开销,我决定使用 gdal 的 C++ 库,而不是使用对现有 gdalDataset 的 Python 回调. (space 不是问题)。 但是,在实现此代码后,我 运行 在 运行 时出错(扩展编译正常)

这是

 import getRasterImage_new
 ImportError: /local1/data/scratch/lib/python2.7/site-packages
    /getRasterImage_new.so: undefined symbol: _ZN11GDALDataset14GetRasterYSizeEv

下面的代码复制了错误(可能需要一些编辑才能在您的机器上运行(忽略未初始化的变量,这正是复制错误所需要的)。

Python:

#!/usr/bin/env python
import numpy
from osgeo import gdal
import PythonCTest

print("test starting")
PythonCTest.testFunction(1)
print("test complete")

C++:

#include "Python.h"
#include "numpy/arrayobject.h"
#include "gdal_priv.h"
#include <iostream>

extern "C"{
static PyObject* PythonCTest_testFunction(PyObject* args);
static PyMethodDef PythonCTest_newMethods[] = {
   {"testFunction", (PyCFunction)PythonCTest_testFunction, METH_VARARGS,
      "test function"},
   {NULL,NULL,0,NULL}};

PyMODINIT_FUNC initPythonCTest(void){
   (void)Py_InitModule("PythonCTest",PythonCTest_newMethods);
   import_array();
}
}
GDALDataset* y;
static PyObject* PythonCTest_testFunction(PyObject* args){
   std::cout << "in testFunction\n";
   y->GetRasterYSize();
   std::cout << "doing stuff" << "\n";
   return Py_None;
}

非常欢迎任何建议。


编辑

您也可以删除 from osgeo import gdal 并且出现错误 stull(只是刚刚注意到)。


编辑 2

我忘了说我正在使用 distutils 编译我的扩展

当前setup.py是

#!/usr/bin/env python
from distutils.core import setup, Extension
import os
os.environ["CC"] = "g++"
setup(name='PythonCTest', version='1.0', \
   ext_modules=[Extension('PythonCTest', ['PythonCTest.cpp'],
   extra_compile_args=['--std=c++14','-l/usr/include/gdal', '-I/usr/include/gdal'])])

一个Python扩展模块是一个可动态加载(共享)的库。当 linking 共享库时,您需要指定其库依赖项,例如 -lgdal,就此而言,-lpython2.7。如果不这样做会导致库中有未解析的符号,如果这些符号在加载时未提供,加载将失败,如 Python.

所报告

要解决该错误,您需要将 libraries=['gdal'] 添加到 Extension 构造函数。在 extra_compile_args 中指定 -lgdal 将不起作用,因为顾名思义,编译参数用于编译而不是用于 linking。

请注意,在 link 执行可执行文件时未检测到未解析的符号,构建将失败并出现 linker 错误。要在 linking 共享库时获得相同的诊断,请在 link 参数中包含 -Wl,-zdefs