diff --git a/docs/source/usage/project_integration.md b/docs/source/usage/project_integration.md index 18d0b3e250c5edde60a2c21ea1e4191e7b9f37b7..f6f3bb3e57d59ec240be441d7549c85d4eb97fae 100644 --- a/docs/source/usage/project_integration.md +++ b/docs/source/usage/project_integration.md @@ -1,22 +1,56 @@ (guide_project_integration)= # Project and Build System Integration -## Command Line Interface - -*pystencils-sfg* exposes not one, but two command line interfaces: -The *global CLI* offers a few tools meant to be used by build systems, -while the *generator script* command line interface is meant for a build system to communicate -with the code generator during on-the-fly generation. - -### Global CLI +(config_module)= +## Project-Wide Settings using Configuration Modules + +When embedding *pystencils-sfg* into a C++ project or build system, +you might want to set a project-wide base configuration for all generator scripts. +In addition, it might be necessary to pass various details about the project +and build setup to the generator scripts. +Both can be achieved by the use of a *configuration module*. + +A configuration module is a Python file that defines up to two functions: +- `def configure_sfg(cfg: SfgConfig)` is called to set up the project-wide base configuration. + It takes an {any}`SfgConfig` object which it may modify to establish the project-wide option set. +- `def project_info() -> Any` is called by *pystencils-sfg* to retrieve an object that encapsulates + any custom project-specific information. + This information is passed on to the generator scripts through + the {any}`sfg.context.project_info <SfgContext.project_info>` attribute. + +An example configuration module might look like this: + +```Python +from pystencilssfg import SfgConfig + +def configure_sfg(cfg: SfgConfig): + cfg.extensions.header = "h++" + cfg.extensions.impl = "c++" + cfg.clang_format.code_style = "llvm" + ... + +def project_info(): + return { + "project_name": "my-project", + "float_precision": "float32", + "use_cuda": False, + ... + } +``` -The global CLI may be accessed either through the `sfg-cli` shell command, or using `python -m pystencilssfg`. +Here, `project_info` returns a dictionary, but this is just for illustration; +the function may return any type of arbitrarily complex objects. +For improved API safety, {any}`dataclasses` might be a good tool for setting up +project info objects. -### Generator Script CLI +When invoking a generator script, the path to the current configuration module must be passed to it +using the `--sfg-config-module` command-line parameter. +This can be automated by an adequately set up build system, such as GNU Make or CMake. -The {any}`SourceFileGenerator` evaluates a generator script's command line arguments, -which can be supplied by the user, but more frequently by the build system. +If you are using pystencils-sfg with CMake through the provided CMake module, +[see below](#cmake_set_config_module) on how to specify a configuration module for your project. +(cmake_integration)= ## CMake Integration *pystencils-sfg* is shipped with a CMake module for on-the-fly code generation during the CMake build process. @@ -50,7 +84,8 @@ pystencilssfg_generate_target_sources( <target> SCRIPTS script1.py [script2.py ...] [DEPENDS dependency1.py [dependency2.py...]] [FILE_EXTENSIONS <header-extension> <impl-extension>] - [HEADER_ONLY]) + [OUTPUT_MODE <standalone|inline|header-only>] +) ``` It registers the generator scripts `script1.py [script2.py ...]` to be executed at compile time using `add_custom_command` @@ -72,7 +107,14 @@ path, such that generated header files for a target `<target>` may be included v #include "gen/<target>/kernels.h" ``` -### Configuration Module +(cmake_set_config_module)= +### Set a Configuration Module + +To specify a [configuration module](#config_module) for your project, +set the scoped variable `PystencilsSfg_CONFIG_MODULE` to point at the respective Python file. +The pystencils-sfg CMake system will then pass that module to each generator script invocation. -The *pystencils-sfg* CMake module reads the scoped variable `PystencilsSfg_CONFIGURATOR_SCRIPT` to find -the *configuration module* that should be passed to the generator scripts. +You might want to populate your configuration module with information about the current +build setup and environment. +For this purpose, take a look at the +[configure_file](https://cmake.org/cmake/help/latest/command/configure_file.html) CMake function. diff --git a/integration/CMakeDemo/CMakeLists.txt b/integration/CMakeDemo/CMakeLists.txt index 6642f40e63368d7ad60b4dd602eaab8e737c1c71..b69ff9aec9fe93af6d5364edb80cff67a51a5ba0 100644 --- a/integration/CMakeDemo/CMakeLists.txt +++ b/integration/CMakeDemo/CMakeLists.txt @@ -11,7 +11,7 @@ execute_process( COMMAND sfg-cli cmake make-find-module find_package( PystencilsSfg REQUIRED ) -set( PystencilsSfg_CONFIGURATOR_SCRIPT codegen_config.py ) +set( PystencilsSfg_CONFIG_MODULE codegen_config.py ) add_library( genlib ) pystencilssfg_generate_target_sources( genlib SCRIPTS kernels.py FILE_EXTENSIONS .h .cpp ) diff --git a/integration/CMakeDemo/codegen_config.py b/integration/CMakeDemo/codegen_config.py index 2f1231a95d4050b994235b4dd56e964819d774c0..8162ae460328ab0229f422c3ec9d63522106a78b 100644 --- a/integration/CMakeDemo/codegen_config.py +++ b/integration/CMakeDemo/codegen_config.py @@ -1,16 +1,6 @@ -from sys import stderr -from pystencilssfg import SfgConfiguration +from pystencilssfg import SfgConfig -def sfg_config(): - print("sfg_config() called!", file=stderr) - project_info = { - 'B': 'A' - } - - return SfgConfiguration( - header_extension='hpp', - impl_extension='cpp', - outer_namespace='cmake_demo', - project_info=project_info - ) +def configure(cfg: SfgConfig): + cfg.extensions.header = "h++" + cfg.extensions.impl = "c++" diff --git a/src/pystencilssfg/cmake/modules/PystencilsSfg.cmake b/src/pystencilssfg/cmake/modules/PystencilsSfg.cmake index deb97ce841f394ddf4ff31f2e326ce18f91706cd..c42a251fda1c4201023e8150f9e35c4427e532c8 100644 --- a/src/pystencilssfg/cmake/modules/PystencilsSfg.cmake +++ b/src/pystencilssfg/cmake/modules/PystencilsSfg.cmake @@ -54,11 +54,22 @@ function(pystencilssfg_generate_target_sources TARGET) endif() if(DEFINED PystencilsSfg_CONFIGURATOR_SCRIPT) + message(AUTHOR_WARNING "The variable PystencilsSfg_CONFIGURATOR_SCRIPT is deprecated. Set PystencilsSfg_CONFIG_MODULE instead.") cmake_path(ABSOLUTE_PATH PystencilsSfg_CONFIGURATOR_SCRIPT OUTPUT_VARIABLE configscript) list(APPEND generatorArgs "--sfg-config-module=${configscript}") list(APPEND _pssfg_DEPENDS ${configscript}) endif() + if(DEFINED PystencilsSfg_CONFIG_MODULE) + if(DEFINED PystencilsSfg_CONFIGURATOR_SCRIPT) + message(FATAL_ERROR "At most one of PystencilsSfg_CONFIGURATOR_SCRIPT and PystencilsSfg_CONFIG_MODULE may be set.") + endif() + + cmake_path(ABSOLUTE_PATH PystencilsSfg_CONFIG_MODULE OUTPUT_VARIABLE config_module) + list(APPEND generatorArgs "--sfg-config-module=${config_module}") + list(APPEND _pssfg_DEPENDS ${config_module}) + endif() + if(DEFINED _pssfg_FILE_EXTENSIONS) string(JOIN "," extensionsString ${_pssfg_FILE_EXTENSIONS})