Cython, CMake и setup.py, python в подкаталоге компилируются дважды - PullRequest
0 голосов
/ 06 сентября 2018

Я пытаюсь создать библиотеку C ++ вместе с привязками Cython, следуя структуре https://bloerg.net/2012/11/10/cmake-and-distutils.html.

Проблема в том, что во время make install расширение будет скомпилировано дважды. Эта двойная компиляция не происходит, когда в основной папке есть только один основной CMakeLists.txt (с измененными путями). Вот подробности:

Моя структура проекта

.
├── CMakeLists.txt
├── python
│   ├── CMakeLists.txt
│   ├── a_py.pxd
│   ├── a_py.pyx
│   └── setup.py.in
└── src
    ├── A.cpp
    └── A.h

Верхний уровень CMakeLists.txt содержит только add_subdirectory(python).

python/CMakeLists.txt является

IF(NOT ${PYTHON})
    find_program(PYTHON "python")
ENDIF()

set(SETUP_PY_IN "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.in")
set(SETUP_PY    "${CMAKE_CURRENT_BINARY_DIR}/setup.py")

set(PY_OUTPUT      "${CMAKE_CURRENT_BINARY_DIR}/build/pytimestamp")

configure_file(
    ${SETUP_PY_IN}
    ${SETUP_PY}
)

add_custom_command(OUTPUT "${PY_OUTPUT}"
                   COMMAND ${PYTHON} ${SETUP_PY} build_ext
                   COMMAND ${CMAKE_COMMAND} -E touch ${PY_OUTPUT}
               )

add_custom_target(a_py ALL DEPENDS ${PY_OUTPUT})

install(CODE "execute_process(COMMAND ${PYTHON} ${SETUP_PY} install)")

setup.py:

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

В обоих случаях (CMakeFile.txt в корне или в подпапке python) сначала выполняется шаг build_ext:

Scanning dependencies of target a_py
[100%] Generating build/pytimestamp
running build_ext

и компилирует сгенерированные a_py.cpp и A.cpp и связывает библиотеку. На этапе установки сборка запускается снова , только когда CMakeFile.txt находится в подпапке python .

Вот что происходит во время установки:

running build_ext
skipping '/Users/xxx/tmp/ctest/t08/python/a_py.cpp' Cython extension (up-to-date)
building 'a' extension
creating build

Обратите внимание, что a_py.pyx снова не цитонизируется, но каталог сборки воссоздается (то же самое между этапами сборки и установки), и файлы компилируются (с точно такими же вызовами компилятора и компоновщика).

Полный пример можно найти здесь: https://github.com/zeeMonkeez/cmakeCythonTest

1 Ответ

0 голосов
/ 19 июня 2019

У меня была такая же проблема. Очевидно, в моем случае на этапе установки 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}")
...