From 18197ae93533e10e734591eccdec9634ab3b1e6b Mon Sep 17 00:00:00 2001 From: Christopher Bate Date: Sat, 4 Oct 2025 16:25:55 -0600 Subject: [PATCH 1/2] Make some optimizations to the CMake build system I profiled initial CMake configuration and generation (Ninja) steps in LLVM-Project with just LLVM, MLIR, and Clang enabled using the command shown below. Based on the profile, I then implemented a number of optimizations. Initial time of `cmake` command @ 679d2b2ab618: -- Configuring done (17.8s) -- Generating done (6.9s) After all below optimizations: -- Configuring done (12.8s) -- Generating done (4.7s) With a "toolchain check cache" (explained below): -- Configuring done (6.9s) -- Generating done (4.3s) There's definitely room for more optimizations -- another 20% at least. Most changes have a small impact. It's the gradual creep of inefficiencies that have added up over time to make the system less efficient than it could be. Command tested: ``` cmake -G Ninja -S llvm -B ${buildDir} \ -DLLVM_ENABLE_PROJECTS="mlir;clang" \ -DLLVM_TARGETS_TO_BUILD="X86;NVPTX" \ -DCMAKE_BUILD_TYPE=RelWithDebInfo \ -DLLVM_ENABLE_ASSERTIONS=ON \ -DLLVM_CCACHE_BUILD=ON \ -DBUILD_SHARED_LIBS=ON \ -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DLLVM_USE_LINKER=lld \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DMLIR_ENABLE_BINDINGS_PYTHON=ON \ -DLLVM_TOOLCHAIN_CHECK_CACHE=${PWD}/.toolchain-check-cache.cmake \ --fresh ``` ## Optimizations: ### Optimize `check_linker_flag` calls In `AddLLVM.cmake`, there were a couple places where we call `check_linker_flag` every time `llvm_add_library` is called. Even in non-initial cmake configuration runs, this carries unreasonable overhead. Change: Host (CheckLinkerFlag)` in AddLLVM.cmake and optimize placement of `check_linker_flag` calls so that they are only made once. Impact: - <1 sec ### Make `add_lit_testsuites` optional The function `add_lit_testsuites` is used to recursively populate a set of convenience targets that run a filtered portion of a LIT test suite. So instead of running `check-mlir` you can run `check-mlir-dialect`. These targets are built recursively for each subdirectory (e.g. `check-mlir-dialect-tensor`, `check-mlir-dialect-math`, etc.). This call has quite a bit of overhead, especially for the main LLVM LIT test suite. Personally I use a combination of `ninja -C build check-mlir-build-only` and `llvm-lit` directly to run filtered portions of the MLIR LIT test suite, but I can imagine that others depend on these filtered targets. Change: Introduce a new option `LLVM_ENABLE_LIT_CONVENIENCE_TARGETS` which defaults to `ON`. When set to `OFF`, the function `add_lit_testsuites` just becomes a no-op. It's possible that we could also just improve the performance of `add_lit_testsuites` directly, but I didn't pursue this. Impact: ~1-2sec ### Reduce `file(GLOB)` calls in `LLVMProcessSources.cmake` The `llvm_process_sources` call is made whenver the `llvm_add_library` function is called. It makes several `file(GLOB)` calls, which can be expensive depending on the underlying filesystem/storage. The function globs for headers and TD files to add as sources to the target, but the comments suggest that this is only necessary for MSVC. In addition, it calls `llvm_check_source_file_list` to check that no source files in the directory are unused unless `PARTIAL_SOURCES_INTENDED` is set, which incurs another `file(GLOB)` call. Changes: Guard the `file(GLOB)` calls for populating header sources behind `if(MSVC)`. Only do the `llvm_check_source_file_list` check if a new option `LLVM_ENABLE_EXPENSIVE_CMAKE_CHECKS` is set to `ON`. Impact: depends on system. On my local workstation, impact is minimal. On another remote server I use, impact is much larger. ### Optimize initial symbol/flag checks made in `config-ix.cmake` and `HandleLLVMOptions.cmake` The `config-ix.cmake` and `HandleLLVMOptions.cmake` files make a number of calls to compile C/C++ programs in order to verify the precense of certain symbols or whether certain compiler flags are supported. These checks have the biggest impact on an initial `cmake` configuration time. I propose an "opt in" approach for amortizing these checks using a special generated CMake cache file as directed by the developer. An option `LLVM_TOOLCHAIN_CHECK_CACHE` is introduced. It should be set to a path like `-DLLVM_TOOLCHAIN_CHECK_CACHE=$PWD/.toolchain-check-cache.cmake`. Before entering the `config-ix.cmake` and `HandleLLVMOptions.cmake` files, if the `LLVM_TOOLCHAIN_CHECK_CACHE` option is set and exists, include that file to pre-populate cache variables. Otherwise, we save the current set of CMake cache variables names. After calling the `config-ix|HandleLLVMOptions` files, if the `LLVM_TOOLCHAIN_CHECK_CACHE` option is set but does not exist, check what new CMake cache variables were set by those scripts. Filter these variables by whether they are likely cache variables supporting symbol/flag checks (e.g. `CXX_SUPPORTS_.*|HAVE_.*` etc) and write the file to set all these cache variables to their current values. This allows a developer to obviate any subsequent checks, even in initial `cmake` configuration runs. The correctness depends on the developer knowing when it is invalid (e.g. they change toolchains or platforms) and us suddenly not changing the meaning of `CXX_SUPPORTS_SOME_FLAG` to correspond to a different flag. It could be extended the cache file to store a key used to check whether to regenerate the cache, but I didn't go there. Impact: Trivial overhead for cache generation, ~5sec reduction in initial config time. ### Reduce overhead of embedded Google Benchmark configuration Note: technically this could be lumped in with the above if we expanded scope of before/after change that the `LLVM_TOOLCHAIN_CHECK_CACHE` covers. GoogleBenchmark is embedded under the `third-party/benchmark` directory. Its CMake script does a compilation check for each flag that it wants to populate (even for `-Wall`). In comparison, LLVM's HandleLLVMOptions.cmake script takes a faster approach by skipping as many compilation checks as possible if the cache variable `LLVM_COMPILER_IS_GCC_COMPATIBLE` is true. Changes: Use `LLVM_COMPILER_IS_GCC_COMPATIBLE` to skip as many compilation checks as possible in GoogleBenchmark. Impact: ~1-2sec --- llvm/CMakeLists.txt | 22 ++++++++- llvm/cmake/modules/AddLLVM.cmake | 51 ++++++++++++-------- llvm/cmake/modules/LLVMCacheSnapshot.cmake | 51 ++++++++++++++++++++ llvm/cmake/modules/LLVMProcessSources.cmake | 24 ++++++---- third-party/benchmark/CMakeLists.txt | 53 ++++++++++++--------- 5 files changed, 149 insertions(+), 52 deletions(-) create mode 100644 llvm/cmake/modules/LLVMCacheSnapshot.cmake diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt index c450ee5a3d72e..d52bd84814aec 100644 --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -867,6 +867,11 @@ option(LLVM_INSTALL_GTEST "Install the llvm gtest library. This should be on if you want to do stand-alone builds of the other projects and run their unit tests." OFF) +option(LLVM_ENABLE_EXPENSIVE_CMAKE_CHECKS + "Enable use of expensive CMake checks for unused source files" ON) +option(LLVM_ENABLE_LIT_CONVENIENCE_TARGETS + "Enable use of convenience targets for all subdirectories of a LIT test suite" ON) + option(LLVM_BUILD_BENCHMARKS "Add LLVM benchmark targets to the list of default targets. If OFF, benchmarks still could be built using Benchmarks target." OFF) option(LLVM_INCLUDE_BENCHMARKS "Generate benchmark targets. If OFF, benchmarks can't be built." ON) @@ -1027,9 +1032,18 @@ endif() find_package(Python3 ${LLVM_MINIMUM_PYTHON_VERSION} REQUIRED COMPONENTS Interpreter) +set(LLVM_TOOLCHAIN_CHECK_CACHE "" CACHE PATH + "Path to where a generated *.cmake cache file will be saved.") + +include(LLVMCacheSnapshot) # All options referred to from HandleLLVMOptions have to be specified # BEFORE this include, otherwise options will not be correctly set on -# first cmake run +# first cmake run. +if(LLVM_TOOLCHAIN_CHECK_CACHE AND EXISTS "${LLVM_TOOLCHAIN_CHECK_CACHE}") + include("${LLVM_TOOLCHAIN_CHECK_CACHE}") +elseif(LLVM_TOOLCHAIN_CHECK_CACHE) + llvm_get_list_of_existing_cache_variables(cache_before) +endif() include(config-ix) # By default, we target the host, but this can be overridden at CMake @@ -1081,6 +1095,12 @@ endif() include(HandleLLVMOptions) +if(LLVM_TOOLCHAIN_CHECK_CACHE AND NOT EXISTS "${LLVM_TOOLCHAIN_CHECK_CACHE}") + llvm_list_of_new_cache_variables_and_values(cache_before cache_new_pairs) + list(JOIN cache_new_pairs "\n" cache_new_pairs_joined) + file(WRITE "${LLVM_TOOLCHAIN_CHECK_CACHE}" "${cache_new_pairs_joined}") +endif() + ###### # Configure all of the various header file fragments LLVM uses which depend on diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake index 80e59a4df2433..f26dd7aa549c5 100644 --- a/llvm/cmake/modules/AddLLVM.cmake +++ b/llvm/cmake/modules/AddLLVM.cmake @@ -3,17 +3,18 @@ include(LLVMDistributionSupport) include(LLVMProcessSources) include(LLVM-Config) include(DetermineGCCCompatible) +include(CheckLinkerFlag) # get_subproject_title(titlevar) # Set ${outvar} to the title of the current LLVM subproject (Clang, MLIR ...) -# +# # The title is set in the subproject's top-level using the variable # LLVM_SUBPROJECT_TITLE. If it does not exist, it is assumed it is LLVM itself. # The title is not semantically significant, but use to create folders in # CMake-generated IDE projects (Visual Studio/XCode). function(get_subproject_title outvar) if (LLVM_SUBPROJECT_TITLE) - set(${outvar} "${LLVM_SUBPROJECT_TITLE}" PARENT_SCOPE) + set(${outvar} "${LLVM_SUBPROJECT_TITLE}" PARENT_SCOPE) else () set(${outvar} "LLVM" PARENT_SCOPE) endif () @@ -269,7 +270,6 @@ if (NOT DEFINED LLVM_LINKER_DETECTED AND NOT WIN32) endif() if("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin") - include(CheckLinkerFlag) # Linkers that support Darwin allow a setting to internalize all symbol exports, # aiding in reducing binary size and often is applicable for executables. check_linker_flag(C "-Wl,-no_exported_symbols" LLVM_LINKER_SUPPORTS_NO_EXPORTED_SYMBOLS) @@ -289,8 +289,23 @@ if (NOT DEFINED LLVM_LINKER_DETECTED AND NOT WIN32) endif() endif() +if (NOT uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG") + if(NOT LLVM_NO_DEAD_STRIP) + if("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS" AND LLVM_LINKER_IS_SOLARISLD) + # Support for ld -z discard-unused=sections was only added in + # Solaris 11.4. GNU ld ignores it, but warns every time. + check_linker_flag(CXX "-Wl,-z,discard-unused=sections" LINKER_SUPPORTS_Z_DISCARD_UNUSED) + endif() + endif() +endif() + +# Check for existence of symbolic functions flag. Not supported +# by the older BFD linker (such as on some OpenBSD archs), the +# MinGW driver for LLD, and the Solaris native linker. +check_linker_flag(CXX "-Wl,-Bsymbolic-functions" + LLVM_LINKER_SUPPORTS_B_SYMBOLIC_FUNCTIONS) + function(add_link_opts target_name) - include(CheckLinkerFlag) get_llvm_distribution(${target_name} in_distribution in_distribution_var) if(NOT in_distribution) # Don't LTO optimize targets that aren't part of any distribution. @@ -320,9 +335,6 @@ function(add_link_opts target_name) set_property(TARGET ${target_name} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-dead_strip") elseif("${CMAKE_SYSTEM_NAME}" MATCHES "SunOS" AND LLVM_LINKER_IS_SOLARISLD) - # Support for ld -z discard-unused=sections was only added in - # Solaris 11.4. GNU ld ignores it, but warns every time. - check_linker_flag(CXX "-Wl,-z,discard-unused=sections" LINKER_SUPPORTS_Z_DISCARD_UNUSED) if (LINKER_SUPPORTS_Z_DISCARD_UNUSED) set_property(TARGET ${target_name} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-z,discard-unused=sections") @@ -349,12 +361,6 @@ function(add_link_opts target_name) set_property(TARGET ${target_name} APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-brtl") endif() - - # Check for existence of symbolic functions flag. Not supported - # by the older BFD linker (such as on some OpenBSD archs), the - # MinGW driver for LLD, and the Solaris native linker. - check_linker_flag(CXX "-Wl,-Bsymbolic-functions" - LLVM_LINKER_SUPPORTS_B_SYMBOLIC_FUNCTIONS) endfunction(add_link_opts) # Set each output directory according to ${CMAKE_CONFIGURATION_TYPES}. @@ -645,11 +651,11 @@ function(llvm_add_library name) endif() set_target_properties(${name} PROPERTIES FOLDER "${subproject_title}/Libraries") - ## If were compiling with clang-cl use /Zc:dllexportInlines- to exclude inline + ## If were compiling with clang-cl use /Zc:dllexportInlines- to exclude inline ## class members from being dllexport'ed to reduce compile time. ## This will also keep us below the 64k exported symbol limit ## https://blog.llvm.org/2018/11/30-faster-windows-builds-with-clang-cl_14.html - if(LLVM_BUILD_LLVM_DYLIB AND NOT LLVM_DYLIB_EXPORT_INLINES AND + if(LLVM_BUILD_LLVM_DYLIB AND NOT LLVM_DYLIB_EXPORT_INLINES AND MSVC AND CMAKE_CXX_COMPILER_ID MATCHES Clang) target_compile_options(${name} PUBLIC /Zc:dllexportInlines-) if(TARGET ${obj_name}) @@ -1500,8 +1506,8 @@ macro(llvm_add_tool project name) RUNTIME DESTINATION ${${project}_TOOLS_INSTALL_DIR} COMPONENT ${name}) if (LLVM_ENABLE_PDB) - install(FILES $ - DESTINATION "${${project}_TOOLS_INSTALL_DIR}" COMPONENT ${name} + install(FILES $ + DESTINATION "${${project}_TOOLS_INSTALL_DIR}" COMPONENT ${name} OPTIONAL) endif() @@ -1535,8 +1541,8 @@ macro(add_llvm_example name) if( LLVM_BUILD_EXAMPLES ) install(TARGETS ${name} RUNTIME DESTINATION "${LLVM_EXAMPLES_INSTALL_DIR}") if (LLVM_ENABLE_PDB) - install(FILES $ - DESTINATION "${LLVM_EXAMPLES_INSTALL_DIR}" COMPONENT ${name} + install(FILES $ + DESTINATION "${LLVM_EXAMPLES_INSTALL_DIR}" COMPONENT ${name} OPTIONAL) endif() endif() @@ -1574,8 +1580,8 @@ macro(add_llvm_utility name) RUNTIME DESTINATION ${LLVM_UTILS_INSTALL_DIR} COMPONENT ${name}) if (LLVM_ENABLE_PDB) - install(FILES $ - DESTINATION "${LLVM_UTILS_INSTALL_DIR}" COMPONENT ${name} + install(FILES $ + DESTINATION "${LLVM_UTILS_INSTALL_DIR}" COMPONENT ${name} OPTIONAL) endif() @@ -2192,6 +2198,9 @@ function(add_lit_testsuite target comment) endfunction() function(add_lit_testsuites project directory) + if(NOT LLVM_ENABLE_LIT_CONVENIENCE_TARGETS) + return() + endif() if (NOT LLVM_ENABLE_IDE) cmake_parse_arguments(ARG "EXCLUDE_FROM_CHECK_ALL" diff --git a/llvm/cmake/modules/LLVMCacheSnapshot.cmake b/llvm/cmake/modules/LLVMCacheSnapshot.cmake new file mode 100644 index 0000000000000..89d592a0a4165 --- /dev/null +++ b/llvm/cmake/modules/LLVMCacheSnapshot.cmake @@ -0,0 +1,51 @@ +# Example usage +# llvm_get_cache_vars(before) +# include(SomeModule) +# llvm_diff_cache_vars("${before}" new_vars new_pairs) + +# message(STATUS "New cache variables: ${new_vars}") +# message(STATUS "New cache vars and values:\n${new_pairs}") + +# get_list_of_existing_cache_variables(existing) +function(llvm_get_list_of_existing_cache_variables out_var) + get_cmake_property(_all CACHE_VARIABLES) + if(NOT _all) + set(_all "") + endif() + set(${out_var} "${_all}" PARENT_SCOPE) +endfunction() + +# list_of_new_cache_variables_and_values(existing new_vars_and_values) +# - `existing` is the name of the var returned by the first helper +# - `new_vars_and_values` will be a list like: NAME=VALUE (TYPE=...);NAME2=VALUE2 (TYPE=...) +function(llvm_list_of_new_cache_variables_and_values existing_list_var out_var) + # Existing (pre-include) snapshot + set(_before "${${existing_list_var}}") + + # Current (post-include) snapshot + get_cmake_property(_after CACHE_VARIABLES) + + # Compute new names + set(_new "${_after}") + if(_before) + list(REMOVE_ITEM _new ${_before}) + endif() + + # Pack "NAME=VALUE (TYPE=...)" for each new cache entry + set(_pairs "") + foreach(_k IN LISTS _new) + if(NOT "${_k}" MATCHES "^((C|CXX)_SUPPORTS|HAVE_|GLIBCXX_USE|SUPPORTS_FVISI)") + continue() + endif() + # Cache VALUE: dereference is fine here because cache entries read like normal vars + set(_val "${${_k}}") + # Cache TYPE (e.g., STRING, BOOL, PATH, FILEPATH, INTERNAL, UNINITIALIZED) + get_property(_type CACHE "${_k}" PROPERTY TYPE) + if(NOT _type) + set(_type "UNINITIALIZED") + endif() + list(APPEND _pairs "set(${_k} \"${_val}\" CACHE ${_type} \"\")") + endforeach() + + set(${out_var} "${_pairs}" PARENT_SCOPE) +endfunction() diff --git a/llvm/cmake/modules/LLVMProcessSources.cmake b/llvm/cmake/modules/LLVMProcessSources.cmake index 0670d60bf2afd..0bcce4c6c78ad 100644 --- a/llvm/cmake/modules/LLVMProcessSources.cmake +++ b/llvm/cmake/modules/LLVMProcessSources.cmake @@ -56,17 +56,25 @@ endfunction(find_all_header_files) function(llvm_process_sources OUT_VAR) cmake_parse_arguments(ARG "PARTIAL_SOURCES_INTENDED" "" "ADDITIONAL_HEADERS;ADDITIONAL_HEADER_DIRS" ${ARGN}) set(sources ${ARG_UNPARSED_ARGUMENTS}) - llvm_check_source_file_list(${sources}) - # This adds .td and .h files to the Visual Studio solution: - add_td_sources(sources) - find_all_header_files(hdrs "${ARG_ADDITIONAL_HEADER_DIRS}") - if (hdrs) - set_source_files_properties(${hdrs} PROPERTIES HEADER_FILE_ONLY ON) + if(LLVM_ENABLE_EXPENSIVE_CMAKE_CHECKS) + llvm_check_source_file_list(${sources}) + endif() + + if(ARG_ADDITIONAL_HEADERS) + set_source_files_properties(${ARG_ADDITIONAL_HEADERS} PROPERTIES HEADER_FILE_ONLY ON) + list(APPEND sources ${ARG_ADDITIONAL_HEADERS}) endif() - set_source_files_properties(${ARG_ADDITIONAL_HEADERS} PROPERTIES HEADER_FILE_ONLY ON) - list(APPEND sources ${ARG_ADDITIONAL_HEADERS} ${hdrs}) + # This adds .td and .h files to the Visual Studio solution: + if(MSVC OR LLVM_ENABLE_EXPENSIVE_CMAKE_CHECKS) + add_td_sources(sources) + find_all_header_files(hdrs "${ARG_ADDITIONAL_HEADER_DIRS}") + if (hdrs) + set_source_files_properties(${hdrs} PROPERTIES HEADER_FILE_ONLY ON) + endif() + list(APPEND sources ${hdrs}) + endif() set( ${OUT_VAR} ${sources} PARENT_SCOPE ) endfunction(llvm_process_sources) diff --git a/third-party/benchmark/CMakeLists.txt b/third-party/benchmark/CMakeLists.txt index d9bcc6a4939be..663793c1d4a91 100644 --- a/third-party/benchmark/CMakeLists.txt +++ b/third-party/benchmark/CMakeLists.txt @@ -147,6 +147,15 @@ endif() set(CMAKE_CXX_STANDARD ${BENCHMARK_CXX_STANDARD}) set(CMAKE_CXX_STANDARD_REQUIRED YES) set(CMAKE_CXX_EXTENSIONS OFF) +option(BENCHMARK_ENABLE_EXPENSIVE_CMAKE_CHECKS "Enable use of expensive CMake checks for unused source files" ON) + +macro(handle_flag flag) + if(LLVM_COMPILER_IS_GCC_COMPATIBLE AND NOT BENCHMARK_ENABLE_EXPENSIVE_CMAKE_CHECKS) + list(APPEND CMAKE_CXX_FLAGS ${flag}) + else() + add_cxx_compiler_flag(${flag}) + endif() +endmacro() if (MSVC) # Turn compiler warnings up to 11 @@ -185,49 +194,49 @@ else() add_definitions(-D_LARGEFILE64_SOURCE) add_definitions(-D_LARGEFILE_SOURCE) # Turn compiler warnings up to 11 - add_cxx_compiler_flag(-Wall) - add_cxx_compiler_flag(-Wextra) - add_cxx_compiler_flag(-Wshadow) - add_cxx_compiler_flag(-Wfloat-equal) - add_cxx_compiler_flag(-Wold-style-cast) + handle_flag(-Wall) + handle_flag(-Wextra) + handle_flag(-Wshadow) + handle_flag(-Wfloat-equal) + handle_flag(-Wold-style-cast) if(BENCHMARK_ENABLE_WERROR) - add_cxx_compiler_flag(-Werror) + handle_flag(-Werror) endif() if (NOT BENCHMARK_ENABLE_TESTING) # Disable warning when compiling tests as gtest does not use 'override'. - add_cxx_compiler_flag(-Wsuggest-override) + handle_flag(-Wsuggest-override) endif() - add_cxx_compiler_flag(-pedantic) - add_cxx_compiler_flag(-pedantic-errors) - add_cxx_compiler_flag(-Wshorten-64-to-32) - add_cxx_compiler_flag(-fstrict-aliasing) + handle_flag(-pedantic) + handle_flag(-pedantic-errors) + handle_flag(-Wshorten-64-to-32) + handle_flag(-fstrict-aliasing) # Disable warnings regarding deprecated parts of the library while building # and testing those parts of the library. - add_cxx_compiler_flag(-Wno-deprecated-declarations) + handle_flag(-Wno-deprecated-declarations) if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel" OR CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") # Intel silently ignores '-Wno-deprecated-declarations', # warning no. 1786 must be explicitly disabled. # See #631 for rationale. - add_cxx_compiler_flag(-wd1786) - add_cxx_compiler_flag(-fno-finite-math-only) + handle_flag(-wd1786) + handle_flag(-fno-finite-math-only) endif() # Disable deprecation warnings for release builds (when -Werror is enabled). if(BENCHMARK_ENABLE_WERROR) - add_cxx_compiler_flag(-Wno-deprecated) + handle_flag(-Wno-deprecated) endif() if (NOT BENCHMARK_ENABLE_EXCEPTIONS) - add_cxx_compiler_flag(-fno-exceptions) + handle_flag(-fno-exceptions) endif() if (HAVE_CXX_FLAG_FSTRICT_ALIASING) if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel" AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") #ICC17u2: Many false positives for Wstrict-aliasing - add_cxx_compiler_flag(-Wstrict-aliasing) + handle_flag(-Wstrict-aliasing) endif() endif() # ICC17u2: overloaded virtual function "benchmark::Fixture::SetUp" is only partially overridden # (because of deprecated overload) - add_cxx_compiler_flag(-wd654) - add_cxx_compiler_flag(-Wthread-safety) + handle_flag(-wd654) + handle_flag(-Wthread-safety) if (HAVE_CXX_FLAG_WTHREAD_SAFETY) cxx_feature_check(THREAD_SAFETY_ATTRIBUTES "-DINCLUDE_DIRECTORIES=${PROJECT_SOURCE_DIR}/include") endif() @@ -246,8 +255,8 @@ else() # Link time optimisation if (BENCHMARK_ENABLE_LTO) - add_cxx_compiler_flag(-flto) - add_cxx_compiler_flag(-Wno-lto-type-mismatch) + handle_flag(-flto) + handle_flag(-Wno-lto-type-mismatch) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") find_program(GCC_AR gcc-ar) if (GCC_AR) @@ -278,7 +287,7 @@ else() BENCHMARK_SHARED_LINKER_FLAGS_COVERAGE) set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage.") - add_cxx_compiler_flag(--coverage COVERAGE) + handle_flag(--coverage COVERAGE) endif() if (BENCHMARK_USE_LIBCXX) From 57c4fa8c1221052867c679fbd4432f6114b7d74c Mon Sep 17 00:00:00 2001 From: Christopher Bate Date: Sun, 5 Oct 2025 11:10:46 -0600 Subject: [PATCH 2/2] Use a more effective approach to handling GCC compatible flags in GoogleBenchmark --- third-party/benchmark/CMakeLists.txt | 53 ++++++++----------- .../benchmark/cmake/AddCXXCompilerFlag.cmake | 39 +++++++++++--- 2 files changed, 54 insertions(+), 38 deletions(-) diff --git a/third-party/benchmark/CMakeLists.txt b/third-party/benchmark/CMakeLists.txt index 663793c1d4a91..d9bcc6a4939be 100644 --- a/third-party/benchmark/CMakeLists.txt +++ b/third-party/benchmark/CMakeLists.txt @@ -147,15 +147,6 @@ endif() set(CMAKE_CXX_STANDARD ${BENCHMARK_CXX_STANDARD}) set(CMAKE_CXX_STANDARD_REQUIRED YES) set(CMAKE_CXX_EXTENSIONS OFF) -option(BENCHMARK_ENABLE_EXPENSIVE_CMAKE_CHECKS "Enable use of expensive CMake checks for unused source files" ON) - -macro(handle_flag flag) - if(LLVM_COMPILER_IS_GCC_COMPATIBLE AND NOT BENCHMARK_ENABLE_EXPENSIVE_CMAKE_CHECKS) - list(APPEND CMAKE_CXX_FLAGS ${flag}) - else() - add_cxx_compiler_flag(${flag}) - endif() -endmacro() if (MSVC) # Turn compiler warnings up to 11 @@ -194,49 +185,49 @@ else() add_definitions(-D_LARGEFILE64_SOURCE) add_definitions(-D_LARGEFILE_SOURCE) # Turn compiler warnings up to 11 - handle_flag(-Wall) - handle_flag(-Wextra) - handle_flag(-Wshadow) - handle_flag(-Wfloat-equal) - handle_flag(-Wold-style-cast) + add_cxx_compiler_flag(-Wall) + add_cxx_compiler_flag(-Wextra) + add_cxx_compiler_flag(-Wshadow) + add_cxx_compiler_flag(-Wfloat-equal) + add_cxx_compiler_flag(-Wold-style-cast) if(BENCHMARK_ENABLE_WERROR) - handle_flag(-Werror) + add_cxx_compiler_flag(-Werror) endif() if (NOT BENCHMARK_ENABLE_TESTING) # Disable warning when compiling tests as gtest does not use 'override'. - handle_flag(-Wsuggest-override) + add_cxx_compiler_flag(-Wsuggest-override) endif() - handle_flag(-pedantic) - handle_flag(-pedantic-errors) - handle_flag(-Wshorten-64-to-32) - handle_flag(-fstrict-aliasing) + add_cxx_compiler_flag(-pedantic) + add_cxx_compiler_flag(-pedantic-errors) + add_cxx_compiler_flag(-Wshorten-64-to-32) + add_cxx_compiler_flag(-fstrict-aliasing) # Disable warnings regarding deprecated parts of the library while building # and testing those parts of the library. - handle_flag(-Wno-deprecated-declarations) + add_cxx_compiler_flag(-Wno-deprecated-declarations) if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel" OR CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") # Intel silently ignores '-Wno-deprecated-declarations', # warning no. 1786 must be explicitly disabled. # See #631 for rationale. - handle_flag(-wd1786) - handle_flag(-fno-finite-math-only) + add_cxx_compiler_flag(-wd1786) + add_cxx_compiler_flag(-fno-finite-math-only) endif() # Disable deprecation warnings for release builds (when -Werror is enabled). if(BENCHMARK_ENABLE_WERROR) - handle_flag(-Wno-deprecated) + add_cxx_compiler_flag(-Wno-deprecated) endif() if (NOT BENCHMARK_ENABLE_EXCEPTIONS) - handle_flag(-fno-exceptions) + add_cxx_compiler_flag(-fno-exceptions) endif() if (HAVE_CXX_FLAG_FSTRICT_ALIASING) if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel" AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "IntelLLVM") #ICC17u2: Many false positives for Wstrict-aliasing - handle_flag(-Wstrict-aliasing) + add_cxx_compiler_flag(-Wstrict-aliasing) endif() endif() # ICC17u2: overloaded virtual function "benchmark::Fixture::SetUp" is only partially overridden # (because of deprecated overload) - handle_flag(-wd654) - handle_flag(-Wthread-safety) + add_cxx_compiler_flag(-wd654) + add_cxx_compiler_flag(-Wthread-safety) if (HAVE_CXX_FLAG_WTHREAD_SAFETY) cxx_feature_check(THREAD_SAFETY_ATTRIBUTES "-DINCLUDE_DIRECTORIES=${PROJECT_SOURCE_DIR}/include") endif() @@ -255,8 +246,8 @@ else() # Link time optimisation if (BENCHMARK_ENABLE_LTO) - handle_flag(-flto) - handle_flag(-Wno-lto-type-mismatch) + add_cxx_compiler_flag(-flto) + add_cxx_compiler_flag(-Wno-lto-type-mismatch) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") find_program(GCC_AR gcc-ar) if (GCC_AR) @@ -287,7 +278,7 @@ else() BENCHMARK_SHARED_LINKER_FLAGS_COVERAGE) set(CMAKE_BUILD_TYPE "${CMAKE_BUILD_TYPE}" CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel Coverage.") - handle_flag(--coverage COVERAGE) + add_cxx_compiler_flag(--coverage COVERAGE) endif() if (BENCHMARK_USE_LIBCXX) diff --git a/third-party/benchmark/cmake/AddCXXCompilerFlag.cmake b/third-party/benchmark/cmake/AddCXXCompilerFlag.cmake index 858589e9775c6..1154311851f5d 100644 --- a/third-party/benchmark/cmake/AddCXXCompilerFlag.cmake +++ b/third-party/benchmark/cmake/AddCXXCompilerFlag.cmake @@ -27,20 +27,45 @@ function(mangle_compiler_flag FLAG OUTPUT) set(${OUTPUT} "${SANITIZED_FLAG}" PARENT_SCOPE) endfunction(mangle_compiler_flag) +set(BENCHMARK_GCC_COMPATIBLE_FLAGS + -fno-exceptions + -fstrict-aliasing + -pedantic + -pedantic-errors + -Wall + -Werror + -Wextra + -Wfloat-equal + -Wno-deprecated + -Wno-deprecated-declarations + -Wold-style-cast + -Wshadow + -Wstrict-aliasing + -Wsuggest-override + ) + +macro(_benchmark_populate_cxx_compiler_flag) + if(ARGC GREATER 1) + set(VARIANT ${ARGV1}) + string(TOUPPER "_${VARIANT}" VARIANT) + else() + set(VARIANT "") + endif() + set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${BENCHMARK_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE) +endmacro() + function(add_cxx_compiler_flag FLAG) mangle_compiler_flag("${FLAG}" MANGLED_FLAG) + if(LLVM_COMPILER_IS_GCC_COMPATIBLE AND "${FLAG}" IN_LIST BENCHMARK_GCC_COMPATIBLE_FLAGS) + _benchmark_populate_cxx_compiler_flag(${FLAG} ${VARIANT}) + return() + endif() set(OLD_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}") set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${FLAG}") check_cxx_compiler_flag("${FLAG}" ${MANGLED_FLAG}) set(CMAKE_REQUIRED_FLAGS "${OLD_CMAKE_REQUIRED_FLAGS}") if(${MANGLED_FLAG}) - if(ARGC GREATER 1) - set(VARIANT ${ARGV1}) - string(TOUPPER "_${VARIANT}" VARIANT) - else() - set(VARIANT "") - endif() - set(CMAKE_CXX_FLAGS${VARIANT} "${CMAKE_CXX_FLAGS${VARIANT}} ${BENCHMARK_CXX_FLAGS${VARIANT}} ${FLAG}" PARENT_SCOPE) + _benchmark_populate_cxx_compiler_flag(${FLAG} ${VARIANT}) endif() endfunction()