From d07ba0c70f6ac89dbdd6e32a6d43aa045a4f3a6d Mon Sep 17 00:00:00 2001 From: Rafi Indra Pramudhito Zuhayr Date: Tue, 15 Sep 2026 09:17:10 +0700 Subject: [PATCH 1/5] build: modularize project configuration --- CMakeLists.txt | 71 ++++++++++++---------------- cmake/modules/optimizations.cmake | 30 ++++++++++++ cmake/modules/options.cmake | 39 +++++++++++++++ cmake/modules/project-settings.cmake | 33 +++++++++++++ cmake/modules/sanitizers.cmake | 25 ++++++++++ cmake/modules/warnings.cmake | 30 ++++++++++++ 6 files changed, 187 insertions(+), 41 deletions(-) create mode 100644 cmake/modules/optimizations.cmake create mode 100644 cmake/modules/options.cmake create mode 100644 cmake/modules/project-settings.cmake create mode 100644 cmake/modules/sanitizers.cmake create mode 100644 cmake/modules/warnings.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 6be50b9..1026724 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,59 +1,48 @@ -cmake_minimum_required(VERSION 3.20) +cmake_minimum_required(VERSION 3.21) + project( cpp_request + VERSION 0.9.0 DESCRIPTION "A lightweight synchronous C++17 HTTP/1.1 client built on native sockets" - VERSION 0.1.0 - LANGUAGES CXX C + LANGUAGES CXX ) -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules") -option(CPP_REQUEST_BUILD_BENCHMARKS "Build cpp_request benchmarks" OFF) +include(options) +include(project-settings) -include(CTest) -include(GNUInstallDirs) -include(CMakePackageConfigHelpers) -include(cmake/modules/output.cmake) -include(cmake/modules/warning.cmake) -include(cmake/modules/sanitizing.cmake) -include(cmake/modules/optimizing.cmake) +cpp_request_setup_options() +cpp_request_setup_project() add_subdirectory(src) -if(BUILD_TESTING) + +if(CPP_REQUEST_BUILD_TESTS) + include(testing) add_subdirectory(tests) endif() + if(CPP_REQUEST_BUILD_BENCHMARKS) + include(benchmarking) add_subdirectory(benchmarks) endif() -add_subdirectory(examples) -set(CPP_REQUEST_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/cpp_request") - -configure_package_config_file( - ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cpp_requestConfig.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/cpp_requestConfig.cmake - INSTALL_DESTINATION ${CPP_REQUEST_INSTALL_CMAKEDIR} -) +if(CPP_REQUEST_BUILD_EXAMPLES) + include(examples) + add_subdirectory(examples) +endif() -write_basic_package_version_file( - ${CMAKE_CURRENT_BINARY_DIR}/cpp_requestConfigVersion.cmake - VERSION ${PROJECT_VERSION} - COMPATIBILITY SameMinorVersion -) +if(CPP_REQUEST_ENABLE_INSTALL) + include(install) + cpp_request_configure_install() +endif() -install( - EXPORT cpp_requestTargets - FILE cpp_requestTargets.cmake - NAMESPACE cpp_request:: - DESTINATION ${CPP_REQUEST_INSTALL_CMAKEDIR} -) +if(PROJECT_IS_TOP_LEVEL AND CPP_REQUEST_ENABLE_CLANG_FORMAT) + include("${PROJECT_SOURCE_DIR}/cmake/tools/clang-format.cmake") + cpp_request_add_clang_format_targets() +endif() -install( - FILES - ${CMAKE_CURRENT_BINARY_DIR}/cpp_requestConfig.cmake - ${CMAKE_CURRENT_BINARY_DIR}/cpp_requestConfigVersion.cmake - DESTINATION ${CPP_REQUEST_INSTALL_CMAKEDIR} -) +if(PROJECT_IS_TOP_LEVEL AND CPP_REQUEST_ENABLE_DOXYGEN) + include("${PROJECT_SOURCE_DIR}/cmake/tools/doxygen.cmake") + cpp_request_add_doxygen_target(cpp_request_docs) +endif() diff --git a/cmake/modules/optimizations.cmake b/cmake/modules/optimizations.cmake new file mode 100644 index 0000000..5c347b1 --- /dev/null +++ b/cmake/modules/optimizations.cmake @@ -0,0 +1,30 @@ +include_guard(GLOBAL) + +function(cpp_request_apply_optimizations target) + if(CPP_REQUEST_ENABLE_NATIVE_OPTIMIZATION) + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") + target_compile_options(${target} + PRIVATE + $<$:-march=native> + $<$:-mtune=native> + ) + else() + message(WARNING + "CPP_REQUEST_ENABLE_NATIVE_OPTIMIZATION currently supports Clang and GCC only" + ) + endif() + endif() + + if(CPP_REQUEST_ENABLE_IPO) + include(CheckIPOSupported) + check_ipo_supported(RESULT _cpp_request_ipo_supported OUTPUT _cpp_request_ipo_error) + if(_cpp_request_ipo_supported) + set_property( + TARGET ${target} + PROPERTY INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE + ) + else() + message(WARNING "IPO is unavailable: ${_cpp_request_ipo_error}") + endif() + endif() +endfunction() diff --git a/cmake/modules/options.cmake b/cmake/modules/options.cmake new file mode 100644 index 0000000..6e22336 --- /dev/null +++ b/cmake/modules/options.cmake @@ -0,0 +1,39 @@ +include_guard(GLOBAL) + +function(cpp_request_setup_options) + set(_cpp_request_top_level_default OFF) + if(PROJECT_IS_TOP_LEVEL) + set(_cpp_request_top_level_default ON) + endif() + + option( + CPP_REQUEST_BUILD_TESTS + "Build cpp_request tests" + ${_cpp_request_top_level_default} + ) + option( + CPP_REQUEST_BUILD_BENCHMARKS + "Build cpp_request benchmarks" + OFF + ) + option( + CPP_REQUEST_BUILD_EXAMPLES + "Build cpp_request examples" + ${_cpp_request_top_level_default} + ) + option( + CPP_REQUEST_ENABLE_INSTALL + "Enable cpp_request install and package export rules" + ${_cpp_request_top_level_default} + ) + + option(CPP_REQUEST_ENABLE_WARNINGS "Enable compiler warnings" ON) + option(CPP_REQUEST_WARNINGS_AS_ERRORS "Treat compiler warnings as errors" OFF) + option(CPP_REQUEST_ENABLE_SANITIZERS "Enable AddressSanitizer and UndefinedBehaviorSanitizer" OFF) + option(CPP_REQUEST_ENABLE_IPO "Enable interprocedural optimization for Release builds" OFF) + option(CPP_REQUEST_ENABLE_NATIVE_OPTIMIZATION "Enable host-specific optimization for local Release builds" OFF) + + option(CPP_REQUEST_ENABLE_CLANG_TIDY "Enable clang-tidy for cpp_request targets" OFF) + option(CPP_REQUEST_ENABLE_CLANG_FORMAT "Add clang-format helper targets" OFF) + option(CPP_REQUEST_ENABLE_DOXYGEN "Add the Doxygen documentation target" OFF) +endfunction() diff --git a/cmake/modules/project-settings.cmake b/cmake/modules/project-settings.cmake new file mode 100644 index 0000000..af8a3e7 --- /dev/null +++ b/cmake/modules/project-settings.cmake @@ -0,0 +1,33 @@ +include_guard(GLOBAL) + +include(warnings) +include(sanitizers) +include(optimizations) + +if(CPP_REQUEST_ENABLE_CLANG_TIDY) + include("${PROJECT_SOURCE_DIR}/cmake/tools/clang-tidy.cmake") +endif() + +function(cpp_request_setup_project) + if(PROJECT_IS_TOP_LEVEL AND NOT DEFINED CMAKE_EXPORT_COMPILE_COMMANDS) + set( + CMAKE_EXPORT_COMPILE_COMMANDS + ON + CACHE BOOL "Export compile_commands.json" FORCE + ) + endif() +endfunction() + +function(cpp_request_configure_target target) + if(NOT TARGET ${target}) + message(FATAL_ERROR "cpp_request_configure_target: unknown target '${target}'") + endif() + + cpp_request_apply_warnings(${target}) + cpp_request_apply_sanitizers(${target}) + cpp_request_apply_optimizations(${target}) + + if(CPP_REQUEST_ENABLE_CLANG_TIDY) + cpp_request_apply_clang_tidy(${target}) + endif() +endfunction() diff --git a/cmake/modules/sanitizers.cmake b/cmake/modules/sanitizers.cmake new file mode 100644 index 0000000..26774d7 --- /dev/null +++ b/cmake/modules/sanitizers.cmake @@ -0,0 +1,25 @@ +include_guard(GLOBAL) + +function(cpp_request_apply_sanitizers target) + if(NOT CPP_REQUEST_ENABLE_SANITIZERS) + return() + endif() + + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") + target_compile_options(${target} + PRIVATE + -fsanitize=address + -fsanitize=undefined + -fno-omit-frame-pointer + ) + target_link_options(${target} + PRIVATE + -fsanitize=address + -fsanitize=undefined + ) + else() + message(WARNING + "CPP_REQUEST_ENABLE_SANITIZERS is enabled, but the current compiler is unsupported" + ) + endif() +endfunction() diff --git a/cmake/modules/warnings.cmake b/cmake/modules/warnings.cmake new file mode 100644 index 0000000..c9ce7c8 --- /dev/null +++ b/cmake/modules/warnings.cmake @@ -0,0 +1,30 @@ +include_guard(GLOBAL) + +function(cpp_request_apply_warnings target) + if(NOT CPP_REQUEST_ENABLE_WARNINGS) + return() + endif() + + if(MSVC) + target_compile_options(${target} + PRIVATE + /W4 + /permissive- + ) + if(CPP_REQUEST_WARNINGS_AS_ERRORS) + target_compile_options(${target} PRIVATE /WX) + endif() + else() + target_compile_options(${target} + PRIVATE + -Wall + -Wextra + -Wpedantic + -Wconversion + -Wshadow + ) + if(CPP_REQUEST_WARNINGS_AS_ERRORS) + target_compile_options(${target} PRIVATE -Werror) + endif() + endif() +endfunction() From dcd7a9a4db48a8a801d70e3a52f26eb16cb15100 Mon Sep 17 00:00:00 2001 From: Rafi Indra Pramudhito Zuhayr Date: Tue, 15 Sep 2026 09:17:49 +0700 Subject: [PATCH 2/5] build: centralize target helpers --- benchmarks/CMakeLists.txt | 23 --------------------- cmake/modules/benchmarking.cmake | 34 ++++++++++++++++++++++++-------- cmake/modules/examples.cmake | 8 ++++++++ cmake/modules/testing.cmake | 33 +++++++++++++++++++++++-------- src/CMakeLists.txt | 29 ++++++++------------------- tests/CMakeLists.txt | 25 +---------------------- 6 files changed, 68 insertions(+), 84 deletions(-) create mode 100644 cmake/modules/examples.cmake diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 9125d2c..a6d9e0c 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -1,26 +1,3 @@ -include(${PROJECT_SOURCE_DIR}/cmake/packages/google-benchmark.cmake) -find_package(Threads REQUIRED) - -function(cpp_request_add_benchmark target source) - add_executable(${target} ${source}) - target_include_directories(${target} - PRIVATE - ${PROJECT_SOURCE_DIR}/src - ${CMAKE_CURRENT_SOURCE_DIR} - ) - target_link_libraries(${target} - PRIVATE - cpp_request::internal - benchmark::benchmark_main - Threads::Threads - ) - target_compile_features(${target} PRIVATE cxx_std_17) - - if(WIN32) - target_link_libraries(${target} PRIVATE ws2_32) - endif() -endfunction() - cpp_request_add_benchmark( cpp_request_bench_request_serializer request_serializer_benchmark.cpp diff --git a/cmake/modules/benchmarking.cmake b/cmake/modules/benchmarking.cmake index 0309414..dda462c 100644 --- a/cmake/modules/benchmarking.cmake +++ b/cmake/modules/benchmarking.cmake @@ -1,10 +1,28 @@ -include(${CMAKE_SOURCE_DIR}/cmake/packages/google-benchmark.cmake) - -function(add_benchmark_target name) - add_executable(${name} ${ARGN}) - target_link_libraries(${name} - PRIVATE +include_guard(GLOBAL) + +include("${PROJECT_SOURCE_DIR}/cmake/packages/google-benchmark.cmake") +find_package(Threads REQUIRED) + +function(cpp_request_add_benchmark target source) + add_executable(${target} ${source}) + + target_include_directories(${target} + PRIVATE + ${PROJECT_SOURCE_DIR}/src + ${PROJECT_SOURCE_DIR}/benchmarks + ) + + target_link_libraries(${target} + PRIVATE + cpp_request::cpp_request benchmark::benchmark_main - ${PROJECT_NAME}::internal + Threads::Threads ) -endfunction() \ No newline at end of file + + if(WIN32) + target_link_libraries(${target} PRIVATE ws2_32) + endif() + + target_compile_features(${target} PRIVATE cxx_std_17) + cpp_request_configure_target(${target}) +endfunction() diff --git a/cmake/modules/examples.cmake b/cmake/modules/examples.cmake new file mode 100644 index 0000000..951dfcf --- /dev/null +++ b/cmake/modules/examples.cmake @@ -0,0 +1,8 @@ +include_guard(GLOBAL) + +function(cpp_request_add_example target source) + add_executable(${target} ${source}) + target_link_libraries(${target} PRIVATE cpp_request::cpp_request) + target_compile_features(${target} PRIVATE cxx_std_17) + cpp_request_configure_target(${target}) +endfunction() diff --git a/cmake/modules/testing.cmake b/cmake/modules/testing.cmake index 835a5f1..7dacfc6 100644 --- a/cmake/modules/testing.cmake +++ b/cmake/modules/testing.cmake @@ -1,11 +1,28 @@ -include("${CMAKE_SOURCE_DIR}/cmake/packages/google-test.cmake") +include_guard(GLOBAL) -function(add_test_target name) - add_executable(${name} ${ARGN}) - target_link_libraries(${name} - PRIVATE +include("${PROJECT_SOURCE_DIR}/cmake/packages/google-test.cmake") +find_package(Threads REQUIRED) + +function(cpp_request_add_test target) + add_executable(${target} ${ARGN}) + + target_include_directories(${target} + PRIVATE + ${PROJECT_SOURCE_DIR}/src + ) + + target_link_libraries(${target} + PRIVATE + cpp_request::cpp_request GTest::gtest_main - ${PROJECT_NAME}::internal + Threads::Threads ) - gtest_discover_tests(${name}) -endfunction() \ No newline at end of file + + if(WIN32) + target_link_libraries(${target} PRIVATE ws2_32) + endif() + + target_compile_features(${target} PRIVATE cxx_std_17) + cpp_request_configure_target(${target}) + gtest_discover_tests(${target}) +endfunction() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6ee4ba0..f8800f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(internal +add_library(cpp_request ${CMAKE_CURRENT_SOURCE_DIR}/core/client.cpp ${CMAKE_CURRENT_SOURCE_DIR}/core/headers.cpp ${CMAKE_CURRENT_SOURCE_DIR}/core/url.cpp @@ -15,15 +15,15 @@ add_library(internal ${CMAKE_CURRENT_SOURCE_DIR}/net/tcp_connection.cpp ) -set_target_properties(internal PROPERTIES +set_target_properties(cpp_request PROPERTIES EXPORT_NAME cpp_request OUTPUT_NAME cpp_request ) -add_library(${PROJECT_NAME}::internal ALIAS internal) -add_library(${PROJECT_NAME}::cpp_request ALIAS internal) +add_library(cpp_request::cpp_request ALIAS cpp_request) +add_library(cpp_request::internal ALIAS cpp_request) -target_include_directories(internal +target_include_directories(cpp_request PUBLIC $ $ @@ -31,23 +31,10 @@ target_include_directories(internal ${PROJECT_SOURCE_DIR}/src ) -target_compile_features(internal PUBLIC cxx_std_17) +target_compile_features(cpp_request PUBLIC cxx_std_17) if(WIN32) - target_link_libraries(internal PRIVATE ws2_32) + target_link_libraries(cpp_request PRIVATE ws2_32) endif() -install( - TARGETS internal - EXPORT cpp_requestTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} - INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} -) - -install( - DIRECTORY ${PROJECT_SOURCE_DIR}/include/cpp_request - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - FILES_MATCHING PATTERN "*.hpp" -) +cpp_request_configure_target(cpp_request) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 167b55a..edbe9d8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,4 @@ -include(${PROJECT_SOURCE_DIR}/cmake/packages/google-test.cmake) -find_package(Threads REQUIRED) - -add_executable(cpp_request_tests +cpp_request_add_test(cpp_request_tests ${CMAKE_CURRENT_SOURCE_DIR}/result_test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/url_test.cpp ${CMAKE_CURRENT_SOURCE_DIR}/headers_test.cpp @@ -22,26 +19,6 @@ add_executable(cpp_request_tests ${CMAKE_CURRENT_SOURCE_DIR}/tcp_io_test.cpp ) -target_include_directories(cpp_request_tests - PRIVATE - ${PROJECT_SOURCE_DIR}/src -) - -target_link_libraries(cpp_request_tests - PRIVATE - cpp_request::internal - GTest::gtest_main - Threads::Threads -) - -if(WIN32) - target_link_libraries(cpp_request_tests PRIVATE ws2_32) -endif() - -target_compile_features(cpp_request_tests PRIVATE cxx_std_17) - -gtest_discover_tests(cpp_request_tests) - add_test( NAME PackageConsumer.InstallAndUse COMMAND From ceb8373db5a857af1e32b277675e39ff2acf58e7 Mon Sep 17 00:00:00 2001 From: Rafi Indra Pramudhito Zuhayr Date: Tue, 15 Sep 2026 09:18:26 +0700 Subject: [PATCH 3/5] build: centralize install package rules --- cmake/modules/install.cmake | 51 +++++++++++++++++++ cmake/modules/project-settings.cmake | 1 + .../cpp_requestConfig.cmake.in | 0 3 files changed, 52 insertions(+) create mode 100644 cmake/modules/install.cmake rename cmake/{ => templates}/cpp_requestConfig.cmake.in (100%) diff --git a/cmake/modules/install.cmake b/cmake/modules/install.cmake new file mode 100644 index 0000000..76bd1f0 --- /dev/null +++ b/cmake/modules/install.cmake @@ -0,0 +1,51 @@ +include_guard(GLOBAL) + +include(CMakePackageConfigHelpers) + +function(cpp_request_configure_install) + set( + CPP_REQUEST_INSTALL_CMAKEDIR + "${CMAKE_INSTALL_LIBDIR}/cmake/cpp_request" + ) + + configure_package_config_file( + "${PROJECT_SOURCE_DIR}/cmake/templates/cpp_requestConfig.cmake.in" + "${PROJECT_BINARY_DIR}/cpp_requestConfig.cmake" + INSTALL_DESTINATION "${CPP_REQUEST_INSTALL_CMAKEDIR}" + ) + + write_basic_package_version_file( + "${PROJECT_BINARY_DIR}/cpp_requestConfigVersion.cmake" + VERSION "${PROJECT_VERSION}" + COMPATIBILITY SameMinorVersion + ) + + install( + TARGETS cpp_request + EXPORT cpp_requestTargets + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + ) + + install( + DIRECTORY "${PROJECT_SOURCE_DIR}/include/cpp_request" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + FILES_MATCHING PATTERN "*.hpp" + ) + + install( + EXPORT cpp_requestTargets + FILE cpp_requestTargets.cmake + NAMESPACE cpp_request:: + DESTINATION "${CPP_REQUEST_INSTALL_CMAKEDIR}" + ) + + install( + FILES + "${PROJECT_BINARY_DIR}/cpp_requestConfig.cmake" + "${PROJECT_BINARY_DIR}/cpp_requestConfigVersion.cmake" + DESTINATION "${CPP_REQUEST_INSTALL_CMAKEDIR}" + ) +endfunction() diff --git a/cmake/modules/project-settings.cmake b/cmake/modules/project-settings.cmake index af8a3e7..0364fe2 100644 --- a/cmake/modules/project-settings.cmake +++ b/cmake/modules/project-settings.cmake @@ -1,5 +1,6 @@ include_guard(GLOBAL) +include(GNUInstallDirs) include(warnings) include(sanitizers) include(optimizations) diff --git a/cmake/cpp_requestConfig.cmake.in b/cmake/templates/cpp_requestConfig.cmake.in similarity index 100% rename from cmake/cpp_requestConfig.cmake.in rename to cmake/templates/cpp_requestConfig.cmake.in From 3df97bd7810f0b623bc171a5c25bbb922b61a9db Mon Sep 17 00:00:00 2001 From: Rafi Indra Pramudhito Zuhayr Date: Tue, 15 Sep 2026 09:19:12 +0700 Subject: [PATCH 4/5] build: clean up CMake tooling --- cmake/modules/optimizing.cmake | 56 -------------------------------- cmake/modules/output.cmake | 5 --- cmake/modules/sanitizing.cmake | 15 --------- cmake/modules/testing.cmake | 1 + cmake/modules/warning.cmake | 18 ---------- cmake/packages/google-test.cmake | 6 ++-- cmake/templates/CMakeLists.txt | 1 - cmake/templates/Doxyfile.in | 11 +++++++ cmake/templates/vcpkg.json.in | 7 ---- cmake/tools/clang-format.cmake | 55 +++++++++++++++++++++++-------- cmake/tools/clang-tidy.cmake | 15 ++++++--- cmake/tools/doxygen.cmake | 46 +++++++++++++------------- cmake/tools/vcpkg.cmake | 10 ------ 13 files changed, 90 insertions(+), 156 deletions(-) delete mode 100644 cmake/modules/optimizing.cmake delete mode 100644 cmake/modules/output.cmake delete mode 100644 cmake/modules/sanitizing.cmake delete mode 100644 cmake/modules/warning.cmake delete mode 100644 cmake/templates/CMakeLists.txt create mode 100644 cmake/templates/Doxyfile.in delete mode 100644 cmake/templates/vcpkg.json.in delete mode 100644 cmake/tools/vcpkg.cmake diff --git a/cmake/modules/optimizing.cmake b/cmake/modules/optimizing.cmake deleted file mode 100644 index 2d41cf5..0000000 --- a/cmake/modules/optimizing.cmake +++ /dev/null @@ -1,56 +0,0 @@ -if(ENABLE_RELEASE_OPTIMIZATION) - include(CheckIPOSupported) - check_ipo_supported(RESULT IPO_SUPPORTED OUTPUT IPO_ERROR) -endif() - -function(add_release_optimizations_target target) - if(ENABLE_RELEASE_OPTIMIZATION) - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") - target_compile_options(${target} - PRIVATE - $<$:-O3> - $<$:-ffunction-sections> - $<$:-fdata-sections> - ) - if(ENABLE_NATIVE_OPTIMIZATION) - target_compile_options(${target} - PRIVATE - $<$:-march=native> - $<$:-mtune=native> - ) - endif() - if(WIN32) - target_link_options(${target} - PRIVATE - $<$:LINKER:/OPT:REF> - $<$:LINKER:/OPT:ICF> - ) - else() - target_link_options(${target} - PRIVATE - $<$:LINKER:--gc-sections> - ) - endif() - elseif(MSVC) - target_compile_options(${target} - PRIVATE - $<$:/O2> - $<$:/GL> - $<$:/arch:AVX2> - ) - target_link_options(${target} - PRIVATE - $<$:/LTCG> - ) - endif() - if(IPO_SUPPORTED AND ENABLE_IPO) - set_property( - TARGET - ${target} - PROPERTY - INTERPROCEDURAL_OPTIMIZATION_RELEASE - TRUE - ) - endif() - endif() -endfunction() \ No newline at end of file diff --git a/cmake/modules/output.cmake b/cmake/modules/output.cmake deleted file mode 100644 index cd24611..0000000 --- a/cmake/modules/output.cmake +++ /dev/null @@ -1,5 +0,0 @@ -set(PROJECT_OUTPUT_DIR "${CMAKE_SOURCE_DIR}/out") -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_OUTPUT_DIR}/bin") -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_OUTPUT_DIR}/lib") -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_OUTPUT_DIR}/lib") -set(DOXYGEN_OUTPUT_DIRECTORY "${PROJECT_OUTPUT_DIR}/docs") \ No newline at end of file diff --git a/cmake/modules/sanitizing.cmake b/cmake/modules/sanitizing.cmake deleted file mode 100644 index aae5a1e..0000000 --- a/cmake/modules/sanitizing.cmake +++ /dev/null @@ -1,15 +0,0 @@ -function(add_sanitize_target target) - if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") - target_compile_options(${target} - PRIVATE - -fsanitize=address - -fsanitize=undefined - -fno-omit-frame-pointer - ) - target_link_options(${target} - PRIVATE - -fsanitize=address - -fsanitize=undefined - ) - endif() -endfunction() \ No newline at end of file diff --git a/cmake/modules/testing.cmake b/cmake/modules/testing.cmake index 7dacfc6..9580956 100644 --- a/cmake/modules/testing.cmake +++ b/cmake/modules/testing.cmake @@ -1,5 +1,6 @@ include_guard(GLOBAL) +enable_testing() include("${PROJECT_SOURCE_DIR}/cmake/packages/google-test.cmake") find_package(Threads REQUIRED) diff --git a/cmake/modules/warning.cmake b/cmake/modules/warning.cmake deleted file mode 100644 index 6c8e1ce..0000000 --- a/cmake/modules/warning.cmake +++ /dev/null @@ -1,18 +0,0 @@ -function(add_warning_target target) - if(MSVC) - target_compile_options(${target} - PRIVATE - /W4 - /permissive- - ) - else() - target_compile_options(${target} - PRIVATE - -Wall - -Wextra - -Wpedantic - -Wconversion - -Wshadow - ) - endif() -endfunction() \ No newline at end of file diff --git a/cmake/packages/google-test.cmake b/cmake/packages/google-test.cmake index d1ea176..177757a 100644 --- a/cmake/packages/google-test.cmake +++ b/cmake/packages/google-test.cmake @@ -1,4 +1,5 @@ -enable_testing() +include_guard(GLOBAL) + find_package(GTest CONFIG QUIET) if(NOT GTest_FOUND) @@ -7,10 +8,11 @@ if(NOT GTest_FOUND) googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG v1.18.0 + GIT_SHALLOW TRUE ) set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(googletest) endif() -include(GoogleTest) \ No newline at end of file +include(GoogleTest) diff --git a/cmake/templates/CMakeLists.txt b/cmake/templates/CMakeLists.txt deleted file mode 100644 index a180188..0000000 --- a/cmake/templates/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(${CMAKE_SOURCE_DIR}/cmake/tools/vcpkg.cmake) \ No newline at end of file diff --git a/cmake/templates/Doxyfile.in b/cmake/templates/Doxyfile.in new file mode 100644 index 0000000..3c294ae --- /dev/null +++ b/cmake/templates/Doxyfile.in @@ -0,0 +1,11 @@ +PROJECT_NAME = "@PROJECT_NAME@" +PROJECT_NUMBER = "@PROJECT_VERSION@" +OUTPUT_DIRECTORY = "@PROJECT_BINARY_DIR@/docs" +INPUT = "@PROJECT_SOURCE_DIR@/include" +RECURSIVE = YES +FILE_PATTERNS = *.h *.hpp +EXTRACT_ALL = YES +GENERATE_HTML = YES +GENERATE_LATEX = NO +QUIET = YES +WARN_IF_UNDOCUMENTED = NO diff --git a/cmake/templates/vcpkg.json.in b/cmake/templates/vcpkg.json.in deleted file mode 100644 index 12f6da4..0000000 --- a/cmake/templates/vcpkg.json.in +++ /dev/null @@ -1,7 +0,0 @@ -{ - "name": "@PROJECT_NAME_SLUG@", - "version": "@PROJECT_VERSION@", - "description": "@PROJECT_DESCRIPTION@", - "dependencies": [ - ] -} \ No newline at end of file diff --git a/cmake/tools/clang-format.cmake b/cmake/tools/clang-format.cmake index 46dffda..7cfc5ae 100644 --- a/cmake/tools/clang-format.cmake +++ b/cmake/tools/clang-format.cmake @@ -1,19 +1,46 @@ -find_program(CLANG_FORMAT_EXE NAMES clang-format) +include_guard(GLOBAL) -function(add_clang_format_target target) - if(CLANG_FORMAT_EXE) - get_target_property(TARGET_SOURCES ${target} SOURCES) +find_program(CLANG_FORMAT_EXE NAMES clang-format) - add_custom_target(format - COMMAND ${CLANG_FORMAT_EXE} -i -style=file ${TARGET_SOURCES} - COMMENT "Formatting ${target} source files with clang-format" +function(cpp_request_add_clang_format_targets) + if(NOT CLANG_FORMAT_EXE) + message(WARNING + "CPP_REQUEST_ENABLE_CLANG_FORMAT is ON, but clang-format was not found" ) + return() + endif() - add_custom_target(format-check - COMMAND ${CLANG_FORMAT_EXE} --dry-run --Werror -style=file ${TARGET_SOURCES} - COMMENT "Checking ${target} source formatting" - ) - else() - message(WARNING "clang format not found! Target '${target}' will not be created.") + file(GLOB_RECURSE _cpp_request_format_sources + CONFIGURE_DEPENDS + LIST_DIRECTORIES FALSE + "${PROJECT_SOURCE_DIR}/include/*.h" + "${PROJECT_SOURCE_DIR}/include/*.hpp" + "${PROJECT_SOURCE_DIR}/src/*.c" + "${PROJECT_SOURCE_DIR}/src/*.cc" + "${PROJECT_SOURCE_DIR}/src/*.cpp" + "${PROJECT_SOURCE_DIR}/src/*.h" + "${PROJECT_SOURCE_DIR}/src/*.hpp" + "${PROJECT_SOURCE_DIR}/tests/*.cpp" + "${PROJECT_SOURCE_DIR}/tests/*.hpp" + "${PROJECT_SOURCE_DIR}/benchmarks/*.cpp" + "${PROJECT_SOURCE_DIR}/benchmarks/*.hpp" + "${PROJECT_SOURCE_DIR}/examples/*.cpp" + "${PROJECT_SOURCE_DIR}/examples/*.hpp" + ) + + if(NOT _cpp_request_format_sources) + return() endif() -endfunction() \ No newline at end of file + + add_custom_target(cpp_request_format + COMMAND "${CLANG_FORMAT_EXE}" -i -style=file ${_cpp_request_format_sources} + COMMENT "Formatting cpp_request C++ sources" + VERBATIM + ) + + add_custom_target(cpp_request_format_check + COMMAND "${CLANG_FORMAT_EXE}" --dry-run --Werror -style=file ${_cpp_request_format_sources} + COMMENT "Checking cpp_request C++ source formatting" + VERBATIM + ) +endfunction() diff --git a/cmake/tools/clang-tidy.cmake b/cmake/tools/clang-tidy.cmake index 6fc3404..68ba2a4 100644 --- a/cmake/tools/clang-tidy.cmake +++ b/cmake/tools/clang-tidy.cmake @@ -1,9 +1,16 @@ +include_guard(GLOBAL) + find_program(CLANG_TIDY_EXE NAMES clang-tidy) -function(add_clang_tidy_target target) +function(cpp_request_apply_clang_tidy target) if(CLANG_TIDY_EXE) - set_target_properties(${target} PROPERTIES CXX_CLANG_TIDY "${CLANG_TIDY_EXE}") + set_target_properties( + ${target} + PROPERTIES CXX_CLANG_TIDY "${CLANG_TIDY_EXE}" + ) else() - message(WARNING "clang tidy not found! Target '${target}' will not be created.") + message(WARNING + "CPP_REQUEST_ENABLE_CLANG_TIDY is ON, but clang-tidy was not found" + ) endif() -endfunction() \ No newline at end of file +endfunction() diff --git a/cmake/tools/doxygen.cmake b/cmake/tools/doxygen.cmake index d671ada..7581478 100644 --- a/cmake/tools/doxygen.cmake +++ b/cmake/tools/doxygen.cmake @@ -1,28 +1,26 @@ -find_program(DOXYGEN_EXE NAMES DOXYGEN) +include_guard(GLOBAL) -function(add_doxygen_target target) - if(DOXYGEN_EXE) - set(DOXYFILE_IN "${CMAKE_SOURCE_DIR}/cmake/templates/Doxyfile.in") - set(DOXYFILE_OUT "${CMAKE_SOURCE_DIR}/Doxyfile") +find_package(Doxygen QUIET) - if(EXISTS ${DOXYFILE_IN}) - configure_file(${DOXYFILE_IN} ${DOXYFILE_OUT} @ONLY) - - add_custom_target(${target} - COMMAND ${DOXYGEN_EXE} ${DOXYGEN_OUT} - WORKING_DIRECTORY ${DOXYGEN_OUTPUT_DIRECTORY} - COMMENT "Generating API documentation with Doxygen..." - VERBATIM - ) - else() - add_custom_target(${target} - COMMAND ${DOXYGEN_EXE} ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMENT "Generating API documentation with Doxygen..." - VERBATIM - ) - endif() - else() - message(WARNING "Doxygen not found! Target '${target}' will not be created.") +function(cpp_request_add_doxygen_target target) + if(NOT Doxygen_FOUND) + message(WARNING + "CPP_REQUEST_ENABLE_DOXYGEN is ON, but Doxygen was not found" + ) + return() endif() + + set(_cpp_request_doxyfile "${PROJECT_BINARY_DIR}/Doxyfile") + configure_file( + "${PROJECT_SOURCE_DIR}/cmake/templates/Doxyfile.in" + "${_cpp_request_doxyfile}" + @ONLY + ) + + add_custom_target(${target} + COMMAND Doxygen::doxygen "${_cpp_request_doxyfile}" + WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" + COMMENT "Generating cpp_request API documentation" + VERBATIM + ) endfunction() diff --git a/cmake/tools/vcpkg.cmake b/cmake/tools/vcpkg.cmake deleted file mode 100644 index 69b7f23..0000000 --- a/cmake/tools/vcpkg.cmake +++ /dev/null @@ -1,10 +0,0 @@ -string(TOLOWER "${PROJECT_NAME}" PROJECT_NAME_SLUG) -string(REGEX REPLACE "[ _]" "-" PROJECT_NAME_SLUG "${PROJECT_NAME_SLUG}") -string(REGEX REPLACE "-+" "-" PROJECT_NAME_SLUG "${PROJECT_NAME_SLUG}") -string(REGEX REPLACE "^-*(.*[^-])-*$" "\\1" PROJECT_NAME_SLUG "${PROJECT_NAME_SLUG}") - -configure_file( - "${CMAKE_SOURCE_DIR}/cmake/templates/vcpkg.json.in" - "${CMAKE_SOURCE_DIR}/vcpkg.json" - @ONLY -) \ No newline at end of file From f9dd1ddfe124f80b56cfb2571a34862debce97f8 Mon Sep 17 00:00:00 2001 From: Rafi Indra Pramudhito Zuhayr Date: Tue, 15 Sep 2026 09:20:17 +0700 Subject: [PATCH 5/5] build: finalize modular CMake orchestration --- CMakeLists.txt | 4 ++-- cmake/README.md | 27 +++++++++++++++++++++++++++ cmake/modules/options.cmake | 7 ++++++- 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 cmake/README.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 1026724..f8d966b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,9 +10,9 @@ project( list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake/modules") include(options) -include(project-settings) - cpp_request_setup_options() + +include(project-settings) cpp_request_setup_project() add_subdirectory(src) diff --git a/cmake/README.md b/cmake/README.md new file mode 100644 index 0000000..93afd9d --- /dev/null +++ b/cmake/README.md @@ -0,0 +1,27 @@ +# CMake structure + +`cpp_request` keeps the root `CMakeLists.txt` as an orchestrator. Project behavior is split by responsibility: + +- `modules/` — project options, target policy, tests, benchmarks, examples, and install/export rules. +- `packages/` — development-only third-party discovery with `find_package()` first and `FetchContent` fallback. +- `tools/` — optional developer tooling such as clang-format, clang-tidy, and Doxygen. +- `templates/` — inputs for files generated into the build/install tree. + +Normal CMake configure must not modify files in the source tree. In particular, `vcpkg.json` is source-controlled input and is not generated by CMake. + +## Main options + +- `CPP_REQUEST_BUILD_TESTS` +- `CPP_REQUEST_BUILD_BENCHMARKS` +- `CPP_REQUEST_BUILD_EXAMPLES` +- `CPP_REQUEST_ENABLE_INSTALL` +- `CPP_REQUEST_ENABLE_WARNINGS` +- `CPP_REQUEST_WARNINGS_AS_ERRORS` +- `CPP_REQUEST_ENABLE_SANITIZERS` +- `CPP_REQUEST_ENABLE_IPO` +- `CPP_REQUEST_ENABLE_NATIVE_OPTIMIZATION` +- `CPP_REQUEST_ENABLE_CLANG_TIDY` +- `CPP_REQUEST_ENABLE_CLANG_FORMAT` +- `CPP_REQUEST_ENABLE_DOXYGEN` + +Tests, examples, and install rules default on only when `cpp_request` is the top-level project. Benchmarks and developer tools are opt-in. For compatibility with conventional CMake callers, an explicitly supplied `BUILD_TESTING` value is used as the default for `CPP_REQUEST_BUILD_TESTS`. diff --git a/cmake/modules/options.cmake b/cmake/modules/options.cmake index 6e22336..fd9bc17 100644 --- a/cmake/modules/options.cmake +++ b/cmake/modules/options.cmake @@ -6,10 +6,15 @@ function(cpp_request_setup_options) set(_cpp_request_top_level_default ON) endif() + set(_cpp_request_test_default ${_cpp_request_top_level_default}) + if(DEFINED BUILD_TESTING) + set(_cpp_request_test_default ${BUILD_TESTING}) + endif() + option( CPP_REQUEST_BUILD_TESTS "Build cpp_request tests" - ${_cpp_request_top_level_default} + ${_cpp_request_test_default} ) option( CPP_REQUEST_BUILD_BENCHMARKS