最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - Cython can't link external C++ library - Stack Overflow

programmeradmin3浏览0评论

Part of a Python library I'm working on is written in Cython. I need to use the LinBox C++ library (which depends on the Givaro library). Just to test, I've written a small C++ function that eats Cython-accessible data, does something with Givaro, and returns Cython-accessible data. Everything compiles correctly, but when I run the test, I get the following error:

ImportError: dlopen(<path/to/cython>/matrices.cpython-311-darwin.so, 0x0002): symbol not found in flat namespace '__ZN6GivarolsERSoRKNS_7IntegerE'

Running nm on matrices.cpython-311-darwin.so, it looks like the symbol is undefined, because I get U __ZN6GivarolsERSoRKNS_7IntegerE. Here's my MWE:

// fastcomputation.cpp

#include <vector>
#include <givaro/gfq.h>

using namespace std;

int kernel(vector<int> A, int rank, int nullity, double field) {
    Givaro::GFqDom<int> F(field);
    return 1;
}
// fastcomputation.hpp

#include <vector>

int kernel(std::vector<int> A, int rank, int nullity, double field);
# matrices.pyx
# distutils: language = c++

from libcpp.vector cimport vector

cdef extern from "fastcomputation.hpp":
    int kernel(vector[int] A, int rank, int nullity, double field)

cpdef pkernel(vector[int] A, int rank, int nullity, double field):
    print(kernel(A, rank, nullity, field))
# setup.py

from setuptools import setup, Extension
from Cython.Build import cythonize
import os
import numpy

os.environ["CC"] = "gcc-14"
os.environ["CXX"] = "g++-14"

extensions = [
    Extension(
        "*",
        ["<path/to/cython>/*.pyx", "<path/to/cython>/fastcomputation.cpp"],
        include_dirs=[
            numpy.get_include(),
            "<path/to/cython>",
            "/opt/homebrew/Cellar/linbox/include",
            "/opt/homebrew/Cellar/fflas-ffpack/2.5.0/include",
            "/opt/homebrew/Cellar/givaro/4.2.0_1/include",
            "/opt/homebrew/Cellar/gmp/6.3.0/include",
            "/opt/homebrew/Cellar/libomp/20.1.0/include"
        ],
        library_dirs=[
            "/opt/homebrew/Cellar/linbox/lib",
            "/opt/homebrew/Cellar/fflas-ffpack/2.5.0/lib",
            "/opt/homebrew/Cellar/givaro/4.2.0_1/lib",
            "/opt/homebrew/Cellar/gmp/6.3.0/lib",
            "/opt/homebrew/Cellar/libomp/20.1.0/lib"
        ],
        runtime_library_dirs=[
            "/opt/homebrew/Cellar/linbox/lib",
            "/opt/homebrew/Cellar/fflas-ffpack/2.5.0/lib",
            "/opt/homebrew/Cellar/givaro/4.2.0_1/lib",
            "/opt/homebrew/Cellar/gmp/6.3.0/lib",
            "/opt/homebrew/Cellar/libomp/20.1.0/lib"
        ],
        libraries=["linbox", "givaro"],
        language="c++"
    )
]

setup(
    ext_modules=cythonize(extensions, annotate=True, language_level="3")
)

I am not an expert (or even that capable) at getting C++ to compile, so it's possible that I've misdiagnosed this and I'm leaving something out completely. The issue is that, without trying to use Givaro, everything compiles and runs, but I need to use Givaro.

Part of a Python library I'm working on is written in Cython. I need to use the LinBox C++ library (which depends on the Givaro library). Just to test, I've written a small C++ function that eats Cython-accessible data, does something with Givaro, and returns Cython-accessible data. Everything compiles correctly, but when I run the test, I get the following error:

ImportError: dlopen(<path/to/cython>/matrices.cpython-311-darwin.so, 0x0002): symbol not found in flat namespace '__ZN6GivarolsERSoRKNS_7IntegerE'

Running nm on matrices.cpython-311-darwin.so, it looks like the symbol is undefined, because I get U __ZN6GivarolsERSoRKNS_7IntegerE. Here's my MWE:

// fastcomputation.cpp

#include <vector>
#include <givaro/gfq.h>

using namespace std;

int kernel(vector<int> A, int rank, int nullity, double field) {
    Givaro::GFqDom<int> F(field);
    return 1;
}
// fastcomputation.hpp

#include <vector>

int kernel(std::vector<int> A, int rank, int nullity, double field);
# matrices.pyx
# distutils: language = c++

from libcpp.vector cimport vector

cdef extern from "fastcomputation.hpp":
    int kernel(vector[int] A, int rank, int nullity, double field)

cpdef pkernel(vector[int] A, int rank, int nullity, double field):
    print(kernel(A, rank, nullity, field))
# setup.py

from setuptools import setup, Extension
from Cython.Build import cythonize
import os
import numpy

os.environ["CC"] = "gcc-14"
os.environ["CXX"] = "g++-14"

extensions = [
    Extension(
        "*",
        ["<path/to/cython>/*.pyx", "<path/to/cython>/fastcomputation.cpp"],
        include_dirs=[
            numpy.get_include(),
            "<path/to/cython>",
            "/opt/homebrew/Cellar/linbox/include",
            "/opt/homebrew/Cellar/fflas-ffpack/2.5.0/include",
            "/opt/homebrew/Cellar/givaro/4.2.0_1/include",
            "/opt/homebrew/Cellar/gmp/6.3.0/include",
            "/opt/homebrew/Cellar/libomp/20.1.0/include"
        ],
        library_dirs=[
            "/opt/homebrew/Cellar/linbox/lib",
            "/opt/homebrew/Cellar/fflas-ffpack/2.5.0/lib",
            "/opt/homebrew/Cellar/givaro/4.2.0_1/lib",
            "/opt/homebrew/Cellar/gmp/6.3.0/lib",
            "/opt/homebrew/Cellar/libomp/20.1.0/lib"
        ],
        runtime_library_dirs=[
            "/opt/homebrew/Cellar/linbox/lib",
            "/opt/homebrew/Cellar/fflas-ffpack/2.5.0/lib",
            "/opt/homebrew/Cellar/givaro/4.2.0_1/lib",
            "/opt/homebrew/Cellar/gmp/6.3.0/lib",
            "/opt/homebrew/Cellar/libomp/20.1.0/lib"
        ],
        libraries=["linbox", "givaro"],
        language="c++"
    )
]

setup(
    ext_modules=cythonize(extensions, annotate=True, language_level="3")
)

I am not an expert (or even that capable) at getting C++ to compile, so it's possible that I've misdiagnosed this and I'm leaving something out completely. The issue is that, without trying to use Givaro, everything compiles and runs, but I need to use Givaro.

Share edited Mar 11 at 11:55 apizzimenti asked Mar 11 at 2:55 apizzimentiapizzimenti 4772 gold badges8 silver badges20 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

Fixed by including relevant linking flags and compiling parts of the Cython code differently, á la

# setup.py

from setuptools import setup, Extension
from distutils import sysconfig
from Cython.Build import cythonize
import os
import subprocess
import numpy

# Get the right compilation and linking flags.
LIB = ["givaro"]
_CFLAGS = " ".join([subprocess.run(["pkg-config", "--cflags", pkg], text=True, capture_output=True).stdout.strip() for pkg in LIB])
CFLAGS = list(set(_CFLAGS.split(" ")))

_LINKS = " ".join([subprocess.run(["pkg-config", "--libs", pkg], text=True, capture_output=True).stdout.strip() for pkg in LIB])
LINKS = list(set(_LINKS.split(" ")))

sysconfig.get_config_vars()['CC'] = 'gcc-14'
sysconfig.get_config_vars()['CXX'] = 'g++-14'

extensions = [
    Extension(
        "*",
        ["<path/to/cython>/matrices.pyx", "<path/to/cython>/fastcomputation.cpp"],
        include_dirs=[
            numpy.get_include(),
            "<path/to/cython>",
            "/opt/homebrew/Cellar/linbox/include",
            "/opt/homebrew/Cellar/givaro/4.2.0_1/include",
            "/opt/homebrew/Cellar/gmp/6.3.0/include"
        ],
        library_dirs=[
            "/opt/homebrew/Cellar/linbox/lib",
            "/opt/homebrew/Cellar/givaro/4.2.0_1/lib",
            "/opt/homebrew/Cellar/gmp/6.3.0/lib",
        ],
        # extra_compile_args=CFLAGS,
        extra_link_args=LINKS,
        language="c++"
    ),
    Extension(
        "*",
        [
            "<path/to/cython>/linearAlgebra.pyx",
            "<path/to/cython>/persistence.pyx",
            "<path/to/cython>/cubicalComplex.pyx"
        ],
        include_dirs=[numpy.get_include()],
        language="c"
    )
]

setup(
    ext_modules=cythonize(
        extensions,
        annotate=True,
        language_level="3"
    )
)
发布评论

评论列表(0)

  1. 暂无评论