【问题标题】:Building Python submodules from C++ extensions via cmake通过 cmake 从 C++ 扩展构建 Python 子模块
【发布时间】:2020-09-09 08:57:49
【问题描述】:

我正在尝试通过 cmake 将 c++ 扩展作为子模块合并到现有的 python 库中。构建 C++ 扩展可以正常工作并将其作为 python 模块导入,但不能作为头库的子模块。

我的目录结构如下:

frontend/
   foo.py
   bar.py
   backend/
      backend.cpp

扩展通过pybind绑定到一个python模块:

PYBIND11_MODULE(backend, m)
{
    m.doc() = "backend c++ implementation"; // optional module docstring
    m.def("method", &method, "The method I want to call from python.");
}

在CMakeLists.txt中,相关行是:

pybind11_add_module(backend "frontend/backend/backend.cpp")

我已按照herehere 的说明编写 setup.py 脚本。我猜最重要的几行是这样的:

from setuptools import setup, Extension, find_packages
from setuptools.command.build_ext import build_ext
from setuptools.command.test import test as TestCommand

class CMakeExtension(Extension):
    def __init__(self, name, sourcedir=".", sources=[]):
        Extension.__init__(self, name, sources=[])


class CMakeBuild(build_ext):
    def run(self):
        build_directory = os.path.abspath(self.build_temp)
        if not os.path.exists(self.build_temp):
            os.makedirs(self.build_temp)

        cmake_list_dir = os.path.abspath(os.path.dirname(__file__))
        print("-" * 10, "Running CMake prepare", "-" * 40)
        subprocess.check_call(
            ["cmake", cmake_list_dir], cwd=self.build_temp,
        )

        print("-" * 10, "Building extensions", "-" * 40)
        cmake_cmd = ["cmake", "--build", "."] + self.build_args
        subprocess.check_call(cmake_cmd, cwd=self.build_temp)

        # Move from build temp to final position
        for ext in self.extensions:
            self.move_output(ext)

    def move_output(self, ext):
        build_temp = Path(self.build_temp).resolve()
        dest_path = Path(self.get_ext_fullpath(ext.name)).resolve()
        source_path = build_temp / self.get_ext_filename(ext.name)
        dest_directory = dest_path.parents[0]
        dest_directory.mkdir(parents=True, exist_ok=True)
        self.copy_file(source_path, dest_path)


extensions = [CMakeExtension("backend")]

setup(
    name="frontend",
    packages=["frontend"],
    ext_modules=extensions,
    cmdclass=dict(build_ext=CMakeBuild),
)

但这不会使backend 成为frontend 的子模块,而是一个独立的模块。所以这行得通:

from backend import method

但是为了避免与其他库的命名问题,我想要的是:

from frontend.backend import method

不幸的是,将 pybinding 或扩展调用中的命名更改为 extensions = [CMakeExtension("frontend.backend")] 并不能解决我的问题,然后安装程序找不到 backend.<platform>.so 共享库,因为它会查找不存在的 frontend/backend.<platform>.so .我该如何解决这个问题?

【问题讨论】:

  • CMakeExtension("frontend.backend")] 应该是正确的。你是如何运行 setup.py 的?
  • pip install .

标签: python c++ cmake module setuptools


【解决方案1】:

我想我已经通过以下几行解决了这个问题:

setup.py 文件中的变化:

ext_modules = [
    Extension(
        "frontend.backend", sources=["frontend/backend/backend.cpp"]
    )
]

更改 CMakeLists.txt 文件:

pybind11_add_module(backend "frontend/backend/backend.cpp")
set_target_properties( backend
    PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/frontend"
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/frontend"
    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/frontend"
)

共享库对象 backend.platform.so 必须位于前端目录中。 pybind 模块名称和源文件 .cpp 都不应包含任何“。”在名称中,因为来自build_extget_ext_fullpath() 方法将按点分割。只有前端目录包含 init.py 文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-20
    • 1970-01-01
    • 2018-01-17
    • 2016-11-04
    • 2021-11-23
    • 2010-09-20
    • 1970-01-01
    • 2011-03-31
    相关资源
    最近更新 更多