From 014e063a1037302f9d67d0eb03f1fcc6eb668f31 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 29 Apr 2023 23:09:10 +0100 Subject: [PATCH 1/3] cmake: Add `ProcessConfigurations.cmake` module --- CMakeLists.txt | 49 ++++-------------- cmake/ProcessConfigurations.cmake | 86 +++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 40 deletions(-) create mode 100644 cmake/ProcessConfigurations.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 3107eb3bf1..422c505962 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -161,18 +161,17 @@ option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." ON) option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." ${SECP256K1_VALGRIND}) option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF) +include(ProcessConfigurations) +set_default_config(RelWithDebInfo) + # Redefine configuration flags. # We leave assertions on, because they are only used in the examples, and we want them always on there. if(MSVC) - string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") - string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") - string(REGEX REPLACE "/DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") + remove_flag_from_all_configs(/DNDEBUG) else() - string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") - string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") - string(REGEX REPLACE "-DNDEBUG[ \t\r\n]*" "" CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") + remove_flag_from_all_configs(-DNDEBUG) # Prefer -O2 optimization level. (-O3 is CMake's default for Release for many compilers.) - string(REGEX REPLACE "-O3[ \t\r\n]*" "-O2" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") + replace_flag_in_config(Release -O3 -O2) endif() # Define custom "Coverage" build type. @@ -195,23 +194,10 @@ mark_as_advanced( ) get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -set(default_build_type "RelWithDebInfo") if(is_multi_config) - set(CMAKE_CONFIGURATION_TYPES "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" CACHE STRING - "Supported configuration types." - FORCE - ) + list(APPEND CMAKE_CONFIGURATION_TYPES Coverage) else() - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY - STRINGS "${default_build_type}" "Release" "Debug" "MinSizeRel" "Coverage" - ) - if(NOT CMAKE_BUILD_TYPE) - message(STATUS "Setting build type to \"${default_build_type}\" as none was specified") - set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING - "Choose the type of build." - FORCE - ) - endif() + set_property(CACHE CMAKE_BUILD_TYPE APPEND PROPERTY STRINGS Coverage) endif() include(TryAppendCFlags) @@ -312,24 +298,7 @@ message("CFLAGS ................................ ${CMAKE_C_FLAGS}") get_directory_property(compile_options COMPILE_OPTIONS) string(REPLACE ";" " " compile_options "${compile_options}") message("Compile options ....................... " ${compile_options}) -if(NOT is_multi_config) - message("Build type:") - message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}") - string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type) - message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_${build_type}}") - message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${build_type}}") - message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${build_type}}") -else() - message("Supported configurations .............. ${CMAKE_CONFIGURATION_TYPES}") - message("RelWithDebInfo configuration:") - message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_RELWITHDEBINFO}") - message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}") - message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO}") - message("Debug configuration:") - message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_DEBUG}") - message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}") - message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") -endif() +print_config_flags() message("\n") if(SECP256K1_EXPERIMENTAL) message( diff --git a/cmake/ProcessConfigurations.cmake b/cmake/ProcessConfigurations.cmake new file mode 100644 index 0000000000..57f75ec71b --- /dev/null +++ b/cmake/ProcessConfigurations.cmake @@ -0,0 +1,86 @@ +function(get_all_configs output) + get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(is_multi_config) + set(all_configs ${CMAKE_CONFIGURATION_TYPES}) + else() + get_property(all_configs CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS) + if(NOT all_configs) + # See https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#default-and-custom-configurations + set(all_configs Debug Release RelWithDebInfo MinSizeRel) + endif() + endif() + set(${output} "${all_configs}" PARENT_SCOPE) +endfunction() + +# When used with multi-configuration generators, this function rearranges +# the CMAKE_CONFIGURATION_TYPES list, ensuring that the default configuration type +# appears first while maintaining the order of the remaining configuration types. +function(set_default_config config) + get_all_configs(all_configs) + if(NOT ${config} IN_LIST all_configs) + message(FATAL_ERROR "The default config is \"${config}\", but must be one of ${all_configs}.") + endif() + + list(REMOVE_ITEM all_configs ${config}) + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.15) + list(PREPEND all_configs ${config}) + else() + set(all_configs ${config} ${all_configs}) + endif() + + get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(is_multi_config) + get_property(help_string CACHE CMAKE_CONFIGURATION_TYPES PROPERTY HELPSTRING) + set(CMAKE_CONFIGURATION_TYPES "${all_configs}" CACHE STRING "${help_string}" FORCE) + else() + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY + STRINGS "${all_configs}" + ) + if(NOT CMAKE_BUILD_TYPE) + message(STATUS "Setting build type to \"${config}\" as none was specified") + get_property(help_string CACHE CMAKE_BUILD_TYPE PROPERTY HELPSTRING) + set(CMAKE_BUILD_TYPE "${config}" CACHE STRING "${help_string}" FORCE) + endif() + endif() +endfunction() + +function(remove_flag_from_all_configs flag) + get_all_configs(all_configs) + foreach(config IN LISTS all_configs) + string(TOUPPER "${config}" config_uppercase) + set(flags "${CMAKE_C_FLAGS_${config_uppercase}}") + separate_arguments(flags) + list(FILTER flags EXCLUDE REGEX "${flag}") + list(JOIN flags " " new_flags) + set(CMAKE_C_FLAGS_${config_uppercase} "${new_flags}" PARENT_SCOPE) + endforeach() +endfunction() + +function(replace_flag_in_config config old_flag new_flag) + string(TOUPPER "${config}" config_uppercase) + string(REGEX REPLACE "(^| )${old_flag}( |$)" "\\1${new_flag}\\2" new_flags "${CMAKE_C_FLAGS_${config_uppercase}}") + set(CMAKE_C_FLAGS_${config_uppercase} "${new_flags}" PARENT_SCOPE) +endfunction() + +function(print_config_flags) + macro(print_flags config) + string(TOUPPER "${config}" config_uppercase) + message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_${config_uppercase}}") + message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${config_uppercase}}") + message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${config_uppercase}}") + endmacro() + + get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(is_multi_config) + list(JOIN CMAKE_CONFIGURATION_TYPES " " configs) + message("Supported configuration types ......... ${configs}") + foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES) + message("'${config}' configuration type:") + print_flags(${config}) + endforeach() + else() + message("Build type:") + message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}") + print_flags(${CMAKE_BUILD_TYPE}) + endif() +endfunction() From 4b3bd6654051173ef3093ee5f8d47e5c333858bb Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 29 Apr 2023 23:09:25 +0100 Subject: [PATCH 2/3] cmake: Use `SECP256K1_COVERAGE` instead of `CMAKE_BUILD_TYPE=Coverage` This change fixes coverage-enabled builds for multi-configuration generators, e.g., "Ninja Multi-Config". --- CMakeLists.txt | 48 +++++++++++++++++----------------------------- src/CMakeLists.txt | 4 ++-- 2 files changed, 20 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 422c505962..cacb997827 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -156,9 +156,20 @@ if(SECP256K1_VALGRIND) endif() option(SECP256K1_BUILD_BENCHMARK "Build benchmarks." ON) + +include(CMakeDependentOption) +cmake_dependent_option(SECP256K1_COVERAGE "Enable coverage analysis support." OFF "NOT MSVC" OFF) +include(TryAppendCFlags) +if(SECP256K1_COVERAGE) + add_compile_definitions(COVERAGE) + try_append_c_flags(-O0 --coverage) + add_link_options(--coverage) +endif() + option(SECP256K1_BUILD_TESTS "Build tests." ON) option(SECP256K1_BUILD_EXHAUSTIVE_TESTS "Build exhaustive tests." ON) option(SECP256K1_BUILD_CTIME_TESTS "Build constant-time tests." ${SECP256K1_VALGRIND}) + option(SECP256K1_BUILD_EXAMPLES "Build examples." OFF) include(ProcessConfigurations) @@ -170,37 +181,14 @@ if(MSVC) remove_flag_from_all_configs(/DNDEBUG) else() remove_flag_from_all_configs(-DNDEBUG) - # Prefer -O2 optimization level. (-O3 is CMake's default for Release for many compilers.) - replace_flag_in_config(Release -O3 -O2) -endif() - -# Define custom "Coverage" build type. -set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_RELWITHDEBINFO} -O0 -DCOVERAGE=1 --coverage" CACHE STRING - "Flags used by the C compiler during \"Coverage\" builds." - FORCE -) -set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING - "Flags used for linking binaries during \"Coverage\" builds." - FORCE -) -set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} --coverage" CACHE STRING - "Flags used by the shared libraries linker during \"Coverage\" builds." - FORCE -) -mark_as_advanced( - CMAKE_C_FLAGS_COVERAGE - CMAKE_EXE_LINKER_FLAGS_COVERAGE - CMAKE_SHARED_LINKER_FLAGS_COVERAGE -) - -get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(is_multi_config) - list(APPEND CMAKE_CONFIGURATION_TYPES Coverage) -else() - set_property(CACHE CMAKE_BUILD_TYPE APPEND PROPERTY STRINGS Coverage) + if(SECP256K1_COVERAGE) + remove_flag_from_all_configs(-O[s0-9]) + else() + # Prefer -O2 optimization level. (-O3 is CMake's default for Release for many compilers.) + replace_flag_in_config(Release -O3 -O2) + endif() endif() -include(TryAppendCFlags) if(MSVC) # Keep the following commands ordered lexicographically. try_append_c_flags(/W3) # Production quality warning level. @@ -275,7 +263,7 @@ message("Optional binaries:") message(" benchmark ........................... ${SECP256K1_BUILD_BENCHMARK}") message(" noverify_tests ...................... ${SECP256K1_BUILD_TESTS}") set(tests_status "${SECP256K1_BUILD_TESTS}") -if(CMAKE_BUILD_TYPE STREQUAL "Coverage") +if(SECP256K1_COVERAGE) set(tests_status OFF) endif() message(" tests ............................... ${tests_status}") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0bba19982a..08015eb0d5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -88,7 +88,7 @@ if(SECP256K1_BUILD_TESTS) add_executable(noverify_tests tests.c) target_link_libraries(noverify_tests secp256k1_precomputed secp256k1_asm) add_test(NAME noverify_tests COMMAND noverify_tests) - if(NOT CMAKE_BUILD_TYPE STREQUAL "Coverage") + if(NOT SECP256K1_COVERAGE) add_executable(tests tests.c) target_compile_definitions(tests PRIVATE VERIFY) target_link_libraries(tests secp256k1_precomputed secp256k1_asm) @@ -100,7 +100,7 @@ if(SECP256K1_BUILD_EXHAUSTIVE_TESTS) # Note: do not include secp256k1_precomputed in exhaustive_tests (it uses runtime-generated tables). add_executable(exhaustive_tests tests_exhaustive.c) target_link_libraries(exhaustive_tests secp256k1_asm) - target_compile_definitions(exhaustive_tests PRIVATE $<$>:VERIFY>) + target_compile_definitions(exhaustive_tests PRIVATE $<$>:VERIFY>) add_test(NAME exhaustive_tests COMMAND exhaustive_tests) endif() From 94dd0c0b99a9255378f07d95a57dd55d68ffb22e Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Sat, 29 Apr 2023 23:09:36 +0100 Subject: [PATCH 3/3] autotools, docs: Adjust help string for `--enable-coverage` option --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 82cf95132d..ef954f92da 100644 --- a/configure.ac +++ b/configure.ac @@ -151,7 +151,7 @@ AC_ARG_ENABLE(benchmark, [SECP_SET_DEFAULT([enable_benchmark], [yes], [yes])]) AC_ARG_ENABLE(coverage, - AS_HELP_STRING([--enable-coverage],[enable compiler flags to support kcov coverage analysis [default=no]]), [], + AS_HELP_STRING([--enable-coverage],[enable coverage analysis support [default=no]]), [], [SECP_SET_DEFAULT([enable_coverage], [no], [no])]) AC_ARG_ENABLE(tests,