I'm trying to build a C++ library together with Cython bindings following the structure of https://bloerg.net/2012/11/10/cmake-and-distutils.html.
The issue is that during make install, the extension will be compiled twice. This double compilation does not happen when there is only one main CMakeLists.txt in the main folder (with paths adjusted). Here are the details:
My project structure is
.
├── CMakeLists.txt
├── python
│ ├── CMakeLists.txt
│ ├── a_py.pxd
│ ├── a_py.pyx
│ └── setup.py.in
└── src
├── A.cpp
└── A.h
The top level CMakeLists.txt only contains add_subdirectory(python).
python/CMakeLists.txt is
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 is:
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}' },
)
In both cases (CMakeFile.txt in root or in python subfolder), first the build_ext step runs:
Scanning dependencies of target a_py [100%] Generating build/pytimestamp running build_ext
and compiles the generated a_py.cpp and A.cpp and links the library.
During the install step, the compilation is run again only when CMakeFile.txt is in the python subfolder.
This is what happens during installation:
running build_ext skipping '/Users/xxx/tmp/ctest/t08/python/a_py.cpp' Cython extension (up-to-date) building 'a' extension creating build
Note that the a_py.pyx does not get cythonized again, but the build directory gets recreated (it is the same between the build and install steps) and the files are compiled (with exactly the same compiler and linker invocations).
A full example can be found here: https://github.com/zeeMonkeez/cmakeCythonTest