Skip to content

Commit

Permalink
improve litgen_cmake
Browse files Browse the repository at this point in the history
  • Loading branch information
pthom committed Dec 5, 2024
1 parent c78150a commit f5d154c
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 52 deletions.
2 changes: 1 addition & 1 deletion _litgen_template
121 changes: 70 additions & 51 deletions src/litgen/integration_tests/litgen_cmake/litgen_cmake.cmake
Original file line number Diff line number Diff line change
@@ -1,26 +1,57 @@
set(litgen_cmake_help_message "
This Cmake module provides two public functions:
This Cmake module provides several public functions:
litgen_find_python
******************
litgen_find_python() will find Python >= 3.8 with the interpreter and Development module.
(and working around quirks of CMake 3.18 and below)
litgen_find_pybind11()
*******************************************************************************
**********************
litgen_find_pybind11() will find pybind11 and Python3
It is equivalent to:
find_package(Python 3.8 REQUIRED COMPONENTS Interpreter Development[.Module])
find_package(pybind11 CONFIG REQUIRED)
(after having altered CMAKE_PREFIX_PATH by adding the path to pybind11 provided
by `pip install pybind11`. This is helpful when building the C++ library outside of skbuild)
When building via CMake, you may have to specify Python_EXECUTABLE via
-DPython_EXECUTABLE=/path/to/your/venv/bin/python
litgen_find_nanobind
*********************
litgen_find_nanobind() will find nanobind and Python3
litgen_setup_module(bound_library python_native_module_name python_module_name)
*******************************************************************************
litgen_setup_module is a helper function that will:
* link the python native module (.so) to the bound C++ library (bound_library)
* set the install path of the native module to '.' (so that pip install works)
* automatically copy the native module to the python module folder after build
(so that editable mode works even when you modify the C++ library and rebuild)
* set the VERSION_INFO macro to the project version defined in CMakeLists.txt
* when building as a C++ project (i.e. not with skbuild), it will copy the python module
to the editable_bindings_folder and to the platform dependent installation directory
(site-packages when using pip install), so that it is used by our next runs of python.
Note: how to specify the version of Python to use
*************************************************
When building via CMake, you may have to specify Python_EXECUTABLE via
-DPython_EXECUTABLE=/path/to/your/venv/bin/python
")

macro(litgen_find_python)
# cf https://nanobind.readthedocs.io/en/latest/building.html
if (CMAKE_VERSION VERSION_LESS 3.18)
set(DEV_MODULE Development)
else()
set(DEV_MODULE Development.Module)
endif()

find_package(Python 3.8 COMPONENTS Interpreter ${DEV_MODULE} REQUIRED)
endmacro()


# When building outside of skbuild, we need to add the path to pybind11 provided by pip
function(_lg_add_pybind11_pip_cmake_prefix_path)
execute_process(
Expand All @@ -43,16 +74,7 @@ endfunction()


function(litgen_find_pybind11)
if(SKBUILD)
# we only need the Development.Module component to build native modules
find_package(Python 3.8 REQUIRED COMPONENTS Interpreter Development.Module)
else()
# when building via CMake, we need the full Development component,
# to be able to debug the native module
find_package(Python 3.8 REQUIRED COMPONENTS Interpreter Development)
endif()
set(Python_EXECUTABLE ${Python_EXECUTABLE} CACHE PATH "Python executable" FORCE)

litgen_find_python()
if(NOT SKBUILD)
# when building via CMake, we need to add the path to pybind11 provided by pip
# (skbuild does it automatically)
Expand All @@ -64,14 +86,7 @@ endfunction()


macro(litgen_find_nanobind)
# cf https://nanobind.readthedocs.io/en/latest/building.html
if (CMAKE_VERSION VERSION_LESS 3.18)
set(DEV_MODULE Development)
else()
set(DEV_MODULE Development.Module)
endif()

find_package(Python 3.8 COMPONENTS Interpreter ${DEV_MODULE} REQUIRED)
litgen_find_python()

# Detect the installed nanobind package and import it into CMake
execute_process(
Expand Down Expand Up @@ -101,33 +116,37 @@ function(litgen_setup_module
# Set VERSION_INFO macro to the project version defined in CMakeLists.txt (absolutely optional)
target_compile_definitions(${python_native_module_name} PRIVATE VERSION_INFO=${PROJECT_VERSION})

# Copy the python module for editable mode
set(bindings_module_folder ${editable_bindings_folder}/${python_module_name})
set(python_native_module_editable_location ${bindings_module_folder}/$<TARGET_FILE_NAME:${python_native_module_name}>)
add_custom_target(
${python_module_name}_deploy_editable
ALL
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${python_native_module_name}> ${python_native_module_editable_location}
DEPENDS ${python_native_module_name}
)

# Also copy the python module to the site-packages folder (for non-editable mode)
# First, ask python for site-packages folder
execute_process(
COMMAND "${Python_EXECUTABLE}" -c "import sysconfig; print(sysconfig.get_path('platlib'))"
OUTPUT_VARIABLE python_site_packages
OUTPUT_STRIP_TRAILING_WHITESPACE COMMAND_ECHO STDOUT
RESULT_VARIABLE _result_python_site_packages
)
if(NOT _result_python_site_packages EQUAL 0)
message(FATAL_ERROR "Failed to get python site-packages folder")
endif()
set(python_native_module_editable_location_site_packages ${python_site_packages}/${python_module_name}/$<TARGET_FILE_NAME:${python_native_module_name}>)
add_custom_target(
${python_module_name}_deploy_editable_site_packages
ALL
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${python_native_module_name}> ${python_native_module_editable_location_site_packages}
DEPENDS ${python_native_module_name})
# message(STATUS "Python native module will be copied to ${python_native_module_editable_location_site_packages}")

if (NOT SKBUILD)
# If we are **not** building with skbuild, it means that we are **not** building a wheel for pipy or conda.
#
# Instead, we are building as a standard C++ project: in this case, we want to deploy our compiled module
# so that it is used by our next runs of python.
#
# We will copy it into two different locations, to cover all cases:
# - 1. ${editable_bindings_folder}: the user selected binding folder
# (if the user did *manually* prepend it to his python path)
# - 2. ${Python_SITEARCH}: the platform dependent installation directory
# (site-packages when using pip install)

# 1. Copy the python module to editable_bindings_folder
set(bindings_module_folder ${editable_bindings_folder}/${python_module_name})
set(python_native_module_editable_location ${bindings_module_folder}/$<TARGET_FILE_NAME:${python_native_module_name}>)
add_custom_target(
${python_module_name}_deploy_editable
ALL
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${python_native_module_name}> ${python_native_module_editable_location}
DEPENDS ${python_native_module_name}
)

# 2. Copy the python module to the platform dependent installation directory (site-packages when using pip install)
# We'll rely on find_package(Python) which fills Python_SITEARCH, which is where we want to copy the module
litgen_find_python() # will call find_package(Python) and set Python_SITEARCH
set(python_native_module_editable_location_site_packages ${Python_SITEARCH}/${python_module_name}/$<TARGET_FILE_NAME:${python_native_module_name}>)
add_custom_target(
${python_module_name}_deploy_editable_site_packages
ALL
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${python_native_module_name}> ${python_native_module_editable_location_site_packages}
DEPENDS ${python_native_module_name})
message(STATUS "litgen_setup_module: python native module will be copied to ${python_native_module_editable_location_site_packages}")
endif(NOT SKBUILD)
endfunction()

0 comments on commit f5d154c

Please sign in to comment.