构建 Python 扩展以及对 CMake 的需求
何时CMake 开发集成 C 库的 Python 扩展,提供了用于管理构建过程的综合工具。但是,典型的工作流程涉及在运行 setup.py bdist_wheel 之前使用 CMake 手动编译库。这可能不方便且耗时。
在 setup.py 中调用 CMake
为了解决这个问题,可以将 CMake 合并到 setup.py 构建过程中。关键是创建一个自定义的 build_ext 命令,利用 CMake 来配置和构建扩展。
自定义 build_ext 命令
在 setup.py 文件中,覆盖build_ext 命令类并将其注册到命令类中。在您的自定义实现中,配置并调用 CMake 来构建扩展模块。
示例项目和设置脚本
为了演示这个概念,请考虑一个带有 C 语言的简单项目扩展名 (foo) 和一个 Python 模块 (spam.eggs)。 setup.py 脚本利用 CMakeExtension 类来封装扩展,而不调用原始的 build_ext。 build_cmake 方法处理 CMake 配置和构建步骤。
<code class="python">import os import pathlib from setuptools import setup, Extension from setuptools.command.build_ext import build_ext_orig class CMakeExtension(Extension): def __init__(self, name): # don't invoke the original build_ext for this special extension super().__init__(name, sources=[]) class build_ext(build_ext_orig): def run(self): for ext in self.extensions: self.build_cmake(ext) super().run() def build_cmake(self, ext): cwd = pathlib.Path().absolute() # these dirs will be created in build_py, so if you don't have # any python sources to bundle, the dirs will be missing build_temp = pathlib.Path(self.build_temp) build_temp.mkdir(parents=True, exist_ok=True) extdir = pathlib.Path(self.get_ext_fullpath(ext.name)) extdir.mkdir(parents=True, exist_ok=True) # example of cmake args config = 'Debug' if self.debug else 'Release' cmake_args = [ '-DCMAKE_LIBRARY_OUTPUT_DIRECTORY=' + str(extdir.parent.absolute()), '-DCMAKE_BUILD_TYPE=' + config ] # example of build args build_args = [ '--config', config, '--', '-j4' ] os.chdir(str(build_temp)) self.spawn(['cmake', str(cwd)] + cmake_args) if not self.dry_run: self.spawn(['cmake', '--build', '.'] + build_args) setup( name='spam', version='0.1', packages=['spam'], ext_modules=[CMakeExtension('spam/foo')], cmdclass={ 'build_ext': build_ext, } )</code>
测试和验证
通过构建项目的轮子并安装它,您可以验证该库是否是成功安装并正常运行。从 spam.eggs 模块运行包装函数应该会产生预期的输出。
以上是如何将 CMake 集成到 setup.py 中以构建 Python 扩展?的详细内容。更多信息请关注PHP中文网其他相关文章!