diff --git a/CMakeLists.txt b/CMakeLists.txt index 24fafb8f6b951c56c500664c39f64011b597e054..8a733abdfff2a70241370c9f6cf8e190ab4ef589 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,15 +5,23 @@ list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ) find_package( PystencilsSfg REQUIRED ) -set( SfgConfigModule ${CMAKE_BINARY_DIR}/CodegenConfig.py ) +set( + WALBERLA_CODEGEN_CONFIG_MODULE + ${CMAKE_BINARY_DIR}/CodegenConfig.py + CACHE + FILEPATH + "Path to waLBerla-wide codegen config module" +) +mark_as_advanced( WALBERLA_CODEGEN_CONFIG_MODULE ) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/CodegenConfig.template.py - ${SfgConfigModule} + ${WALBERLA_CODEGEN_CONFIG_MODULE} ) -message( STATUS "Wrote project-wide code generator configuration to ${SfgConfigModule}" ) +message( STATUS "Wrote project-wide code generator configuration to ${WALBERLA_CODEGEN_CONFIG_MODULE}" ) -set( PystencilsSfg_CONFIG_MODULE ${SfgConfigModule} PARENT_SCOPE ) +include( CodegenFunctions ) add_library( sfg_walberla INTERFACE ) diff --git a/cmake/CodegenFunctions.cmake b/cmake/CodegenFunctions.cmake new file mode 100644 index 0000000000000000000000000000000000000000..318dad835d95d23a005201f887bfd7a7c78e1db6 --- /dev/null +++ b/cmake/CodegenFunctions.cmake @@ -0,0 +1,21 @@ +#[[ +Register code generation scripts for a CMake target. + +Signature: + +``` +walberla_generate_sources( <target> + SCRIPTS script1.py [script2.py ...] + [DEPENDS dependency1.py [dependency2.py...] ] + [FILE_EXTENSIONS <header-extension> <impl-extension>] + [OUTPUT_MODE <standalone|inline|header-only>] +) +``` + +This is a wrapper around `pystencilssfg_generate_target_sources` +without the `CONFIG_MODULE` parameter. +See also https://pycodegen.pages.i10git.cs.fau.de/pystencils-sfg/usage/project_integration.html#add-generator-scripts +#]] +function(walberla_generate_sources TARGET) + pystencilssfg_generate_target_sources(${ARGV} CONFIG_MODULE $CACHE{WALBERLA_CODEGEN_CONFIG_MODULE}) +endfunction() diff --git a/examples/GeneratorScriptBasics/BasicCodegen.py b/examples/GeneratorScriptBasics/BasicCodegen.py index 61b2e312aeed674fa3961f1ac59b7a67b0ea6d76..3151d551cf0c539ddc00f539967d8e1d52848f22 100644 --- a/examples/GeneratorScriptBasics/BasicCodegen.py +++ b/examples/GeneratorScriptBasics/BasicCodegen.py @@ -1,7 +1,7 @@ from pystencilssfg import SourceFileGenerator -from sfg_walberla import WalberlaBuildConfig with SourceFileGenerator() as sfg: - build_config = WalberlaBuildConfig.from_sfg(sfg) + sfg.include("core/DataTypes.h") + sfg.namespace("gen") + sfg.code("constexpr walberla::uint_t MAGIC_NUMBER = 0xcafe;") - print(build_config) diff --git a/examples/GeneratorScriptBasics/BasicCodegenApp.cpp b/examples/GeneratorScriptBasics/BasicCodegenApp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0cb852b61fda67ad65a4ba18612acf40f23f7882 --- /dev/null +++ b/examples/GeneratorScriptBasics/BasicCodegenApp.cpp @@ -0,0 +1,6 @@ +#include "gen/Ex_GeneratorScriptBasics/BasicCodegen.hpp" +#include <iostream> + +int main(void) { + std::cout << gen::MAGIC_NUMBER << std::endl; +} diff --git a/examples/GeneratorScriptBasics/CMakeLists.txt b/examples/GeneratorScriptBasics/CMakeLists.txt index 118434c7bc3af7560b4de6d91ada4971d7c803d9..5804fe28101f15e23ead12756d362a476ff823c5 100644 --- a/examples/GeneratorScriptBasics/CMakeLists.txt +++ b/examples/GeneratorScriptBasics/CMakeLists.txt @@ -1,12 +1,6 @@ add_executable( Ex_GeneratorScriptBasics ) -# target_sources( Ex_GeneratorScriptBasics PRIVATE Ex_GeneratorScriptBasics.cpp ) +target_sources( Ex_GeneratorScriptBasics PRIVATE BasicCodegenApp.cpp ) -pystencilssfg_generate_target_sources( Ex_GeneratorScriptBasics +walberla_generate_sources( Ex_GeneratorScriptBasics SCRIPTS BasicCodegen.py -) - -target_link_libraries( - Ex_GeneratorScriptBasics - PRIVATE - core blockforest sfg_walberla -) +) \ No newline at end of file diff --git a/examples/GeneratorScriptBasics/GeneratorScriptBasics.md b/examples/GeneratorScriptBasics/GeneratorScriptBasics.md index 1dc4edeefdc6e4ad4247338e1dd24d3deb967b80..32b0680cb2f1c82e3b22b1b60e4b9da510ff2ffd 100644 --- a/examples/GeneratorScriptBasics/GeneratorScriptBasics.md +++ b/examples/GeneratorScriptBasics/GeneratorScriptBasics.md @@ -1,8 +1,14 @@ # Getting Started with Generator Scripts -This chapter aims to give an introduction on working with +This chapter aims to give an introduction on working with *generator scripts*, +which are the driving force of the next-codegen system in waLBerla. -## Files +In the course of this guide, we will + - set up the basic structure of a generator script; + - register that script with CMake; + - and include the generated files into a simple *Hello World*-like application. + +:::{dropdown} Get The Files {download}`GeneratorScriptBasics.zip </zipped-examples/GeneratorScriptBasics.zip>`. @@ -12,13 +18,73 @@ This example comprises the following files: - `BasicCodegen.py`: A sample code generation script; - `CMakeLists.txt`: The CMake build system configuration. -## CMake Target Definition +::: + +## Our First Generator Script + +Create and open the file `BasicCodegen.py` and populate it with the following basic code: -:::{card} `CMakeLists.txt` -::::{literalinclude} CMakeLists.txt +```{literalinclude} BasicCodegen.py +:caption: BasicCodegen.py +``` + +Let's take this apart. +- In line 1, we import the `SourceFileGenerator`, which is the object responsible for running code generation + and interacting with the build system. + It is exposed by [pystencils-sfg][pystencils-sfg], a lower-level package that `sfg-walberla` relies on. +- In line 3, we enter code generation mode by opening up a managed block controlled by the `SourceFileGenerator`. + It gives us the `sfg` object, which is our primary interaction point with the code generation engine. +- In lines 4 to 6, we use the `sfg` object to do three things: + - Include a header file; this will cause the respective `#include` directive to be generated. + - Set the namespace; this will place all generated code into the `gen` namespace. + - Define a constant; this will print the definition verbatim into the output header file. + +To see the generator script in effect, we need to create a CMake target and a simple application we can include it into. +Create both the `BasicCodegenApp.cpp` and `CMakeLists.txt` files, open up `CMakeLists.txt`, and add the following: + +:::{literalinclude} CMakeLists.txt :language: CMake -:::: +:caption: CMakeLists.txt +:emphasize-lines: 4-6 ::: +At first, we create a new executable target called `Ex_GeneratorScriptBasics` +and add the `BasicCodegen.cpp` source file to it. +To us code generators, however, the second part is more interesting: +we register our generator script `BasicCodegen.py` at the target using +`walberla_generate_sources`. +This will cause the build system to execute the generator script during build, +compile its generated sources, +and make its generated headers available to us. + +To observe this, add the following to your `BasicCodegenApp.cpp`: + +```{literalinclude} BasicCodegenApp.cpp +:caption: BasicCodegenApp.cpp +``` + +Don't worry if your IDE tells you `BasicCodegen.hpp` does not exist yet; +the file will be generated in a moment. +Use CMake to build the application `Ex_GeneratorScriptBasics` and run it, and you should see it print `51966` +to stdout. + +Let's take a look at what is happening during the build. +Your CMake build output should contain a line somewhat like this: + +``` +Generating sfg_sources/gen/Ex_GeneratorScriptBasics/BasicCodegen.hpp, sfg_sources/gen/Ex_GeneratorScriptBasics/BasicCodegen.cpp +``` + +This indicates that the generator script was executed and produced exactly two files below the `sfg_sources` directory: +- a header file `gen/Ex_GeneratorScriptBasics/BasicCodegen.hpp`, which is the one we included into our application, and +- a source file ``gen/Ex_GeneratorScriptBasics/BasicCodegen.cpp`, which at this time is still empty + because we haven't yet defined any kernels or functions. + +The `walberla_generate_sources` CMake command made sure that the `sfg_sources` directory was placed in your +target's include path, so you can include the generated files. + +That covers the basics of setting up and running a code generator script; +you're all set now to generate and run your first numerical kernels. -[sfg_add_gen_scripts]: https://pycodegen.pages.i10git.cs.fau.de/pystencils-sfg/usage/project_integration.html#add-generator-scripts "pystencils-sfg Documentation" \ No newline at end of file +[pystencils-sfg]: https://pycodegen.pages.i10git.cs.fau.de/pystencils-sfg/index.html +[sfg_add_gen_scripts]: https://pycodegen.pages.i10git.cs.fau.de/pystencils-sfg/usage/project_integration.html#add-generator-scripts "pystencils-sfg Documentation" diff --git a/examples/conf.py b/examples/conf.py index ca204c777c94d36dfc0e19b74202b8c5cea70ba7..cfa54f38b4a54d40be07e51cb183f088bdf36c32 100644 --- a/examples/conf.py +++ b/examples/conf.py @@ -26,7 +26,8 @@ exclude_patterns = ["build"] myst_enable_extensions = [ "colon_fence", "dollarmath", - "attrs_inline" + "attrs_inline", + "attrs_block", ] # -- Options for HTML output -------------------------------------------------