# Registers book examples as real compiled targets. # # book_example(file [EXPECT "regex"]) — a runnable, fully-checked example. # Builds with the full warning set plus -Werror (when BOOK_WERROR is ON) and # clang-tidy; runs under CTest (with ASan/UBSan when BOOK_SANITIZE is ON). # If EXPECT is given, the run also must print output matching the regex. # -Werror turns every warning into a hard error so a clean example stays # clean. It applies only to book_example: demos and gaps still emit their # teaching warnings without failing the build. # # book_demo(file) — a deliberately-wrong teaching demo (dangling pointer, # ODR violation, fossil code). Compiles with warnings visible (the warning # is the exhibit), clang-tidy off, no sanitizer, no CTest run. The expected # diagnostic is pasted in a comment at the top of the file by hand. # # book_gap(file feature) — standard C++26 feature without shipping Clang # support. The target exists only with -DBOOK_ENABLE_GAPS=ON and may # legitimately fail to compile. Never built by default. # The lifetime-safety analysis flag is not stabilized: prefer -Wlifetime-safety # (Clang 23+ direction), fall back to the cc1 form -Xclang -fexperimental-lifetime-safety # (Clang 22, emits few diagnostics). Unknown -W options must not pass the probe, # hence -Werror=unknown-warning-option for the first check. include(CheckCXXCompilerFlag) include(CheckCXXSourceCompiles) set(CMAKE_REQUIRED_FLAGS "-Werror=unknown-warning-option") check_cxx_compiler_flag("-Wlifetime-safety" BOOK_HAVE_WLIFETIME_SAFETY) set(CMAKE_REQUIRED_FLAGS "-Xclang -fexperimental-lifetime-safety") check_cxx_source_compiles("int main() { return 0; }" BOOK_HAVE_EXPERIMENTAL_LIFETIME) unset(CMAKE_REQUIRED_FLAGS) if(BOOK_HAVE_WLIFETIME_SAFETY) set(BOOK_LIFETIME_FLAG "-Wlifetime-safety") elseif(BOOK_HAVE_EXPERIMENTAL_LIFETIME) set(BOOK_LIFETIME_FLAG "-Xclang;-fexperimental-lifetime-safety") message(STATUS "lifetime-safety analysis: experimental cc1 form (Clang 22)") else() message(WARNING "this compiler has no lifetime-safety analysis; the committee is incomplete") set(BOOK_LIFETIME_FLAG "") endif() set(BOOK_WARNING_FLAGS -Wall -Wextra -Wpedantic -Wconversion -Wshadow ${BOOK_LIFETIME_FLAG}) function(_book_add_target out_var file) get_filename_component(name "${file}" NAME_WE) add_executable(${name} "${file}") set(${out_var} ${name} PARENT_SCOPE) endfunction() function(book_example file) cmake_parse_arguments(arg "" "EXPECT" "" ${ARGN}) _book_add_target(t "${file}") target_compile_options(${t} PRIVATE ${BOOK_WARNING_FLAGS}) if(BOOK_WERROR) target_compile_options(${t} PRIVATE -Werror) endif() if(BOOK_SANITIZE) target_compile_options(${t} PRIVATE -fsanitize=address -fsanitize=undefined) target_link_options(${t} PRIVATE -fsanitize=address -fsanitize=undefined) endif() add_test(NAME ${t}_run COMMAND ${t}) if(arg_EXPECT) set_tests_properties(${t}_run PROPERTIES PASS_REGULAR_EXPRESSION "${arg_EXPECT}") endif() endfunction() function(book_demo file) _book_add_target(t "${file}") target_compile_options(${t} PRIVATE ${BOOK_WARNING_FLAGS}) set_target_properties(${t} PROPERTIES CXX_CLANG_TIDY "") endfunction() function(book_gap file feature) if(BOOK_ENABLE_GAPS) message(STATUS "gap example enabled: ${file} (feature: ${feature})") _book_add_target(t "${file}") target_compile_options(${t} PRIVATE ${BOOK_WARNING_FLAGS}) set_target_properties(${t} PROPERTIES CXX_CLANG_TIDY "") endif() endfunction() # book_compile_error(file expected_regex) — verifies that a file fails to # compile and that the compiler diagnostic matches expected_regex. This is a # configure-time check via try_compile, so it runs once per configure, not # as a build target. If the file unexpectedly compiles, or the expected # diagnostic is missing, configure fails with a FATAL_ERROR. function(book_compile_error file expected_regex) get_filename_component(name "${file}" NAME_WE) set(bindir "${CMAKE_CURRENT_BINARY_DIR}/compile_error_${name}") file(MAKE_DIRECTORY "${bindir}") try_compile( BOOK_COMPILE_ERROR_${name} "${bindir}" "${CMAKE_CURRENT_SOURCE_DIR}/${file}" OUTPUT_VARIABLE BOOK_COMPILE_ERROR_OUTPUT CXX_STANDARD 26 CXX_STANDARD_REQUIRED ON ) if(BOOK_COMPILE_ERROR_${name}) message(FATAL_ERROR "book_compile_error: ${file} unexpectedly compiled; expected it to fail") endif() if(NOT BOOK_COMPILE_ERROR_OUTPUT MATCHES "${expected_regex}") message(FATAL_ERROR "book_compile_error: ${file} failed to compile but the diagnostic did " "not match '${expected_regex}'. Actual output:\n${BOOK_COMPILE_ERROR_OUTPUT}") endif() message(STATUS "compile error verified: ${file} (matches '${expected_regex}')") endfunction()