xref: /llvm-project/mlir/cmake/modules/MLIRDetectPythonEnv.cmake (revision 5cd427477218d8bdb659c6c53a7758f741c3990a)
1# Macros and functions related to detecting details of the Python environment.
2
3# Finds and configures python packages needed to build MLIR Python bindings.
4macro(mlir_configure_python_dev_packages)
5  if(NOT MLIR_DISABLE_CONFIGURE_PYTHON_DEV_PACKAGES)
6    if(MLIR_DETECT_PYTHON_ENV_PRIME_SEARCH)
7      # Prime the search for python to see if there is a full development
8      # package. This seems to work around cmake bugs searching only for
9      # Development.Module in some environments. However, in other environments
10      # it may interfere with the subsequent search for Development.Module.
11      find_package(Python3 ${LLVM_MINIMUM_PYTHON_VERSION}
12        COMPONENTS Interpreter Development)
13    endif()
14
15    # After CMake 3.18, we are able to limit the scope of the search to just
16    # Development.Module. Searching for Development will fail in situations where
17    # the Python libraries are not available. When possible, limit to just
18    # Development.Module.
19    # See https://pybind11.readthedocs.io/en/stable/compiling.html#findpython-mode
20    set(_python_development_component Development.Module)
21
22    find_package(Python3 ${LLVM_MINIMUM_PYTHON_VERSION}
23      COMPONENTS Interpreter ${_python_development_component} REQUIRED)
24
25    # It's a little silly to detect Python a second time, but nanobind's cmake
26    # code looks for Python_ not Python3_.
27    find_package(Python ${LLVM_MINIMUM_PYTHON_VERSION}
28      COMPONENTS Interpreter ${_python_development_component} REQUIRED)
29
30    unset(_python_development_component)
31    message(STATUS "Found python include dirs: ${Python3_INCLUDE_DIRS}")
32    message(STATUS "Found python libraries: ${Python3_LIBRARIES}")
33    message(STATUS "Found numpy v${Python3_NumPy_VERSION}: ${Python3_NumPy_INCLUDE_DIRS}")
34    mlir_detect_pybind11_install()
35    find_package(pybind11 2.10 CONFIG REQUIRED)
36    message(STATUS "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIR}")
37    message(STATUS "Python prefix = '${PYTHON_MODULE_PREFIX}', "
38                  "suffix = '${PYTHON_MODULE_SUFFIX}', "
39                  "extension = '${PYTHON_MODULE_EXTENSION}")
40
41    mlir_detect_nanobind_install()
42    find_package(nanobind 2.4 CONFIG REQUIRED)
43    message(STATUS "Found nanobind v${nanobind_VERSION}: ${nanobind_INCLUDE_DIR}")
44    message(STATUS "Python prefix = '${PYTHON_MODULE_PREFIX}', "
45                  "suffix = '${PYTHON_MODULE_SUFFIX}', "
46                  "extension = '${PYTHON_MODULE_EXTENSION}")
47  endif()
48endmacro()
49
50# Detects a pybind11 package installed in the current python environment
51# and sets variables to allow it to be found. This allows pybind11 to be
52# installed via pip, which typically yields a much more recent version than
53# the OS install, which will be available otherwise.
54function(mlir_detect_pybind11_install)
55  if(pybind11_DIR)
56    message(STATUS "Using explicit pybind11 cmake directory: ${pybind11_DIR} (-Dpybind11_DIR to change)")
57  else()
58    message(STATUS "Checking for pybind11 in python path...")
59    execute_process(
60      COMMAND "${Python3_EXECUTABLE}"
61      -c "import pybind11;print(pybind11.get_cmake_dir(), end='')"
62      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
63      RESULT_VARIABLE STATUS
64      OUTPUT_VARIABLE PACKAGE_DIR
65      ERROR_QUIET)
66    if(NOT STATUS EQUAL "0")
67      message(STATUS "not found (install via 'pip install pybind11' or set pybind11_DIR)")
68      return()
69    endif()
70    message(STATUS "found (${PACKAGE_DIR})")
71    set(pybind11_DIR "${PACKAGE_DIR}" PARENT_SCOPE)
72  endif()
73endfunction()
74
75
76# Detects a nanobind package installed in the current python environment
77# and sets variables to allow it to be found. This allows nanobind to be
78# installed via pip, which typically yields a much more recent version than
79# the OS install, which will be available otherwise.
80function(mlir_detect_nanobind_install)
81  if(nanobind_DIR)
82    message(STATUS "Using explicit nanobind cmake directory: ${nanobind_DIR} (-Dnanobind_DIR to change)")
83  else()
84    message(STATUS "Checking for nanobind in python path...")
85    execute_process(
86      COMMAND "${Python3_EXECUTABLE}"
87      -c "import nanobind;print(nanobind.cmake_dir(), end='')"
88      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
89      RESULT_VARIABLE STATUS
90      OUTPUT_VARIABLE PACKAGE_DIR
91      ERROR_QUIET)
92    if(NOT STATUS EQUAL "0")
93      message(STATUS "not found (install via 'pip install nanobind' or set nanobind_DIR)")
94      return()
95    endif()
96    message(STATUS "found (${PACKAGE_DIR})")
97    set(nanobind_DIR "${PACKAGE_DIR}" PARENT_SCOPE)
98    execute_process(
99      COMMAND "${Python3_EXECUTABLE}"
100      -c "import nanobind;print(nanobind.include_dir(), end='')"
101      WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
102      RESULT_VARIABLE STATUS
103      OUTPUT_VARIABLE PACKAGE_DIR
104      ERROR_QUIET)
105    if(NOT STATUS EQUAL "0")
106      message(STATUS "not found (install via 'pip install nanobind' or set nanobind_DIR)")
107      return()
108    endif()
109    set(nanobind_INCLUDE_DIR "${PACKAGE_DIR}" PARENT_SCOPE)
110  endif()
111endfunction()
112