【发布时间】:2021-04-27 15:53:51
【问题描述】:
我想用 cython 包装一些 C++ 类,但我的问题是我必须在另一个类中使用一些类。我没有找到其他人有同样的问题,甚至没有类似的问题,如果已经被问到,我很抱歉......我做了一个已经很长的简约例子......
所以我有以下文件结构,BuildAll.sh 在文件夹中运行,如果它有一个 BuildAll.sh 文件,它会更深入,如果一个文件夹有一个 setup.py 文件,它会构建它(setup.py 文件将查找每个 *.pyx 文件并构建它们) 现在出于虚拟目的,classAC 是用 C++ 编写的 ClassA,它拥有一个 int 作为成员。 B 文件夹中也是如此,但 classBC 将 classAC 的实例作为成员,我认为这是问题所在,因为 classBC 不知道 classAC 的定义。
.
├── BuildAll.sh
├── main.py
└── src
├── A
│ ├── classAC.cpp
│ ├── classAC.hpp
│ ├── classAC.pxd
│ ├── classA.pyx
│ ├── __init__.py
│ └── setup.py
├── B
│ ├── classBC.cpp
│ ├── classBC.hpp
│ ├── classBC.pxd
│ ├── classB.pyx
│ ├── __init__.py
│ └── setup.py
├── BuildAll.sh
└── __init__.py
BuildAll.sh:
#!/bin/bash
# Go into every directory
for D in */
do
cd $D
# If dir contains a BuildAll.sh script, run it.
if test -f "BuildAll.sh"; then
./BuildAll.sh
fi
# If dir contains a setup.py file, then build it.
# setup.py will look for every .pyx extension and build it automatically.
if test -f "setup.py"; then
python3 setup.py build_ext --inplace
fi
cd ..
done
setup.py:
from setuptools import Extension, setup
from Cython.Build import cythonize
import glob
PYXFILES = glob.glob("*.pyx")
EXTNAMES = [i[:-4] for i in PYXFILES]
ext_list = []
for i in range(len(PYXFILES)):
ext_list.append(
Extension(
EXTNAMES[i],
[PYXFILES[i]],
extra_compile_args=["-O3"]
)
)
setup(
ext_modules = cythonize(
ext_list,
language_level = 3,
build_dir = 'build',
annotate = True
)
)
classAC.cpp:
#include "classAC.hpp"
classAC::classAC()
: data_(0)
{}
int classAC::data()
{
return data_;
}
classAC.hpp:
#ifndef CLASSAC_H
#define CLASSAC_H
class classAC
{
private:
int data_;
public:
// Constructors
// Null construct
classAC();
// Destructor
~classAC() = default;
int data();
};
#endif // CLASSAC_H
classAC.pxd:
cdef extern from "classAC.cpp":
pass
cdef extern from "classAC.hpp":
cdef cppclass classAC:
classAC()
int data()
classA.pyx:
# distutils: language = c++
from classAC cimport *
cdef class ClassA:
cdef classAC COBJ
def __cinit__(self):
pass
def __init__(self):
self.COBJ = classAC()
def getAdata(self):
return self.COBJ.data()
classBC.cpp:
#include "classBC.hpp"
classBC::classBC()
: aobj_(classAC())
{}
classBC.hpp:
#ifndef CLASSBC_H
#define CLASSBC_H
#include "classAC.hpp"
class classBC
{
/* Base class for an fvMesh */
private:
classAC aobj_;
public:
// Constructors
classBC();
// Destructor
~classBC() = default;
};
#endif // CLASSBC_H
classBC.pxd:
cdef extern from "classBC.cpp":
pass
cdef extern from "classBC.hpp":
cdef cppclass classBC:
classBC()
classB.pyx:
# distutils: language = c++
# distutils: include_dirs = ../A
from classBC cimport *
cdef class ClassB:
"""
"""
cdef classBC COBJ
def __cinit__(self):
pass
def __init__(self):
self.COBJ = classBC()
如果我尝试运行我的 main.py:
#!/usr/bin/python3
from src.A.classA import ClassA
from src.B.classB import ClassB
a = ClassA()
print(a.getAdata())
b = ClassB()
我收到以下错误:
Traceback (most recent call last):
File "./main.py", line 4, in <module>
from src.B.classB import ClassB
ImportError: <pathToThisFolder>/src/B/classB.cpython-38-x86_64-linux-gnu.so: undefined symbol: _ZN7classACC1Ev
我尝试将 classA.longname.so 文件链接到 classBC,但没有帮助。
甚至有可能实现这个功能吗?如果是,怎么做?
我想将所有内容分开,而不是拥有一个巨大的模块。
我的目标是让每个 setup.py 文件保持原样,并且只在 pyx 文件中使用 #distutils 添加特定的扩展选项。
谢谢你的帮助,如果这个结构真的很糟糕,请告诉我......
【问题讨论】:
-
我知道我可以用 cython 编写(而不是从 cpp 文件构建),但我做了一些基准测试,如果我用 c++ 编写代码并包装它,它会比我运行它的成员函数更快在 cython 中编写相同的函数。