Cython、CMake和setup.py、python在一个子目录下编译两次

zee*_*eez 5 python cmake cython setup.py

我正在尝试按照https://bloerg.net/2012/11/10/cmake-and-distutils.html的结构与 Cython 绑定一起构建 C++ 库。

\n\n

问题是,在 期间make install,扩展将被编译两次。CMakeLists.txt当主文件夹中只有一个 main 时(已调整路径),不会发生这种双重编译。详细信息如下:

\n\n

我的项目结构是

\n\n
.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 python\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 CMakeLists.txt\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 a_py.pxd\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 a_py.pyx\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 setup.py.in\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 src\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 A.cpp\n    \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 A.h\n
Run Code Online (Sandbox Code Playgroud)\n\n

顶层CMakeLists.txt仅包含add_subdirectory(python).

\n\n

python/CMakeLists.txt

\n\n
IF(NOT ${PYTHON})\n    find_program(PYTHON "python")\nENDIF()\n\nset(SETUP_PY_IN "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in")\nset(SETUP_PY    "${CMAKE_CURRENT_BINARY_DIR}/setup.py")\n\nset(PY_OUTPUT      "${CMAKE_CURRENT_BINARY_DIR}/build/pytimestamp")\n\nconfigure_file(\n    ${SETUP_PY_IN}\n    ${SETUP_PY}\n)\n\nadd_custom_command(OUTPUT "${PY_OUTPUT}"\n                   COMMAND ${PYTHON} ${SETUP_PY} build_ext\n                   COMMAND ${CMAKE_COMMAND} -E touch ${PY_OUTPUT}\n               )\n\nadd_custom_target(a_py ALL DEPENDS ${PY_OUTPUT})\n\ninstall(CODE "execute_process(COMMAND ${PYTHON} ${SETUP_PY} install)")\n
Run Code Online (Sandbox Code Playgroud)\n\n

setup.py是:

\n\n
from distutils.core import setup\nfrom distutils.extension import Extension\nfrom Cython.Distutils import build_ext\next_modules = [\n    Extension(\n    name="a",\n    sources=["${CMAKE_CURRENT_SOURCE_DIR}/a_py.pyx", "${CMAKE_CURRENT_SOURCE_DIR}/../src/A.cpp"],\n    include_dirs = [\'${CMAKE_CURRENT_SOURCE_DIR}/../src\'],\n    language="c++",\n    ),\n]\nsetup(\n    name = \'a\',\n    version=\'${PROJECT_VERSION}\',\n    cmdclass = {\'build_ext\': build_ext},\n    ext_modules = ext_modules,\n    package_dir={ \'a\': \'${CMAKE_CURRENT_SOURCE_DIR}\' },\n)\n
Run Code Online (Sandbox Code Playgroud)\n\n

在这两种情况下(CMakeFile.txt在根文件夹或python子文件夹中),首先build_ext运行以下步骤:

\n\n
\n
Scanning dependencies of target a_py\n[100%] Generating build/pytimestamp\nrunning build_ext\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

并编译生成的a_py.cpp并链接库。\n在安装步骤中,仅当位于子文件夹A.cpp中时才会再次运行编译CMakeFile.txtpython

\n\n

这是安装过程中发生的情况:

\n\n
\n
running build_ext\nskipping \'/Users/xxx/tmp/ctest/t08/python/a_py.cpp\' Cython extension (up-to-date)\nbuilding \'a\' extension\ncreating build\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

请注意,a_py.pyx不会再次进行 cythonized,但会重新创建构建目录(构建和安装步骤之间是相同的)并且编译文件(使用完全相同的编译器和链接器调用)。

\n\n

完整的示例可以在这里找到:https://github.com/zeeMonkeez/cmakeCythonTest

\n

PJ_*_*gan 2

我有同样的问题。显然,就我而言,在安装阶段setup.py很难找到在构建阶段放置已编译扩展的目录,因此即使使用开关,它也会重新编译它们--skip-build

--build-lib我通过在构建和安装阶段分别使用和开关指定相同的目录路径来解决--build-dir

    add_custom_command(OUTPUT ${PY_OUTPUT}
            COMMAND ${PYTHON} ${SETUP_PY} build_ext --build-lib ${CMAKE_CURRENT_BINARY_DIR}/mysoext
            COMMAND ${CMAKE_COMMAND} -E touch ${PY_OUTPUT}
            DEPENDS ${DEPS}
            )
...
        set(MYINSTCMD "\
            EXECUTE_PROCESS(COMMAND ${PYTHON} ${SETUP_PY} install_lib \
            --skip-build \
            --install-dir /my/install/dir \
            --build-dir ${CMAKE_CURRENT_BINARY_DIR}/mysoext)")
        install(CODE "${MYINSTCMD}")
Run Code Online (Sandbox Code Playgroud)