Skip to content

Commit

Permalink
feat: more robust handling of contract checking mode
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
abdes committed Sep 21, 2022
1 parent a5f4c22 commit 304e9ae
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 41 deletions.
40 changes: 32 additions & 8 deletions cmake/AsapTargets.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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 (<project>::<module>) which we will alias to the target
Expand All @@ -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
Expand All @@ -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(
Expand Down
106 changes: 77 additions & 29 deletions cmake/CompileDefinitions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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 "$<$<CONFIG:Debug>:ASAP_IS_DEBUG_BUILD>")
list(APPEND all_definitions "$<$<CONFIG:Debug>: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 $<$<CONFIG:Debug>:ASAP_CONTRACT_AUDIT>
$<$<CONFIG:RelWithDebInfo>:ASAP_CONTRACT_DEFAULT>
$<$<CONFIG:Release,RelMinSize>: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 $<$<CONFIG:Debug>:ASAP_CONTRACT_AUDIT>
$<$<CONFIG:RelWithDebInfo>:ASAP_CONTRACT_DEFAULT>
$<$<CONFIG:Release,RelMinSize>: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()
20 changes: 16 additions & 4 deletions cmake/TestTargets.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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(
Expand Down

0 comments on commit 304e9ae

Please sign in to comment.