From dafe03d6b0182de8b5f2eeaa37bfbca9086a0960 Mon Sep 17 00:00:00 2001
From: Frederik Hennig <frederik.hennig@fau.de>
Date: Wed, 15 Jan 2025 16:05:53 +0100
Subject: [PATCH] Add the option to specify a custom Python interpreter in
 Cmake

---
 .../cmake/FindPystencilsSfg.cmake             | 36 ++++++++++++++++---
 .../cmake/modules/PystencilsSfg.cmake         | 17 ++++++---
 .../integration/cmake_project/CMakeLists.txt  |  4 +++
 3 files changed, 48 insertions(+), 9 deletions(-)

diff --git a/src/pystencilssfg/cmake/FindPystencilsSfg.cmake b/src/pystencilssfg/cmake/FindPystencilsSfg.cmake
index a5e7b11..a347fa7 100644
--- a/src/pystencilssfg/cmake/FindPystencilsSfg.cmake
+++ b/src/pystencilssfg/cmake/FindPystencilsSfg.cmake
@@ -1,16 +1,42 @@
-set( PystencilsSfg_FOUND OFF CACHE BOOL "pystencils source file generator found" )
+#[[
+Find-Module for pystencils-sfg.
 
-mark_as_advanced( PystencilsSfg_FOUND )
+# Setting the Python interpreter
 
-find_package( Python COMPONENTS Interpreter REQUIRED )
+If the cache entry PystencilsSfg_PYTHON_INTERPRETER is set, e.g. via the commandline
+(`-DPystencilsSfg_PYTHON_INTERPRETER=<...>`), its value be taken as the Python interpreter
+used to find and run pystencils-sfg.
+
+If the cache entry is unset, but the hint PystencilsSfg_PYTHON_PATH is set, its value will
+be used as the Python interpreter.
+
+If none of these is set, a Python interpreter will be selected using the `FindPython` module.
+
+#]]
+
+if(NOT DEFINED CACHE{PystencilsSfg_PYTHON_INTERPRETER})
+    #   The Python interpreter cache variable is not set externally, so...
+    if(DEFINED PystencilsSfg_PYTHON_PATH)
+        #   ... either initialize it from the hint variable ...
+        set( _sfg_cache_python_init ${PystencilsSfg_PYTHON_PATH} )
+    else()
+        #   ... or, if that is also unset, use the system Python
+        find_package( Python COMPONENTS Interpreter REQUIRED )
+        set( _sfg_cache_python_init ${Python_EXECUTABLE} )
+    endif()
+endif()
+
+set(PystencilsSfg_PYTHON_INTERPRETER ${_sfg_cache_python_init} CACHE PATH "Path to the Python executable used to run pystencils-sfg")
 
 #   Try to find pystencils-sfg in the python environment
 
-execute_process(COMMAND ${Python_EXECUTABLE} -m pystencilssfg version --no-newline
+execute_process(COMMAND ${PystencilsSfg_PYTHON_INTERPRETER} -m pystencilssfg version --no-newline
                 RESULT_VARIABLE _PystencilsSfgFindResult OUTPUT_VARIABLE PystencilsSfg_VERSION )
 
 if(${_PystencilsSfgFindResult} EQUAL 0)
     set( PystencilsSfg_FOUND ON )
+else()
+    set( PystencilsSfg_FOUND OFF )
 endif()
 
 if(DEFINED PystencilsSfg_FIND_REQUIRED)
@@ -22,7 +48,7 @@ endif()
 if(${PystencilsSfg_FOUND})
     message( STATUS "Found pystencils Source File Generator (Version ${PystencilsSfg_VERSION})")
     
-    execute_process(COMMAND ${Python_EXECUTABLE} -m pystencilssfg cmake modulepath --no-newline
+    execute_process(COMMAND ${PystencilsSfg_PYTHON_INTERPRETER} -m pystencilssfg cmake modulepath --no-newline
                     OUTPUT_VARIABLE _PystencilsSfg_CMAKE_MODULE_PATH)
 
     set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${_PystencilsSfg_CMAKE_MODULE_PATH})
diff --git a/src/pystencilssfg/cmake/modules/PystencilsSfg.cmake b/src/pystencilssfg/cmake/modules/PystencilsSfg.cmake
index cd1f1ba..3913c70 100644
--- a/src/pystencilssfg/cmake/modules/PystencilsSfg.cmake
+++ b/src/pystencilssfg/cmake/modules/PystencilsSfg.cmake
@@ -1,8 +1,17 @@
+#[[
+pystencils-sfg CMake module.
+
+Do not include this module directly; instead use the CMake find-module of pystencils-sfg
+to dynamically locate it.
+#]]
 
-set(PystencilsSfg_GENERATED_SOURCES_DIR "${CMAKE_BINARY_DIR}/sfg_sources" CACHE PATH "Output directory for genenerated sources" )
 
+set(PystencilsSfg_GENERATED_SOURCES_DIR "${CMAKE_BINARY_DIR}/sfg_sources" CACHE PATH "Output directory for genenerated sources" )
 mark_as_advanced(PystencilsSfg_GENERATED_SOURCES_DIR)
 
+#   This cache variable definition is a duplicate of the one in FindPystencilsSfg.cmake
+set(PystencilsSfg_PYTHON_INTERPRETER ${Python_EXECUTABLE} CACHE PATH "Path to the Python executable used to run pystencils-sfg")
+
 file(MAKE_DIRECTORY "${PystencilsSfg_GENERATED_SOURCES_DIR}")
 
 function(_pssfg_add_gen_source target script)
@@ -16,11 +25,11 @@ function(_pssfg_add_gen_source target script)
     get_filename_component(basename ${script} NAME_WLE)
     cmake_path(ABSOLUTE_PATH script OUTPUT_VARIABLE scriptAbsolute)
 
-    execute_process(COMMAND ${Python_EXECUTABLE} -m pystencilssfg list-files "--sep=;" --no-newline ${_pssfg_GENERATOR_ARGS} ${script}
+    execute_process(COMMAND ${PystencilsSfg_PYTHON_INTERPRETER} -m pystencilssfg list-files "--sep=;" --no-newline ${_pssfg_GENERATOR_ARGS} ${script}
                     OUTPUT_VARIABLE generatedSources RESULT_VARIABLE _pssfg_result
                     ERROR_VARIABLE _pssfg_stderr)
 
-    execute_process(COMMAND ${Python_EXECUTABLE} -c "from pystencils.include import get_pystencils_include_path; print(get_pystencils_include_path(), end='')"
+    execute_process(COMMAND ${PystencilsSfg_PYTHON_INTERPRETER} -c "from pystencils.include import get_pystencils_include_path; print(get_pystencils_include_path(), end='')"
                     OUTPUT_VARIABLE _Pystencils_INCLUDE_DIR)
 
     if(NOT (${_pssfg_result} EQUAL 0))
@@ -36,7 +45,7 @@ function(_pssfg_add_gen_source target script)
 
     add_custom_command(OUTPUT ${generatedSourcesAbsolute}
                        DEPENDS ${scriptAbsolute} ${_pssfg_DEPENDS}
-                       COMMAND ${Python_EXECUTABLE} ${scriptAbsolute} ${_pssfg_GENERATOR_ARGS}
+                       COMMAND ${PystencilsSfg_PYTHON_INTERPRETER} ${scriptAbsolute} ${_pssfg_GENERATOR_ARGS}
                        WORKING_DIRECTORY "${generatedSourcesDir}")
 
     target_sources(${target} PRIVATE ${generatedSourcesAbsolute})
diff --git a/tests/integration/cmake_project/CMakeLists.txt b/tests/integration/cmake_project/CMakeLists.txt
index efee912..8faa86d 100644
--- a/tests/integration/cmake_project/CMakeLists.txt
+++ b/tests/integration/cmake_project/CMakeLists.txt
@@ -5,6 +5,10 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
 
 find_package( PystencilsSfg REQUIRED )
 
+if(NOT ${PystencilsSfg_FOUND})
+    message( FATAL_ERROR "PystencilsSfg_FOUND was not set even though find_package returned successfully. This is an error." )
+endif()
+
 set( UseGlobalCfgModule OFF CACHE BOOL "Specify config module globally" )
 set( UseLocalCfgModule OFF CACHE BOOL "Specify config module locally" )
 
-- 
GitLab