在 CMake 中使用 setup.py 构建 python 包

Posted

技术标签:

【中文标题】在 CMake 中使用 setup.py 构建 python 包【英文标题】:Build a python package with setup.py in CMake 【发布时间】:2015-05-27 18:18:59 【问题描述】:

编辑:这个问题有点太长了。这是我真正的问题:如何在 CMake 中使用 setuptools (setup.py) 构建和安装 python 包?我的代码的详细信息如下所示(但使用源外构建方法,带有源的方法是有效的)。


我有一个项目需要分发我自己的 python 包。我制作了一个 setup.py 脚本,但我想用 CMake 构建和安装它。

我关注了Using CMake with setup.py,但它只适用于CMakeLists.txt 旁边的setup.py 和python 文件夹,并且没有从构建目录执行cmake。

使用这种布局:

Project/
--build/
--lib/
----python/
------folder1/
------folder2/
------data/
------...
------__init__.py
----setup.py
----CMakeLists.txt
--CMakeLists.txt

CMakeLists.txt:

cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)
add_subdirectory(lib)
(..)

lib/CMakeLists.txt:

find_program(PYTHON "python")

if (PYTHON)
    set(SETUP_PY_IN "$CMAKE_CURRENT_SOURCE_DIR/setup.py")
    set(SETUP_PY    "$CMAKE_CURRENT_BINARY_DIR/setup.py")
    set(DEPS        "$CMAKE_CURRENT_SOURCE_DIR/python/__init__.py")
    set(OUTPUT      "$CMAKE_CURRENT_BINARY_DIR/build")

    configure_file($SETUP_PY_IN $SETUP_PY)

    add_custom_command(OUTPUT $OUTPUT
                       COMMAND $PYTHON
                       ARGS setup.py build
                       DEPENDS $DEPS)

    add_custom_target(target ALL DEPENDS $OUTPUT)

    install(CODE "execute_process(COMMAND $PYTHON $SETUP_PY install)")
endif()

setup.py:

from setuptools import setup, find_packages

setup(name="python",
    version="xx",
    author="xx",
    packages = find_packages(),
    package_data = '': ['*.txt'],
    description="Python lib for xx")

当我从构建目录运行CMake,然后运行make 时,目标已构建,但没有任何内容。就好像没有找到包裹一样。安装安装没有.py文件的python包。

【问题讨论】:

你试过在 add_custom_command 中设置 WORKING_DIRECTORY 吗? 您应该使用相对于当前源目录的所有路径。放置一行,例如DIR = os.path.dirname(os.path.realpath(__file__)),然后使所有包都与该目录相关,以便从源代码构建。 【参考方案1】:

setuptools 不知道源代码外构建,因此找不到任何 python 源文件(因为您没有将它们复制到二进制目录,所以那里似乎只存在 setup.py 文件)。为了解决这个问题,您必须将 python 源代码树复制到 CMAKE_CURRENT_BINARY_DIR

【讨论】:

【参考方案2】:

https://bloerg.net/2012/11/10/cmake-and-distutils.html 建议在setup.py 中将package_dir 设置为$CMAKE_CURRENT_SOURCE_DIR

【讨论】:

【参考方案3】:

如前所述,您可以将 python 文件复制到构建文件夹,例如像这样的

set(TARGET_NAME YourLib)
file(GLOB_RECURSE pyfiles python/*.py)
foreach (filename $pyfiles)
    get_filename_component(target "$filename" NAME)
    message(STATUS "Copying $filename to $TARGET_NAME/$target")
    configure_file("$filename" 
    "$CMAKE_CURRENT_BINARY_DIR/$TARGET_NAME/$target" COPYONLY)
endforeach (filename)

然后有一个像这样的构建目标

add_custom_target(PyPackageBuild
        COMMAND "$PYTHON_EXECUTABLE" -m pip wheel .
        WORKING_DIRECTORY "$CMAKE_CURRENT_BINARY_DIR"
        COMMENT "Building python wheel package"
        )
add_dependencies(PyPackageBuild $TARGET_NAME)

如果您不想使用 pip,则必须调整 PyPackageBuld 目标。

如果你想包含一些共享库,例如用 C++ 编写,由 cmake 项目的其他部分构建,您必须将共享对象文件也复制到二进制文件夹中

set_target_properties($TARGET_NAME PROPERTIES
        PREFIX "$PYTHON_MODULE_PREFIX"
        SUFFIX "$PYTHON_MODULE_EXTENSION"
        BUILD_DIRECTORY "$CMAKE_CURRENT_BINARY_DIR"
        LIBRARY_OUTPUT_DIRECTORY "$CMAKE_CURRENT_BINARY_DIR/$TARGET_NAME/libs"
        BUILD_WITH_INSTALL_RPATH TRUE)
set(TARGET_PYMODULE_NAME "$PYTHON_MODULE_PREFIX$TARGET_NAME$PYTHON_MODULE_EXTENSION")

并将其添加到setup.py中的package_data

....
package_data=
        '': ['libs/YourLib.cpython-39-x86_64-linux-gnu.so']
    

您可以在https://github.com/maximiliank/cmake_python_r_example 找到使用pybind11 进行“C++”绑定的工作示例

【讨论】:

cython版本,setup.py中的共享库名archticture args可以通过import sysconfigf'libs/YourLibsysconfig.get_config_var("EXT_SUFFIX")'获取。

以上是关于在 CMake 中使用 setup.py 构建 python 包的主要内容,如果未能解决你的问题,请参考以下文章

python的构建工具——setup.py文件

dlib(setup.py)循环的构建轮

Mac 上的 h5py setup.py:找不到 hdf5.h 文件

在 setup.py 文件中直接包含一个 pyd

如何使用 setuptools 和 setup.py 从包中排除单个文件

Python Setup.py Build_Ext --inplace