spl-core 6.3.1__py3-none-any.whl → 6.4.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
spl_core/common.cmake ADDED
@@ -0,0 +1,725 @@
1
+ macro(_spl_slash_to_underscore out in)
2
+ string(REGEX REPLACE "/" "_" ${out} ${in})
3
+ endmacro()
4
+
5
+ macro(_spl_get_absolute_path out in)
6
+ if(IS_ABSOLUTE ${in})
7
+ cmake_path(CONVERT ${in} TO_CMAKE_PATH_LIST ${out} NORMALIZE)
8
+ else()
9
+ cmake_path(CONVERT ${CMAKE_CURRENT_LIST_DIR}/${in} TO_CMAKE_PATH_LIST ${out} NORMALIZE)
10
+ endif()
11
+ endmacro()
12
+
13
+ macro(spl_add_component component_path)
14
+ message(DEBUG "spl_add_component: component_path=${component_path}")
15
+ _spl_slash_to_underscore(component_name ${component_path})
16
+ add_subdirectory(${CMAKE_SOURCE_DIR}/${component_path})
17
+
18
+ if(TARGET ${component_name})
19
+ if(BUILD_KIT STREQUAL prod)
20
+ target_link_libraries(${LINK_TARGET_NAME} ${component_name})
21
+ endif()
22
+ endif()
23
+ endmacro()
24
+
25
+ macro(spl_add_named_component component_name)
26
+ message(DEBUG "spl_add_named_component: component_name=${component_name}")
27
+ set(component_path ${${component_name}})
28
+
29
+ if(IS_ABSOLUTE ${component_path})
30
+ add_subdirectory(${component_path})
31
+ else()
32
+ add_subdirectory(${CMAKE_SOURCE_DIR}/${component_path})
33
+ endif()
34
+
35
+ if(TARGET ${component_name})
36
+ if(BUILD_KIT STREQUAL prod)
37
+ target_link_libraries(${LINK_TARGET_NAME} ${component_name})
38
+ endif()
39
+ endif()
40
+ endmacro()
41
+
42
+ macro(spl_add_source fileName)
43
+ message(DEBUG "spl_add_source: fileName=${fileName}")
44
+ cmake_parse_arguments(ADD_SOURCE_ARGS "" "" "COMPILE_OPTIONS" ${ARGN})
45
+ _spl_get_absolute_path(to_be_appended ${fileName})
46
+ list(APPEND SOURCES ${to_be_appended})
47
+
48
+ if(ADD_SOURCE_ARGS_COMPILE_OPTIONS)
49
+ message(DEBUG "spl_add_source: ADD_SOURCE_ARGS_COMPILE_OPTIONS=${ADD_SOURCE_ARGS_COMPILE_OPTIONS}")
50
+ set_source_files_properties(${to_be_appended} PROPERTIES COMPILE_OPTIONS "${ADD_SOURCE_ARGS_COMPILE_OPTIONS}")
51
+ endif()
52
+ endmacro()
53
+
54
+ macro(spl_add_compile_options pattern)
55
+ message(DEBUG "spl_add_compile_options: pattern=${pattern}")
56
+ cmake_parse_arguments(ADD_SOURCE_ARGS "" "" "COMPILE_OPTIONS" ${ARGN})
57
+ message(DEBUG "spl_add_source: ADD_SOURCE_ARGS_COMPILE_OPTIONS=${ADD_SOURCE_ARGS_COMPILE_OPTIONS}")
58
+
59
+ file(GLOB_RECURSE files ${CMAKE_CURRENT_LIST_DIR}/${pattern})
60
+ message(DEBUG "spl_add_compile_options: files=${files}")
61
+
62
+ if(files)
63
+ foreach(file ${files})
64
+ set_source_files_properties(${file} PROPERTIES COMPILE_OPTIONS "${ADD_SOURCE_ARGS_COMPILE_OPTIONS}")
65
+ endforeach()
66
+ endif()
67
+ endmacro()
68
+
69
+ macro(spl_add_include includeDirectory)
70
+ _spl_get_absolute_path(to_be_appended ${includeDirectory})
71
+ list(APPEND INCLUDES ${to_be_appended})
72
+ endmacro()
73
+
74
+ macro(spl_add_test_source fileName)
75
+ _spl_get_absolute_path(to_be_appended ${fileName})
76
+ list(APPEND TEST_SOURCES ${to_be_appended})
77
+ endmacro()
78
+
79
+ macro(_spl_get_google_test)
80
+ # GoogleTest requires at least C++14
81
+ set(CMAKE_CXX_STANDARD 14)
82
+
83
+ # Make source of googletest configurable
84
+ if(NOT DEFINED SPL_GTEST_URL)
85
+ set(SPL_GTEST_URL https://github.com/google/googletest.git)
86
+ endif(NOT DEFINED SPL_GTEST_URL)
87
+
88
+ if(NOT DEFINED SPL_GTEST_TAG)
89
+ set(SPL_GTEST_TAG v1.14.0)
90
+ endif(NOT DEFINED SPL_GTEST_TAG)
91
+
92
+ include(FetchContent)
93
+ FetchContent_Declare(
94
+ googletest
95
+ GIT_REPOSITORY ${SPL_GTEST_URL}
96
+ GIT_TAG ${SPL_GTEST_TAG}
97
+ )
98
+
99
+ # Prevent overriding the parent project's compiler/linker settings on Windows
100
+ if(WIN32)
101
+ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
102
+ endif()
103
+
104
+ # The Python version we want to use is in the PATH, so disable any search for it.
105
+ # Got it from here: https://stackoverflow.com/questions/73514630/make-cmake-not-search-for-python-components-on-reconfigure
106
+ set(CMAKE_DISABLE_FIND_PACKAGE_Python TRUE)
107
+
108
+ FetchContent_MakeAvailable(googletest)
109
+ include(GoogleTest)
110
+
111
+ enable_testing()
112
+ endmacro(_spl_get_google_test)
113
+
114
+ macro(spl_create_component)
115
+ cmake_parse_arguments(CREATE_COMPONENT "" "NAME;LONG_NAME;LIBRARY_TYPE" "" ${ARGN})
116
+
117
+ # Set the default library type to OBJECT if not provided
118
+ if(NOT CREATE_COMPONENT_LIBRARY_TYPE)
119
+ set(CREATE_COMPONENT_LIBRARY_TYPE "OBJECT")
120
+ endif()
121
+
122
+ # Determine the unique component name based on the relative path of the component
123
+ file(RELATIVE_PATH component_path ${CMAKE_SOURCE_DIR} ${CMAKE_CURRENT_LIST_DIR})
124
+
125
+ if(NOT CREATE_COMPONENT_NAME)
126
+ _spl_slash_to_underscore(component_name ${component_path})
127
+ else()
128
+ set(component_name ${CREATE_COMPONENT_NAME})
129
+ endif()
130
+
131
+ # Collect all productive sources for later usage (e.g., in an extension)
132
+ list(APPEND PROD_SOURCES ${SOURCES})
133
+ set(PROD_SOURCES ${PROD_SOURCES} PARENT_SCOPE)
134
+ message(DEBUG "Productive sources: ${PROD_SOURCES}")
135
+
136
+ # Collect all component names for later usage (e.g., in an extension)
137
+ list(APPEND COMPONENT_NAMES ${component_name})
138
+ set(COMPONENT_NAMES ${COMPONENT_NAMES} PARENT_SCOPE)
139
+
140
+ # collect sources for each component in JSON format
141
+ if(SOURCES)
142
+ # Whitespaces are needed for beautified JSON output
143
+ list(JOIN SOURCES "\",\n \"" formatted_json_sources)
144
+ set(formatted_json_sources "[\n \"${formatted_json_sources}\"\n ]")
145
+ else()
146
+ set(formatted_json_sources "[]")
147
+ endif()
148
+
149
+ # collect test sources for each component in JSON format
150
+ if(TEST_SOURCES)
151
+ # Whitespaces are needed for beautified JSON output
152
+ list(JOIN TEST_SOURCES "\",\n \"" formatted_json_test_sources)
153
+ set(formatted_json_test_sources "[\n \"${formatted_json_test_sources}\"\n ]")
154
+ else()
155
+ set(formatted_json_test_sources "[]")
156
+ endif()
157
+
158
+ # Collect all component information for build.json
159
+ set(_build_info " {
160
+ \"name\": \"${component_name}\",
161
+ \"long_name\": \"${CREATE_COMPONENT_LONG_NAME}\",
162
+ \"path\": \"${CMAKE_SOURCE_DIR}/${component_path}\",
163
+ \"sources\": ${formatted_json_sources},
164
+ \"test_sources\": ${formatted_json_test_sources}
165
+ }")
166
+
167
+ # Append the component information to the global build_info list
168
+ list(APPEND build_info ${_build_info})
169
+ set(build_info ${build_info} PARENT_SCOPE)
170
+
171
+ # Collect all component information for sphinx documentation
172
+ # - We need to keep track of all components and their information to be able to generate the variant reports.
173
+ # For the variants reports, one need to loop over all components and generate component variant specific targets.
174
+ # - We use json strings because the content will be written in a config.json file during configure.
175
+ # Also, CMake supports manipulating JSON strings. See the string(JSON ...) documentation.
176
+ set(_component_info "{
177
+ \"name\": \"${component_name}\",
178
+ \"long_name\": \"${CREATE_COMPONENT_LONG_NAME}\",
179
+ \"path\": \"${component_path}\",
180
+ \"has_docs\": \"\",
181
+ \"docs_output_dir\": \"\",
182
+ \"has_reports\": \"\",
183
+ \"reports_output_dir\": \"\"
184
+ }")
185
+
186
+ list(APPEND target_include_directories__INCLUDES ${CMAKE_CURRENT_LIST_DIR}/src)
187
+ list(APPEND target_include_directories__INCLUDES ${CMAKE_CURRENT_BINARY_DIR})
188
+
189
+ list(APPEND target_include_directories__INCLUDES ${INCLUDES})
190
+ list(REMOVE_DUPLICATES target_include_directories__INCLUDES)
191
+ set(target_include_directories__INCLUDES ${target_include_directories__INCLUDES} PARENT_SCOPE)
192
+
193
+ if(BUILD_KIT STREQUAL prod)
194
+ if(SOURCES)
195
+ # Create the component library
196
+ add_library(${component_name} ${CREATE_COMPONENT_LIBRARY_TYPE} ${SOURCES})
197
+
198
+ # Define list of productive specific compile options for component's sources
199
+ target_compile_definitions(${component_name} PRIVATE
200
+ SPLE_TESTABLE_STATIC=static
201
+ SPLE_TESTABLE_INLINE=inline
202
+ static_scope_file=static
203
+ )
204
+ endif()
205
+ elseif(BUILD_KIT STREQUAL test)
206
+ # Create component unittests target
207
+ if(TEST_SOURCES)
208
+ _spl_add_test_suite(${component_name} "${SOURCES}" "${TEST_SOURCES}")
209
+ endif()
210
+
211
+ set(_component_dir ${CMAKE_CURRENT_LIST_DIR})
212
+ set(_component_doc_dir ${_component_dir}/doc)
213
+ set(_component_doc_file ${_component_doc_dir}/index.rst)
214
+ set(_component_test_junit_xml ${CMAKE_CURRENT_BINARY_DIR}/junit.xml)
215
+ set(_component_coverage_json ${CMAKE_CURRENT_BINARY_DIR}/coverage.json)
216
+ set(_component_docs_out_dir ${CMAKE_CURRENT_BINARY_DIR}/docs)
217
+ set(_component_reports_out_dir ${CMAKE_CURRENT_BINARY_DIR}/reports)
218
+
219
+ # The Sphinx source directory is ALWAYS the project root
220
+ set(_sphinx_source_dir ${PROJECT_SOURCE_DIR})
221
+
222
+ # Create component docs target if there is an index.rst file in the component's doc directory
223
+ if(EXISTS ${_component_doc_file})
224
+ file(RELATIVE_PATH _rel_component_docs_out_dir ${_sphinx_source_dir} ${_component_docs_out_dir})
225
+ string(JSON _component_info SET "${_component_info}" docs_output_dir "\"${_rel_component_docs_out_dir}\"")
226
+ string(JSON _component_info SET "${_component_info}" has_docs "\"True\"")
227
+ set(_component_docs_html_out_dir ${_component_docs_out_dir}/html)
228
+
229
+ # create the config.json file. This is exported as SPHINX_BUILD_CONFIGURATION_FILE env variable
230
+ set(_docs_config_json ${_component_docs_out_dir}/config.json)
231
+ file(RELATIVE_PATH _rel_component_doc_dir ${_sphinx_source_dir} ${_component_doc_dir})
232
+ file(WRITE ${_docs_config_json} "{
233
+ \"component_info\": ${_component_info},
234
+ \"include_patterns\": [\"${_rel_component_doc_dir}/**\",\"${_rel_component_docs_out_dir}/**\"]
235
+ }")
236
+
237
+ # add the generated files as dependency to cmake configure step
238
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${_docs_config_json})
239
+ add_custom_target(
240
+ ${component_name}_docs
241
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${_component_docs_out_dir}
242
+
243
+ # We do not know all dependencies for generating the docs (apart from the rst files).
244
+ # This might cause incremental builds to not update parts of the documentation.
245
+ # To avoid this we are using the -E option to make sphinx-build writing all files new.
246
+ COMMAND ${CMAKE_COMMAND} -E env SPHINX_BUILD_CONFIGURATION_FILE=${_docs_config_json} AUTOCONF_JSON_FILE=${AUTOCONF_JSON} VARIANT=${VARIANT} -- sphinx-build -E -b html ${_sphinx_source_dir} ${_component_docs_html_out_dir}
247
+ BYPRODUCTS ${_component_docs_html_out_dir}/index.html
248
+ )
249
+
250
+ if(TEST_SOURCES)
251
+ file(RELATIVE_PATH _rel_component_reports_out_dir ${_sphinx_source_dir} ${_component_reports_out_dir})
252
+ string(JSON _component_info SET "${_component_info}" reports_output_dir "\"${_rel_component_reports_out_dir}\"")
253
+ string(JSON _component_info SET "${_component_info}" has_reports "\"True\"")
254
+ set(_component_reports_html_out_dir ${_component_reports_out_dir}/html)
255
+
256
+ # create the config.json file. This is exported as SPHINX_BUILD_CONFIGURATION_FILE env variable
257
+ set(_reports_config_json ${_component_reports_out_dir}/config.json)
258
+
259
+ # create the test specification rst file
260
+ set(_unit_test_spec_rst ${_component_reports_out_dir}/unit_test_spec.rst)
261
+ file(WRITE ${_unit_test_spec_rst} "
262
+ Unit Test Specification
263
+ =======================
264
+
265
+ .. needtable::
266
+ :filter: type == 'test'
267
+ :columns: id, title, tests, results
268
+ :style: table
269
+
270
+ ")
271
+
272
+ # create the test results rst file
273
+ set(_unit_test_results_rst ${_component_reports_out_dir}/unit_test_results.rst)
274
+ file(WRITE ${_unit_test_results_rst} "
275
+ Unit Test Results
276
+ =================
277
+
278
+ .. test-report:: Unit Test Results
279
+ :id: TEST_RESULT_${component_name}
280
+ :file: ${_component_test_junit_xml}
281
+
282
+ ")
283
+
284
+ # create coverate rst file to be able to automatically link to the coverage/index.html
285
+ set(_coverage_rst ${_component_reports_out_dir}/coverage.rst)
286
+ file(WRITE ${_coverage_rst} "
287
+ Code Coverage
288
+ =============
289
+
290
+ `Report <coverage/index.html>`_
291
+
292
+ ")
293
+
294
+ # generate Doxyfile from template
295
+ set(_component_doxyfile ${_component_reports_out_dir}/Doxyfile)
296
+ set(DOXYGEN_PROJECT_NAME "${CREATE_COMPONENT_LONG_NAME} Documentation")
297
+ set(DOXYGEN_OUTPUT_DIRECTORY ${_component_reports_out_dir}/doxygen)
298
+ set(DOXYGEN_INPUT "${_component_dir}/src ${_component_dir}/test ${KCONFIG_OUT_DIR}")
299
+
300
+ # We need to add the googletest include directory to the doxygen include path
301
+ # to be able to resolve the TEST() macros in the test files.
302
+ set(DOXYGEN_INCLUDE_PATH "${_sphinx_source_dir}/build/modules/googletest-src/googletest/include ${KCONFIG_OUT_DIR}")
303
+ set(DOXYGEN_AWESOME_PATH "${_sphinx_source_dir}/doc/doxygen-awesome")
304
+ configure_file(${_sphinx_source_dir}/doc/Doxyfile.in ${_component_doxyfile} @ONLY)
305
+ file(RELATIVE_PATH _rel_component_doxyfile ${CMAKE_CURRENT_BINARY_DIR} ${_component_doxyfile})
306
+ file(RELATIVE_PATH _rel_component_doxysphinx_index_rst ${_sphinx_source_dir} ${DOXYGEN_OUTPUT_DIRECTORY}/html/index)
307
+
308
+ file(WRITE ${_reports_config_json} "{
309
+ \"component_info\": ${_component_info},
310
+ \"include_patterns\": [\"${_rel_component_doc_dir}/**\",\"${_rel_component_reports_out_dir}/**\"]
311
+ }")
312
+
313
+ # add the generated files as dependency to cmake configure step
314
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${_reports_config_json} ${_unit_test_spec_rst} ${_unit_test_results_rst} ${_component_doxyfile})
315
+
316
+ set(_cov_out_html reports/html/${_rel_component_reports_out_dir}/coverage/index.html)
317
+ file(RELATIVE_PATH _cov_out_json ${CMAKE_CURRENT_BINARY_DIR} ${_component_coverage_json})
318
+
319
+ # For the component report, one needs to generate the coverage/index.html inside the component report sphinx output directory.
320
+ # This will avoid the need to copy the coverage/** directory inside the component report sphinx output directory.
321
+ add_custom_command(
322
+ OUTPUT ${_cov_out_html}
323
+ COMMAND gcovr --root ${PROJECT_SOURCE_DIR} --add-tracefile ${_cov_out_json} --html --html-details --output ${_cov_out_html} ${GCOVR_ADDITIONAL_OPTIONS}
324
+ DEPENDS ${_cov_out_json}
325
+ COMMENT "Generating component coverage html report ${_cov_out_html} ..."
326
+ )
327
+
328
+ # We need to have a separate component doxygen generation target because it is required
329
+ # by both the component and variant reports.
330
+ add_custom_target(
331
+
332
+ # No OUTPUT is defined to force execution of this target every time
333
+ ${component_name}_doxygen
334
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${_component_reports_out_dir}
335
+ COMMAND ${CMAKE_COMMAND} -E remove_directory ${DOXYGEN_OUTPUT_DIRECTORY}
336
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${DOXYGEN_OUTPUT_DIRECTORY}
337
+ COMMAND doxygen ${_rel_component_doxyfile}
338
+ )
339
+
340
+ # No OUTPUT is defined to force execution of this target every time
341
+ # TODO: list of dependencies is not complete
342
+ add_custom_target(
343
+ ${component_name}_report
344
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${_component_reports_out_dir}
345
+ COMMAND doxysphinx build ${_sphinx_source_dir} ${_component_reports_html_out_dir} ${_rel_component_doxyfile}
346
+ COMMAND ${CMAKE_COMMAND} -E env SPHINX_BUILD_CONFIGURATION_FILE=${_reports_config_json} AUTOCONF_JSON_FILE=${AUTOCONF_JSON} VARIANT=${VARIANT} -- sphinx-build -E -b html ${_sphinx_source_dir} ${_component_reports_html_out_dir}
347
+ BYPRODUCTS ${_component_reports_html_out_dir}/index.html
348
+ DEPENDS ${TEST_OUT_JUNIT} ${component_name}_doxygen ${_cov_out_html}
349
+ )
350
+ endif(TEST_SOURCES)
351
+
352
+ # Collect all component sphinx include pattern to be used in the variant targets (docs, reports)
353
+ list(APPEND COMPONENTS_SPHINX_INCLUDE_PATTERNS "${_rel_component_doc_dir}/**" "${_rel_component_docs_out_dir}/**" "${_rel_component_reports_out_dir}/**")
354
+ set(COMPONENTS_SPHINX_INCLUDE_PATTERNS ${COMPONENTS_SPHINX_INCLUDE_PATTERNS} PARENT_SCOPE)
355
+ endif(EXISTS ${_component_doc_file})
356
+ endif(BUILD_KIT STREQUAL prod)
357
+
358
+ # Collect all component info for later usage (e.g., in an extension)
359
+ list(APPEND COMPONENTS_INFO ${_component_info})
360
+ set(COMPONENTS_INFO ${COMPONENTS_INFO} PARENT_SCOPE)
361
+ endmacro()
362
+
363
+ macro(_spl_create_docs_target)
364
+ set(_docs_out_dir ${CMAKE_CURRENT_BINARY_DIR}/docs)
365
+ set(_docs_html_out_dir ${_docs_out_dir}/html)
366
+ set(_docs_config_json ${_docs_out_dir}/config.json)
367
+
368
+ # create the config.json file. This is exported as SPHINX_BUILD_CONFIGURATION_FILE env variable
369
+ list(JOIN COMPONENTS_INFO "," _components_info_json)
370
+ set(_components_info_json "[${_components_info_json}]")
371
+ list(JOIN COMPONENTS_SPHINX_INCLUDE_PATTERNS "\",\"" _components_sphinx_include_patterns_json)
372
+ set(_components_sphinx_include_patterns_json "[\"${_components_sphinx_include_patterns_json}\"]")
373
+ file(WRITE ${_docs_config_json} "{
374
+ \"target\": \"docs\",
375
+ \"include_patterns\": ${_components_sphinx_include_patterns_json},
376
+ \"components_info\": ${_components_info_json}
377
+ }")
378
+
379
+ # add the generated files as dependency to cmake configure step
380
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${_docs_config_json})
381
+ add_custom_target(
382
+ docs
383
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${_docs_out_dir}
384
+ COMMAND ${CMAKE_COMMAND} -E env SPHINX_BUILD_CONFIGURATION_FILE=${_docs_config_json} AUTOCONF_JSON_FILE=${AUTOCONF_JSON} VARIANT=${VARIANT} -- sphinx-build -E -b html ${PROJECT_SOURCE_DIR} ${_docs_html_out_dir}
385
+ BYPRODUCTS ${_docs_html_out_dir}/index.html
386
+ )
387
+ endmacro()
388
+
389
+ macro(_spl_create_reports_target)
390
+ set(_reports_output_dir ${CMAKE_CURRENT_BINARY_DIR}/reports)
391
+ file(RELATIVE_PATH _rel_reports_output_dir ${PROJECT_SOURCE_DIR} ${_reports_output_dir})
392
+ set(_reports_html_output_dir ${_reports_output_dir}/html)
393
+
394
+ # create the config.json file. This is exported as SPHINX_BUILD_CONFIGURATION_FILE env variable
395
+ set(_reports_config_json ${_reports_output_dir}/config.json)
396
+ list(JOIN COMPONENTS_INFO "," _components_info_json)
397
+ set(_components_info_json "[${_components_info_json}]")
398
+
399
+ # Add the variant specific rst files (e.g, coverage.rst) to the include patterns
400
+ list(APPEND COMPONENTS_SPHINX_INCLUDE_PATTERNS "${_rel_reports_output_dir}/**")
401
+ list(JOIN COMPONENTS_SPHINX_INCLUDE_PATTERNS "\",\"" _components_sphinx_include_patterns_json)
402
+ set(_components_sphinx_include_patterns_json "[\"${_components_sphinx_include_patterns_json}\"]")
403
+ file(WRITE ${_reports_config_json} "{
404
+ \"target\": \"reports\",
405
+ \"include_patterns\": ${_components_sphinx_include_patterns_json},
406
+ \"reports_output_dir\": \"${_rel_reports_output_dir}\",
407
+ \"components_info\": ${_components_info_json}
408
+ }")
409
+
410
+ # create the variant code coverage rst file
411
+ set(_coverage_rst ${_reports_output_dir}/coverage.rst)
412
+ file(WRITE ${_coverage_rst} "
413
+ Code Coverage
414
+ =============
415
+
416
+ `Report <coverage/index.html>`_
417
+
418
+ ")
419
+
420
+ # For every component we need to create specific coverage and doxysphinx targets to make sure
421
+ # the output files are generated in the overall variant sphinx output directory.
422
+ # This will avoid the need to copy all the component coverage and doxygen files from the component
423
+ # directories to the variant directory.
424
+ foreach(component_info ${COMPONENTS_INFO})
425
+ string(JSON component_name GET ${component_info} name)
426
+ string(JSON component_path GET ${component_info} path)
427
+ string(JSON component_reports_output_dir GET ${component_info} reports_output_dir)
428
+
429
+ if(component_reports_output_dir)
430
+ set(_variant_component_reports_out_dir reports/html/${component_reports_output_dir})
431
+ set(_cov_out_html ${_variant_component_reports_out_dir}/coverage/index.html)
432
+ set(_cov_out_json ${component_path}/coverage.json)
433
+ add_custom_command(
434
+ OUTPUT ${_cov_out_html}
435
+ COMMAND gcovr --root ${PROJECT_SOURCE_DIR} --add-tracefile ${_cov_out_json} --html --html-details --output ${_cov_out_html} ${GCOVR_ADDITIONAL_OPTIONS}
436
+ DEPENDS ${_cov_out_json}
437
+ COMMENT "Generating variant component coverage html report ${_cov_out_html} ..."
438
+ )
439
+ list(APPEND _components_coverage_html ${_cov_out_html})
440
+
441
+ set(_rel_component_doxyfile ${component_path}/reports/Doxyfile)
442
+ add_custom_target(
443
+ ${component_name}_doxysphinx
444
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${_variant_component_reports_out_dir}
445
+ COMMAND doxysphinx build ${PROJECT_SOURCE_DIR} ${_reports_html_output_dir} ${_rel_component_doxyfile}
446
+ DEPENDS ${component_name}_doxygen
447
+ COMMENT "Generating variant component doxysphinx report ${component_name}_doxysphinx ..."
448
+ )
449
+ list(APPEND _components_variant_doxysphinx_targets ${component_name}_doxysphinx)
450
+ endif()
451
+ endforeach()
452
+
453
+ set(_cov_out_variant_html reports/html/${_rel_reports_output_dir}/coverage/index.html)
454
+ add_custom_command(
455
+ OUTPUT ${_cov_out_variant_html}
456
+ COMMAND gcovr --root ${CMAKE_SOURCE_DIR} --add-tracefile \"${CMAKE_CURRENT_BINARY_DIR}/**/${COV_OUT_JSON}\" --html --html-details --output ${_cov_out_variant_html}
457
+ DEPENDS ${GLOBAL_COMPONENTS_COVERAGE_JSON_LIST}
458
+ COMMENT "Generating overall code coverage report ${_cov_out_variant_html} ..."
459
+ )
460
+
461
+ add_custom_target(
462
+ _components_variant_coverage_html_target
463
+ DEPENDS ${_components_coverage_html} ${_cov_out_variant_html}
464
+ )
465
+
466
+ # add the generated files as dependency to cmake configure step
467
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${_reports_config_json})
468
+ add_custom_target(
469
+ reports
470
+ ALL
471
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${_reports_output_dir}
472
+
473
+ # We need to call sphinx-build with -E to make sure all files are regenerated.
474
+ COMMAND ${CMAKE_COMMAND} -E env SPHINX_BUILD_CONFIGURATION_FILE=${_reports_config_json} AUTOCONF_JSON_FILE=${AUTOCONF_JSON} VARIANT=${VARIANT} -- sphinx-build -E -b html ${PROJECT_SOURCE_DIR} ${_reports_html_output_dir}
475
+ BYPRODUCTS ${_reports_html_output_dir}/index.html
476
+ DEPENDS _components_variant_coverage_html_target ${_components_variant_doxysphinx_targets}
477
+ )
478
+ endmacro()
479
+
480
+ macro(_spl_set_coverage_create_overall_report_is_necessary)
481
+ set(_SPL_COVERAGE_CREATE_OVERALL_REPORT_IS_NECESSARY TRUE PARENT_SCOPE)
482
+ endmacro(_spl_set_coverage_create_overall_report_is_necessary)
483
+
484
+ set(COV_OUT_JSON coverage.json)
485
+
486
+ function(_spl_coverage_create_overall_report)
487
+ if(_SPL_COVERAGE_CREATE_OVERALL_REPORT_IS_NECESSARY)
488
+ set(COV_OUT_VARIANT_HTML reports/coverage/index.html)
489
+ add_custom_command(
490
+ OUTPUT ${COV_OUT_VARIANT_HTML}
491
+ COMMAND gcovr --root ${CMAKE_SOURCE_DIR} --add-tracefile \"${CMAKE_CURRENT_BINARY_DIR}/**/${COV_OUT_JSON}\" --html --html-details --output ${COV_OUT_VARIANT_HTML}
492
+ DEPENDS ${GLOBAL_COMPONENTS_COVERAGE_JSON_LIST}
493
+ COMMENT "Generating overall code coverage report ${COV_OUT_VARIANT_HTML} ..."
494
+ )
495
+ add_custom_target(
496
+ unittests
497
+ DEPENDS coverage ${COV_OUT_VARIANT_HTML}
498
+ )
499
+ add_custom_target(
500
+ coverage_overall_report
501
+ DEPENDS ${COV_OUT_VARIANT_HTML}
502
+ )
503
+ else(_SPL_COVERAGE_CREATE_OVERALL_REPORT_IS_NECESSARY)
504
+ add_custom_target(unittests)
505
+ endif(_SPL_COVERAGE_CREATE_OVERALL_REPORT_IS_NECESSARY)
506
+ endfunction(_spl_coverage_create_overall_report)
507
+
508
+ macro(_spl_add_test_suite COMPONENT_NAME PROD_SRC TEST_SOURCES)
509
+ _spl_set_coverage_create_overall_report_is_necessary()
510
+
511
+ set(exe_name ${COMPONENT_NAME}_test)
512
+ set(PROD_PARTIAL_LINK prod_partial_${COMPONENT_NAME}.obj)
513
+ set(MOCK_SRC mockup_${COMPONENT_NAME}.cc)
514
+
515
+ add_executable(${exe_name}
516
+ ${TEST_SOURCES}
517
+ ${MOCK_SRC}
518
+ )
519
+
520
+ # Create the component library
521
+ add_library(${COMPONENT_NAME} OBJECT ${SOURCES})
522
+
523
+ # Define list of test specific compile options for all sources
524
+ # -ggdb: Produce debugging information to be able to set breakpoints.
525
+ # -save-temps: save temporary files like preprocessed ones for debugging purposes
526
+ set(TEST_COMPILE_OPTIONS -ggdb -save-temps)
527
+
528
+ target_compile_options(${exe_name} PRIVATE ${TEST_COMPILE_OPTIONS})
529
+
530
+ # Coverage data is only generated for the component's sources
531
+ target_compile_options(${COMPONENT_NAME} PRIVATE --coverage ${TEST_COMPILE_OPTIONS})
532
+
533
+ # Define list of test specific compile options for all sources
534
+ # SPLE_UNIT_TESTING: add possibility to configure the code for unit testing
535
+ # SPLE_TESTABLE_STATIC=: add possibility to make static functions testable and mockable
536
+ # SPLE_TESTABLE_INLINE=: add possibility to make inline functions testable and mockable
537
+ # static_scope_file=: add possibility to remove static from the signature (obsolete, use SPLE_TESTABLE_STATIC instead)
538
+ set(TEST_COMPILE_DEFINITIONS
539
+ SPLE_UNIT_TESTING
540
+ SPLE_TESTABLE_STATIC=
541
+ SPLE_TESTABLE_INLINE=
542
+ static_scope_file=
543
+ )
544
+
545
+ target_compile_definitions(${exe_name} PRIVATE ${TEST_COMPILE_DEFINITIONS})
546
+
547
+ target_compile_definitions(${COMPONENT_NAME} PRIVATE ${TEST_COMPILE_DEFINITIONS})
548
+
549
+ target_link_options(${exe_name}
550
+ PRIVATE -ggdb --coverage
551
+ )
552
+
553
+ add_custom_command(
554
+ OUTPUT ${PROD_PARTIAL_LINK}
555
+ COMMAND ${CMAKE_CXX_COMPILER} -r -nostdlib -o ${PROD_PARTIAL_LINK} $<TARGET_OBJECTS:${COMPONENT_NAME}>
556
+ COMMAND_EXPAND_LISTS
557
+ VERBATIM
558
+ DEPENDS $<TARGET_OBJECTS:${COMPONENT_NAME}>
559
+ )
560
+
561
+ set(component_inc_dirs "$<TARGET_PROPERTY:${COMPONENT_NAME},INCLUDE_DIRECTORIES>")
562
+ set(component_comp_defs "$<TARGET_PROPERTY:${COMPONENT_NAME},COMPILE_DEFINITIONS>")
563
+ add_custom_command(
564
+ OUTPUT ${MOCK_SRC}
565
+ BYPRODUCTS mockup_${component_name}.h
566
+ WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
567
+ COMMAND python -m hammocking --suffix _${COMPONENT_NAME} --sources ${PROD_SRC} --plink ${CMAKE_CURRENT_BINARY_DIR}/${PROD_PARTIAL_LINK} --outdir ${CMAKE_CURRENT_BINARY_DIR} "$<$<BOOL:${component_inc_dirs}>:-I$<JOIN:${component_inc_dirs},;-I>>" "$<$<BOOL:${component_comp_defs}>:-D$<JOIN:${component_comp_defs},;-D>>" -x c
568
+ COMMAND_EXPAND_LISTS
569
+ VERBATIM
570
+ DEPENDS
571
+ ${PROD_PARTIAL_LINK}
572
+ )
573
+
574
+ # Create unit test results (junit.xml)
575
+ set(TEST_OUT_JUNIT junit.xml)
576
+ add_custom_command(
577
+ OUTPUT ${TEST_OUT_JUNIT}
578
+
579
+ # Wipe all gcda files before the test executable recreates them
580
+ COMMAND python ${SPL_CORE_PYTHON_DIRECTORY}/gcov_maid/gcov_maid.py --working-dir . --wipe-all-gcda
581
+
582
+ # Run the test executable, generate JUnit report and return 0 independent of the test result
583
+ COMMAND ${CMAKE_CTEST_COMMAND} ${CMAKE_CTEST_ARGUMENTS} --output-junit ${TEST_OUT_JUNIT} || ${CMAKE_COMMAND} -E true
584
+ DEPENDS ${exe_name}
585
+ )
586
+
587
+ set(GLOBAL_COMPONENTS_COVERAGE_JSON_LIST "${GLOBAL_COMPONENTS_COVERAGE_JSON_LIST};${CMAKE_CURRENT_BINARY_DIR}/${COV_OUT_JSON}" CACHE INTERNAL "List of all ${COV_OUT_JSON} files")
588
+
589
+ # Create coverage results (coverage.json)
590
+ add_custom_command(
591
+ OUTPUT ${COV_OUT_JSON}
592
+
593
+ # Wipe orphaned gcno files before gcovr searches for them
594
+ COMMAND python ${SPL_CORE_PYTHON_DIRECTORY}/gcov_maid/gcov_maid.py --working-dir . --wipe-orphaned-gcno
595
+
596
+ # Run gcovr to generate coverage json for the component
597
+ COMMAND gcovr --root ${CMAKE_SOURCE_DIR} --json --output ${COV_OUT_JSON} ${GCOVR_ADDITIONAL_OPTIONS} ${CMAKE_CURRENT_BINARY_DIR}
598
+ DEPENDS ${TEST_OUT_JUNIT}
599
+ COMMENT "Generating component ${COMPONENT_NAME} code coverage json report ${COV_OUT_JSON} ..."
600
+ )
601
+
602
+ # Create coverage html report
603
+ set(COV_OUT_HTML reports/coverage/index.html)
604
+ add_custom_command(
605
+ OUTPUT ${COV_OUT_HTML}
606
+ COMMAND gcovr --root ${CMAKE_SOURCE_DIR} --add-tracefile ${COV_OUT_JSON} --html --html-details --output ${COV_OUT_HTML} ${GCOVR_ADDITIONAL_OPTIONS}
607
+ DEPENDS ${COV_OUT_JSON}
608
+ COMMENT "Generating component ${COMPONENT_NAME} code coverage html report ${COV_OUT_HTML} ..."
609
+ )
610
+
611
+ add_custom_target(
612
+ ${COMPONENT_NAME}_coverage
613
+ DEPENDS ${COV_OUT_HTML}
614
+ )
615
+ add_custom_target(
616
+ ${COMPONENT_NAME}_unittests
617
+ DEPENDS ${COMPONENT_NAME}_coverage
618
+ )
619
+ add_dependencies(coverage ${COMPONENT_NAME}_coverage)
620
+
621
+ target_link_libraries(${exe_name}
622
+ ${COMPONENT_NAME}
623
+ GTest::gtest_main
624
+ GTest::gmock_main
625
+ pthread
626
+ )
627
+
628
+ gtest_discover_tests(${exe_name})
629
+ endmacro()
630
+
631
+ macro(spl_add_conan_requires requirement)
632
+ list(APPEND CONAN__REQUIRES ${requirement})
633
+ endmacro(spl_add_conan_requires)
634
+
635
+ macro(spl_add_conan_build_requires requirement)
636
+ list(APPEND CONAN__BUILD_REQUIRES ${requirement})
637
+ endmacro(spl_add_conan_build_requires)
638
+
639
+ macro(spl_add_conan_install_settings settings)
640
+ list(APPEND CONAN_INSTALL_SETTINGS ${settings})
641
+ endmacro(spl_add_conan_install_settings)
642
+
643
+ macro(spl_run_conan)
644
+ if(CONAN__BUILD_REQUIRES OR CONAN__REQUIRES)
645
+ # This is the wrapper-code
646
+ include(${SPL_CORE_CMAKE_DIRECTORY}/conan.cmake)
647
+
648
+ # This replaces file conanfile.txt
649
+ conan_cmake_configure(
650
+ BUILD_REQUIRES
651
+ ${CONAN__BUILD_REQUIRES}
652
+ REQUIRES
653
+ ${CONAN__REQUIRES}
654
+ GENERATORS
655
+ cmake_paths
656
+ virtualrunenv
657
+ )
658
+
659
+ # This clones a special conan config when required
660
+ if(DEFINED SPL_CONAN_CONFIG_URL)
661
+ if(DEFINED SPL_CONAN_CONFIG_VERIFY_SSL)
662
+ conan_config_install(
663
+ ITEM ${SPL_CONAN_CONFIG_URL}
664
+ VERIFY_SSL ${SPL_CONAN_CONFIG_VERIFY_SSL}
665
+ )
666
+ else()
667
+ conan_config_install(
668
+ ITEM ${SPL_CONAN_CONFIG_URL}
669
+ )
670
+ endif()
671
+ endif()
672
+
673
+ # This replaces the call of command "conan install" on the command line
674
+ conan_cmake_install(
675
+ PATH_OR_REFERENCE .
676
+ SETTINGS
677
+ ${CONAN_INSTALL_SETTINGS}
678
+ )
679
+ include(${CMAKE_BINARY_DIR}/conan_paths.cmake)
680
+
681
+ # This is the ninja hack to get paths of conan packages
682
+ _spl_set_ninja_wrapper_as_cmake_make()
683
+ endif()
684
+ endmacro(spl_run_conan)
685
+
686
+ macro(_spl_set_ninja_wrapper_as_cmake_make)
687
+ set(NINJA_WRAPPER ${CMAKE_SOURCE_DIR}/build/${VARIANT}/${BUILD_KIT}/ninja_wrapper.bat)
688
+ file(WRITE ${NINJA_WRAPPER}
689
+ "@echo off
690
+ @call %~dp0%/activate_run.bat
691
+ @ninja %*
692
+ @call %~dp0%/deactivate_run.bat")
693
+ set(CMAKE_MAKE_PROGRAM ${NINJA_WRAPPER} CACHE FILEPATH "Custom ninja wrapper to activate the Conan virtual environment" FORCE)
694
+ endmacro()
695
+
696
+ # deprecated
697
+ macro(add_include)
698
+ spl_add_include(${ARGN})
699
+ endmacro()
700
+
701
+ # deprecated
702
+ macro(add_source)
703
+ spl_add_source(${ARGN})
704
+ endmacro()
705
+
706
+ # deprecated
707
+ macro(create_component)
708
+ spl_create_component(${ARGN})
709
+ endmacro()
710
+
711
+ macro(_spl_create_build_info_file)
712
+ # create empty build.json file
713
+ set(build_info_file ${CMAKE_CURRENT_BINARY_DIR}/build.json)
714
+
715
+ # create preformatted JSON strings for each component
716
+ # Whitespaces are needed for beautified JSON output
717
+ list(JOIN build_info ",\n " formatted_json_build_info)
718
+
719
+ # add the components to the build.json file
720
+ file(WRITE ${build_info_file} "{
721
+ \"components\":[
722
+ ${formatted_json_build_info}
723
+ ]
724
+ }")
725
+ endmacro()