From 304e9aee1e8fb265be78163578c45ae22569e52b Mon Sep 17 00:00:00 2001 From: Abdessattar Sassi <457645+abdes@users.noreply.github.com> Date: Wed, 21 Sep 2022 13:34:59 +0400 Subject: [PATCH] feat: more robust handling of contract checking mode When linking against the contract checking and enforcement library `asap-contract` (https://github.com/asap-projects/asap-contract), it is possible to control the contract checking mode by passing a value for the `CONTRACTS` option when adding any type of target with `asap_add_xxx` API (e.g. asap_add_library. asap_add_test, etc): * CONTRACTS OFF : set contract checking mode to OFF * CONTRACTS AUDIT : set contract checking mode to AUDIT * CONTRACTS DEFAULT : set contract checking mode to DEFAULT * CONTRACTS AUTO : set contract checking mode using as a first priority the value passed in the cmake option `OPTION_CONTRACT_MODE`. If none is present, automatically set the mode based on the build configuration. For Debug -> AUDIT, For Release and RelMinSize -> OFF, and for RelWithDebInfo -> DEFAULT. * CONTRACTS TESTING : indicates that contracts are being testing and the target needs to have full control on the contract checking mode. Nothing will be done here. The default setting is AUTO. --- cmake/AsapTargets.cmake | 40 ++++++++++--- cmake/CompileDefinitions.cmake | 106 ++++++++++++++++++++++++--------- cmake/TestTargets.cmake | 20 +++++-- 3 files changed, 125 insertions(+), 41 deletions(-) diff --git a/cmake/AsapTargets.cmake b/cmake/AsapTargets.cmake index 6c605bf..0b1e0a5 100644 --- a/cmake/AsapTargets.cmake +++ b/cmake/AsapTargets.cmake @@ -111,7 +111,13 @@ endfunction() # ------------------------------------------------------------------------------ function(asap_add_library target) - swift_add_library("${target}" ${ARGN}) + set(argOption "") + set(argSingle "CONTRACTS") + set(argMulti "") + unset(x_CONTRACTS) + cmake_parse_arguments(x "${argOption}" "${argSingle}" "${argMulti}" ${ARGN}) + + swift_add_library("${target}" ${x_UNPARSED_ARGUMENTS}) # We can refer to this target either with its standalone target name or with a # project scoped name (::) which we will alias to the target @@ -120,7 +126,7 @@ function(asap_add_library target) get_target_property(type ${target} TYPE) if(NOT ${type} STREQUAL "INTERFACE_LIBRARY") # Set some common private compiler defines - asap_set_compile_definitions(${target}) + asap_set_compile_definitions(${target} CONTRACTS ${x_CONTRACTS}) # Set some common compiler options asap_set_compile_options(${target}) # Generate export headers for the library @@ -138,27 +144,45 @@ function(asap_add_library target) endfunction() function(asap_add_executable target) - swift_add_executable("${target}" ${ARGN}) + set(argOption "") + set(argSingle "CONTRACTS") + set(argMulti "") + unset(x_CONTRACTS) + cmake_parse_arguments(x "${argOption}" "${argSingle}" "${argMulti}" ${ARGN}) + + swift_add_executable("${target}" ${x_UNPARSED_ARGUMENTS}) # Set some common private compiler defines - asap_set_compile_definitions(${target}) + asap_set_compile_definitions(${target} CONTRACTS ${x_CONTRACTS}) # Set some common compiler options asap_set_compile_options(${target}) set_target_properties(${target} PROPERTIES FOLDER "Executables") endfunction() function(asap_add_tool target) - swift_add_tool("${target}" ${ARGN}) + set(argOption "") + set(argSingle "CONTRACTS") + set(argMulti "") + unset(x_CONTRACTS) + cmake_parse_arguments(x "${argOption}" "${argSingle}" "${argMulti}" ${ARGN}) + + swift_add_tool("${target}" ${x_UNPARSED_ARGUMENTS}) # Set some common private compiler defines - asap_set_compile_definitions(${target}) + asap_set_compile_definitions(${target} CONTRACTS ${x_CONTRACTS}) # Set some common compiler options asap_set_compile_options(${target}) set_target_properties(${target} PROPERTIES FOLDER "Tools") endfunction() function(asap_add_tool_library target) - swift_add_tool_library("${target}" ${ARGN}) + set(argOption "") + set(argSingle "CONTRACTS") + set(argMulti "") + unset(x_CONTRACTS) + cmake_parse_arguments(x "${argOption}" "${argSingle}" "${argMulti}" ${ARGN}) + + swift_add_tool_library("${target}" ${x_UNPARSED_ARGUMENTS}) # Set some common private compiler defines - asap_set_compile_definitions(${target}) + asap_set_compile_definitions(${target} CONTRACTS ${x_CONTRACTS}) # Set some common compiler options asap_set_compile_options(${target}) set_target_properties( diff --git a/cmake/CompileDefinitions.cmake b/cmake/CompileDefinitions.cmake index 8f35cfd..0087236 100644 --- a/cmake/CompileDefinitions.cmake +++ b/cmake/CompileDefinitions.cmake @@ -7,64 +7,112 @@ include_guard(GLOBAL) # ------------------------------------------------------------------------------ -# Set a common set of compile definitions +# Set a common set of compile definitions. +# +# Compile definitions can be removed from the default set by passing REMOVE +# followed by a list of symbols, eg: +# +# asap_set_compile_definitions(sample-target REMOVE _CRT_SECURE_NO_WARNINGS) +# +# will prevent `_CRT_SECURE_NO_WARNINGS` from being passed to the compiler as a +# defined symbol for sample-target only. +# +# Similarly extra definitions can be added by passing ADD followed by a list of +# symbols (or definitions in the form of symbol=value), eg: +# +# asap_set_compile_definitions(sample-target ADD SUPER HERO=2) +# +# will pass SUPER and HERO=2 to the compiler as definitions for sample-target +# only. +# +# When linking against the contract checking and enforcement library +# `asap-contract` (https://github.com/asap-projects/asap-contract), it is +# possible to control the contract checking mode by passing a value for the +# `CONTRACTS` option to this function as follows: +# +# * CONTRACTS OFF : set contract checking mode to OFF +# * CONTRACTS AUDIT : set contract checking mode to AUDIT +# * CONTRACTS DEFAULT : set contract checking mode to DEFAULT +# +# * CONTRACTS AUTO : set contract checking mode using as a first priority the +# value passed in the cmake option `OPTION_CONTRACT_MODE`. If none is present, +# automatically set the mode based on the build configuration. For Debug -> +# AUDIT, For Release and RelMinSize -> OFF, and for RelWithDebInfo -> DEFAULT. +# +# * CONTRACTS TESTING : indicates that contracts are being testing and the +# target needs to have full control on the contract checking mode. Nothing +# will be done here. +# +# The default setting is AUTO. # ------------------------------------------------------------------------------ function(asap_set_compile_definitions target) - set(argOption "NO_CONTRACT") - set(argSingle "") + set(argOption "") + set(argSingle "CONTRACTS") set(argMulti "ADD" "REMOVE") - unset(x_WARNING) + unset(x_CONTRACTS) unset(x_ADD) unset(x_REMOVE) cmake_parse_arguments(x "${argOption}" "${argSingle}" "${argMulti}" ${ARGN}) + if(NOT DEFINED x_CONTRACTS OR x_CONTRACTS STREQUAL "") + set(x_CONTRACTS "AUTO") + endif() - set(all_flags) + set(all_definitions) # Provide a way to distinguish between debug and release builds via # preprocessor define - list(APPEND all_flags "$<$:ASAP_IS_DEBUG_BUILD>") + list(APPEND all_definitions "$<$:ASAP_IS_DEBUG_BUILD>") if(MSVC) - list(APPEND all_flags "NOMINMAX" "WIN32_LEAN_AND_MEAN=1" + list(APPEND all_definitions "NOMINMAX" "WIN32_LEAN_AND_MEAN=1" "_WIN32_WINNT=0x0600") # Disabling warning for not using "secure-but-not-standard" STL algos - list(APPEND all_flags "_CRT_SECURE_NO_WARNINGS" "_SCL_SECURE_NO_WARNINGS") + list(APPEND all_definitions "_CRT_SECURE_NO_WARNINGS" + "_SCL_SECURE_NO_WARNINGS") endif() if(x_REMOVE) - foreach(flag ${x_REMOVE}) - list(FIND all_flags ${flag} found) + foreach(definition ${x_REMOVE}) + list(FIND all_definitions ${definition} found) if(found EQUAL -1) message( FATAL_ERROR - "Compiler flag '${flag}' specified for removal is not part of the set of common - compiler flags") + "Compiler definition '${definition}' specified for removal is not " + "part of the set of common compiler definitions.") endif() endforeach() - list(REMOVE_ITEM all_flags ${x_REMOVE}) + list(REMOVE_ITEM all_definitions ${x_REMOVE}) endif() - list(APPEND all_flags ${x_ADD}) - target_compile_definitions(${target} PRIVATE ${all_flags}) + list(APPEND all_definitions ${x_ADD}) + + target_compile_definitions(${target} PRIVATE ${all_definitions}) - # If linking against asap_contract, set the contract mode based on the build - # type. Use generator expressions only, do not check for CMAKE_BUILD_TYPE - # which is not friendly with multi-config generators. - # - # Do not add this definition if we are testing asap-_contract - if(TARGET asap_contract AND NOT ASAP_CONTRACT_TESTING) - if(NOT DEFINED OPTION_CONTRACT_MODE) - target_compile_definitions( - ${target} - PRIVATE $<$:ASAP_CONTRACT_AUDIT> - $<$:ASAP_CONTRACT_DEFAULT> - $<$:ASAP_CONTRACT_OFF>) + # If linking against asap_contract, set the contract checking mode. Use + # generator expressions only, do not check for CMAKE_BUILD_TYPE which is not + # friendly with multi-config generators. + if(NOT x_CONTRACTS STREQUAL "TESTING") + if(x_CONTRACTS MATCHES "OFF|AUDIT|DEFAULT") + target_compile_definitions(${target} + PRIVATE "ASAP_CONTRACT_${x_CONTRACTS}") + elseif(x_CONTRACTS STREQUAL "AUTO") + if(NOT DEFINED OPTION_CONTRACT_MODE) + target_compile_definitions( + ${target} + PRIVATE $<$:ASAP_CONTRACT_AUDIT> + $<$:ASAP_CONTRACT_DEFAULT> + $<$:ASAP_CONTRACT_OFF>) + else() + target_compile_definitions( + ${target} PRIVATE "ASAP_CONTRACT_${OPTION_CONTRACT_MODE}") + endif() else() - target_compile_definitions( - ${target} PRIVATE "ASAP_CONTRACT_${OPTION_CONTRACT_MODE}") + message( + FATAL_ERROR "Contract mode '${x_CONTRACTS}' is not valid." + "Valid values are: OFF, DEFAULT, AUDIT, AUTO and TESTING.") endif() endif() endfunction() diff --git a/cmake/TestTargets.cmake b/cmake/TestTargets.cmake index 27ee346..8db2888 100644 --- a/cmake/TestTargets.cmake +++ b/cmake/TestTargets.cmake @@ -7,9 +7,15 @@ include(common/TestTargets) macro(asap_add_test target) - swift_add_test("${target}" ${ARGN}) + set(argOption "") + set(argSingle "CONTRACTS") + set(argMulti "") + unset(x_CONTRACTS) + cmake_parse_arguments(x "${argOption}" "${argSingle}" "${argMulti}" ${ARGN}) + + swift_add_test("${target}" ${x_UNPARSED_ARGUMENTS}) # Set some common private compiler defines - asap_set_compile_definitions(${target}) + asap_set_compile_definitions(${target} CONTRACTS ${x_CONTRACTS}) # Set some common compiler options asap_set_compile_options(${target}) if(TARGET gtest AND BUILD_SHARED_LIBS) @@ -31,9 +37,15 @@ macro(asap_add_test_runner target) endmacro() function(asap_add_test_library target) - swift_add_test_library("${target}" ${ARGN}) + set(argOption "") + set(argSingle "CONTRACTS") + set(argMulti "") + unset(x_CONTRACTS) + cmake_parse_arguments(x "${argOption}" "${argSingle}" "${argMulti}" ${ARGN}) + + swift_add_test_library("${target}" ${x_UNPARSED_ARGUMENTS}) # Set some common private compiler defines - asap_set_compile_definitions(${target}) + asap_set_compile_definitions(${target} CONTRACTS ${x_CONTRACTS}) # Set some common compiler options asap_set_compile_options(${target}) set_target_properties(