@@ -18,6 +18,83 @@ include("${CPP_LIBRARY_ROOT}/cmake/cpp-library-docs.cmake")
1818include ("${CPP_LIBRARY_ROOT} /cmake/cpp-library-presets.cmake" )
1919include ("${CPP_LIBRARY_ROOT} /cmake/cpp-library-ci.cmake" )
2020
21+ # Shared function to handle examples and tests consistently
22+ function (_cpp_library_setup_executables)
23+ set (oneValueArgs
24+ NAME
25+ NAMESPACE
26+ TYPE
27+ )
28+ set (multiValueArgs
29+ EXECUTABLES
30+ )
31+
32+ cmake_parse_arguments (ARG "" "${oneValueArgs} " "${multiValueArgs} " ${ARGN} )
33+
34+ # Extract the clean library name for linking
35+ string (REPLACE "${ARG_NAMESPACE} -" "" CLEAN_NAME "${ARG_NAME} " )
36+
37+ # Download doctest dependency via CPM
38+ if (NOT TARGET doctest::doctest)
39+ CPMAddPackage(
"gh:doctest/[email protected] " )
40+ endif ()
41+
42+ # Determine source directory based on type
43+ if (ARG_TYPE STREQUAL "examples" )
44+ set (source_dir "examples" )
45+ elseif (ARG_TYPE STREQUAL "tests" )
46+ set (source_dir "tests" )
47+ else ()
48+ message (FATAL_ERROR "_cpp_library_setup_executables: TYPE must be 'examples' or 'tests'" )
49+ endif ()
50+
51+ # Add executables
52+ foreach (executable IN LISTS ARG_EXECUTABLES)
53+ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR} /${source_dir} /${executable} .cpp" )
54+
55+ # Check if this is a compile-fail test (has "_fail" in the name)
56+ string (FIND "${executable} " "_fail" fail_pos)
57+ if (fail_pos GREATER -1)
58+ # Negative compile test: this executable must fail to compile
59+ add_executable (${executable} EXCLUDE_FROM_ALL "${source_dir} /${executable} .cpp" )
60+ target_link_libraries (${executable} PRIVATE ${ARG_NAMESPACE} ::${CLEAN_NAME} )
61+ add_test (
62+ NAME compile_${executable}
63+ COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ${executable}
64+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
65+ )
66+ set_tests_properties (compile_${executable} PROPERTIES WILL_FAIL TRUE )
67+ else ()
68+ # Regular executable - conditionally build based on preset
69+ add_executable (${executable} "${source_dir} /${executable} .cpp" )
70+ target_link_libraries (${executable} PRIVATE ${ARG_NAMESPACE} ::${CLEAN_NAME} doctest::doctest)
71+
72+ # Only fully build (compile and link) in test preset
73+ # In clang-tidy preset, compile with clang-tidy but don't link
74+ if (CMAKE_CXX_CLANG_TIDY)
75+ # In clang-tidy mode, exclude from all builds but still compile
76+ set_target_properties (${executable} PROPERTIES EXCLUDE_FROM_ALL TRUE )
77+ # Don't add as a test in clang-tidy mode since we're not linking
78+ else ()
79+ # In test mode, build normally and add as test
80+ add_test (NAME ${executable} COMMAND ${executable} )
81+
82+ # Set test properties for better IDE integration (only for tests)
83+ if (ARG_TYPE STREQUAL "tests" )
84+ set_tests_properties (${executable} PROPERTIES
85+ LABELS "doctest"
86+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
87+ )
88+ endif ()
89+ endif ()
90+ endif ()
91+ else ()
92+ message (WARNING "${ARG_TYPE} file ${source_dir} /${executable} .cpp not found" )
93+ endif ()
94+ endforeach ()
95+
96+ endfunction ()
97+
2198# Main entry point function - users call this to set up their library
2299function (cpp_library_setup)
23100 # Parse arguments
@@ -73,7 +150,8 @@ function(cpp_library_setup)
73150 if (NOT DEFINED ARG_FORCE_INIT)
74151 set (ARG_FORCE_INIT FALSE )
75152 endif ()
76- if (CPP_LIBRARY_FORCE_INIT)
153+
154+ if (DEFINED CPP_LIBRARY_FORCE_INIT AND CPP_LIBRARY_FORCE_INIT)
77155 set (ARG_FORCE_INIT TRUE )
78156 endif ()
79157
@@ -116,8 +194,8 @@ function(cpp_library_setup)
116194 return () # Early return for lightweight consumer mode
117195 endif ()
118196
119- # Create symlink to compile_commands.json for clangd
120- if (CMAKE_EXPORT_COMPILE_COMMANDS)
197+ # Create symlink to compile_commands.json for clangd (only when BUILD_TESTING is enabled)
198+ if (CMAKE_EXPORT_COMPILE_COMMANDS AND BUILD_TESTING )
121199 add_custom_target (clangd_compile_commands ALL
122200 COMMAND ${CMAKE_COMMAND} -E create_symlink
123201 ${CMAKE_BINARY_DIR} /compile_commands.json
@@ -127,17 +205,26 @@ function(cpp_library_setup)
127205 endif ()
128206
129207 # Generate CMakePresets.json
130- _cpp_library_generate_presets(FORCE_INIT ${ARG_FORCE_INIT} )
208+ if (ARG_FORCE_INIT)
209+ _cpp_library_generate_presets(FORCE_INIT)
210+ else ()
211+ _cpp_library_generate_presets()
212+ endif ()
131213
132214 # Copy static template files (like .clang-format, .gitignore, etc.)
133- _cpp_library_copy_templates(FORCE_INIT ${ARG_FORCE_INIT} )
215+ if (ARG_FORCE_INIT)
216+ _cpp_library_copy_templates(FORCE_INIT)
217+ else ()
218+ _cpp_library_copy_templates()
219+ endif ()
134220
135221 # Setup testing (if tests are specified)
136222 if (BUILD_TESTING AND ARG_TESTS)
137- _cpp_library_setup_testing (
223+ _cpp_library_setup_executables (
138224 NAME "${ARG_NAME} "
139225 NAMESPACE "${ARG_NAMESPACE} "
140- TESTS "${ARG_TESTS} "
226+ TYPE "tests"
227+ EXECUTABLES "${ARG_TESTS} "
141228 )
142229 endif ()
143230
@@ -152,41 +239,29 @@ function(cpp_library_setup)
152239 endif ()
153240
154241 # Setup CI
155- _cpp_library_setup_ci(
156- NAME "${ARG_NAME} "
157- VERSION "${ARG_VERSION} "
158- DESCRIPTION "${ARG_DESCRIPTION} "
159- FORCE_INIT ${ARG_FORCE_INIT}
160- )
242+ if (ARG_FORCE_INIT)
243+ _cpp_library_setup_ci(
244+ NAME "${ARG_NAME} "
245+ VERSION "${ARG_VERSION} "
246+ DESCRIPTION "${ARG_DESCRIPTION} "
247+ FORCE_INIT
248+ )
249+ else ()
250+ _cpp_library_setup_ci(
251+ NAME "${ARG_NAME} "
252+ VERSION "${ARG_VERSION} "
253+ DESCRIPTION "${ARG_DESCRIPTION} "
254+ )
255+ endif ()
161256
162- # Build examples if specified
163- if (ARG_EXAMPLES)
164- foreach (example IN LISTS ARG_EXAMPLES)
165- if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR} /examples/${example} .cpp" )
166- string (REPLACE "${ARG_NAMESPACE} -" "" CLEAN_NAME "${ARG_NAME} " )
167-
168- # Check if this is a compile-fail test (has "_fail" in the name)
169- string (FIND "${example} " "_fail" fail_pos)
170- if (fail_pos GREATER -1)
171- # Negative compile test: this example must fail to compile
172- add_executable (${example} EXCLUDE_FROM_ALL "examples/${example} .cpp" )
173- target_link_libraries (${example} PRIVATE ${ARG_NAMESPACE} ::${CLEAN_NAME} )
174- add_test (
175- NAME compile_${example}
176- COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ${example}
177- WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
178- )
179- set_tests_properties (compile_${example} PROPERTIES WILL_FAIL TRUE )
180- else ()
181- # Regular example
182- add_executable (${example} "examples/${example} .cpp" )
183- target_link_libraries (${example} PRIVATE ${ARG_NAMESPACE} ::${CLEAN_NAME} )
184- add_test (NAME ${example} COMMAND ${example} )
185- endif ()
186- else ()
187- message (WARNING "Example file examples/${example} .cpp not found" )
188- endif ()
189- endforeach ()
257+ # Build examples if specified (only when BUILD_TESTING is enabled)
258+ if (BUILD_TESTING AND ARG_EXAMPLES)
259+ _cpp_library_setup_executables(
260+ NAME "${ARG_NAME} "
261+ NAMESPACE "${ARG_NAMESPACE} "
262+ TYPE "examples"
263+ EXECUTABLES "${ARG_EXAMPLES} "
264+ )
190265 endif ()
191266
192267endfunction ()
0 commit comments