首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过cmake从C++扩展构建Python子模块

通过cmake从C++扩展构建Python子模块
EN

Stack Overflow用户
提问于 2020-05-22 13:39:00
回答 1查看 736关注 0票数 2

我试图通过cmake将c++扩展作为子模块合并到现有的python库中。构建C++扩展很好,导入它是因为python模块可以工作,而不是作为头库的子模块。

我有以下目录结构:

代码语言:javascript
复制
frontend/
   foo.py
   bar.py
   backend/
      backend.cpp

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

代码语言:javascript
复制
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中,相关行是:

代码语言:javascript
复制
pybind11_add_module(backend "frontend/backend/backend.cpp")

我按照herehere的说明编写了setup.py脚本。我想最重要的台词是这样的:

代码语言:javascript
复制
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的子模块,而是使其成为单独的模块。因此,这是可行的:

代码语言:javascript
复制
from backend import method

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

代码语言:javascript
复制
from frontend.backend import method

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-23 13:47:24

我想我已经用以下几句话解决了这个问题:

更改setup.py文件:

代码语言:javascript
复制
ext_modules = [
    Extension(
        "frontend.backend", sources=["frontend/backend/backend.cpp"]
    )
]

更改CMakeLists.txt文件:

代码语言:javascript
复制
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都不应该包含任何“。在名称中,因为来自get_ext_fullpath()build_ext方法将被点分割。只有前端目录包含一个init.py文件。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61956365

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档