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