Skip to content

Commit d75ffa1

Browse files
committed
Implement python bindings for 4C mixture module
1 parent 2248a1f commit d75ffa1

17 files changed

+687
-0
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ set(FULL_TARGETS
170170
add_custom_target(full DEPENDS ${FOUR_C_EXECUTABLE_NAME} ${FULL_TARGETS})
171171

172172
include(cmake/setup_tests.cmake)
173+
include(cmake/setup_py4C.cmake)
173174

174175
# Create one large library: every module adds itself to this target
175176
set(FOUR_C_LIBRARY_NAME lib4C)
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# This file is part of 4C multiphysics licensed under the
2+
# GNU Lesser General Public License v3.0 or later.
3+
#
4+
# See the LICENSE.md file in the top-level for license information.
5+
#
6+
# SPDX-License-Identifier: LGPL-3.0-or-later
7+
8+
# Automatically creates a python binding submodule for all sources and headers in the current directory. The target
9+
# will be named based on the folder name. If this function is called recursively inside an already
10+
# defined submodule, the sources are appended to the already defined submodule. The submodule name is returned
11+
# in the variable AUTO_DEFINED_SUBMODULE_NAME which is set at the call site.
12+
function(four_c_auto_define_python_binding_submodule)
13+
if(NOT FOUR_C_WITH_PYBIND11)
14+
return()
15+
endif()
16+
17+
set(options "")
18+
set(oneValueArgs MODULE)
19+
set(multiValueArgs "")
20+
cmake_parse_arguments(
21+
_parsed
22+
"${options}"
23+
"${oneValueArgs}"
24+
"${multiValueArgs}"
25+
${ARGN}
26+
)
27+
if(DEFINED _parsed_UNPARSED_ARGUMENTS)
28+
message(FATAL_ERROR "There are unparsed arguments: ${_parsed_UNPARSED_ARGUMENTS}")
29+
endif()
30+
31+
if(_parsed_MODULE)
32+
set(_bindings_for_module ${_parsed_MODULE})
33+
else()
34+
if("${FOUR_C_CURRENTLY_DEFINED_PARENT_SUBMODULE}" STREQUAL "")
35+
message(
36+
FATAL_ERROR
37+
"No parent module is set. Either give the module these bindings belongs to or call this functions inside a module."
38+
)
39+
endif()
40+
41+
set(_bindings_for_module "${FOUR_C_CURRENTLY_DEFINED_PARENT_SUBMODULE}")
42+
endif()
43+
44+
if(NOT TARGET "${_bindings_for_module}_objs")
45+
message(
46+
FATAL_ERROR
47+
"Tried to add bindings for a module named '${_bindings_for_module}' which is not a known module name."
48+
)
49+
endif()
50+
51+
# create the name of the current binding
52+
set(_target pybind11_${_bindings_for_module})
53+
54+
# create an object target for the current submodule (and fill it with a dummy cpp-file)
55+
add_library(${_target}_objs OBJECT ${PROJECT_SOURCE_DIR}/cmake/dummy.cpp)
56+
57+
# Add all source files of this folder to this target
58+
file(GLOB_RECURSE _sources CONFIGURE_DEPENDS *.cpp)
59+
target_sources(${_target}_objs PRIVATE ${_sources})
60+
61+
# Link the python binding configuration to this target
62+
target_link_libraries(${_target}_objs PUBLIC py4C_config)
63+
64+
# Python bindings require position independent code so that Python can dynamically link the library
65+
target_link_libraries(${_target}_objs PRIVATE four_c_private_compile_interface)
66+
67+
# Link all dependencies of the respective 4C module to this python binding submodule
68+
target_link_libraries(${_target}_objs PRIVATE ${_bindings_for_module}_module)
69+
70+
# Add the current submodule object file to the main python bindings target
71+
target_link_libraries(${FOUR_C_PYTHON_BINDINGS_PROJECT_NAME} PRIVATE ${_target}_objs)
72+
73+
# Now check if there are more directories that contain CMakeLists.txt. If yes, we also add those.
74+
# For this action, we become the parent submodule of the sub-submodules we are about to define.
75+
set(FOUR_C_CURRENTLY_DEFINED_PARENT_SUBMODULE ${_target})
76+
# Recursively add all subdirectories that contain CMakeLists.txt files.
77+
# N.B. We need to directly glob for CMakeLists.txt files here to ensure
78+
# the glob reruns when a new CMakeLists.txt is added.
79+
file(
80+
GLOB children
81+
RELATIVE ${CMAKE_CURRENT_LIST_DIR}
82+
CONFIGURE_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/*/CMakeLists.txt
83+
)
84+
foreach(child ${children})
85+
get_filename_component(_subdir ${child} DIRECTORY)
86+
add_subdirectory(${_subdir})
87+
endforeach()
88+
89+
# Simulate a "return" by setting a variable at the call site
90+
set(AUTO_DEFINED_SUBMODULE_NAME
91+
${_target}
92+
PARENT_SCOPE
93+
)
94+
endfunction()
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# This file is part of 4C multiphysics licensed under the
2+
# GNU Lesser General Public License v3.0 or later.
3+
#
4+
# See the LICENSE.md file in the top-level for license information.
5+
#
6+
# SPDX-License-Identifier: LGPL-3.0-or-later
7+
8+
function(four_c_auto_define_python_bindings_tests)
9+
# only add tests if
10+
if(NOT FOUR_C_ENABLE_PYTHON_BINDINGS)
11+
return()
12+
endif()
13+
14+
set(options "")
15+
set(oneValueArgs MODULE)
16+
set(multiValueArgs "")
17+
cmake_parse_arguments(
18+
_parsed
19+
"${options}"
20+
"${oneValueArgs}"
21+
"${multiValueArgs}"
22+
${ARGN}
23+
)
24+
if(DEFINED _parsed_UNPARSED_ARGUMENTS)
25+
message(FATAL_ERROR "There are unparsed arguments: ${_parsed_UNPARSED_ARGUMENTS}")
26+
endif()
27+
28+
if(_parsed_MODULE)
29+
set(_module_under_test ${_parsed_MODULE})
30+
else()
31+
message(FATAL_ERROR "MODULE not set")
32+
endif()
33+
34+
set(_test_directory ${PROJECT_BINARY_DIR}/python_binding_test_${_parsed_MODULE})
35+
36+
set(_python_binding_test_command_list
37+
"rm -rf ${_test_directory}" "mkdir -p ${_test_directory}" "cd ${_test_directory}"
38+
"python -m venv venv" ". venv/bin/activate" "pip install --upgrade pip"
39+
"[ -f ${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt ] && pip install -r ${CMAKE_CURRENT_SOURCE_DIR}/requirements.txt"
40+
"pip install pytest"
41+
"pip install -e ${PROJECT_BINARY_DIR}/${FOUR_C_PYTHON_BINDINGS_PROJECT_NAME}" # Install bindings in developer mode!
42+
"pytest ${CMAKE_CURRENT_SOURCE_DIR}" "rm -rf ${_test_directory}"
43+
)
44+
45+
# Join them into a single shell command separated by &&
46+
string(JOIN " && " _python_binding_test_command ${_python_binding_test_command_list})
47+
48+
add_test(
49+
NAME ${FOUR_C_PYTHON_BINDINGS_PROJECT_NAME}.${_parsed_MODULE}
50+
COMMAND ${CMAKE_COMMAND} -E env bash -c "${_python_binding_test_command}"
51+
)
52+
53+
endfunction()

cmake/setup_py4C.cmake

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# This file is part of 4C multiphysics licensed under the
2+
# GNU Lesser General Public License v3.0 or later.
3+
#
4+
# See the LICENSE.md file in the top-level for license information.
5+
#
6+
# SPDX-License-Identifier: LGPL-3.0-or-later
7+
8+
if(FOUR_C_ENABLE_PYTHON_BINDINGS)
9+
# Python bindings require position independent code
10+
if(NOT FOUR_C_BUILD_SHARED_LIBS)
11+
message(
12+
FATAL_ERROR
13+
"4C Python bindings require to build 4C with shared libraries (FOUR_C_BUILD_SHARED_LIBS)."
14+
)
15+
endif()
16+
17+
# Python bindings require pybind11
18+
if(NOT FOUR_C_WITH_PYBIND11)
19+
message(
20+
FATAL_ERROR "4C Python bindings require to build 4C with pybind11 (FOUR_C_WITH_PYBIND11)."
21+
)
22+
endif()
23+
24+
# define the name of the python module
25+
set(FOUR_C_PYTHON_BINDINGS_PROJECT_NAME py4C)
26+
27+
# Add setup.py to make python package installable
28+
configure_file(
29+
${PROJECT_SOURCE_DIR}/utilities/py4C/src/config/setup.py.in
30+
${PROJECT_BINARY_DIR}/${FOUR_C_PYTHON_BINDINGS_PROJECT_NAME}/setup.py
31+
@ONLY
32+
)
33+
34+
# Add __init__.py and import from there all pybind11 functions and classes
35+
configure_file(
36+
${PROJECT_SOURCE_DIR}/utilities/py4C/src/config/__init__.py.in
37+
${PROJECT_BINARY_DIR}/${FOUR_C_PYTHON_BINDINGS_PROJECT_NAME}/__init__.py
38+
)
39+
40+
# Add the py4C directory
41+
add_subdirectory(${PROJECT_SOURCE_DIR}/utilities/py4C)
42+
endif()

src/mixture/python/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# This file is part of 4C multiphysics licensed under the
2+
# GNU Lesser General Public License v3.0 or later.
3+
#
4+
# See the LICENSE.md file in the top-level for license information.
5+
#
6+
# SPDX-License-Identifier: LGPL-3.0-or-later
7+
8+
add_subdirectory(bindings)
9+
add_subdirectory(tests)

0 commit comments

Comments
 (0)