diff --git a/cmake/modules/AddCompilerFlags.cmake b/cmake/modules/AddCompilerFlags.cmake index 44aad8f6e0..b03d8bfad5 100644 --- a/cmake/modules/AddCompilerFlags.cmake +++ b/cmake/modules/AddCompilerFlags.cmake @@ -1,71 +1,85 @@ # Allow to easily add flags for C and C++ include(CheckCXXCompilerFlag) include(CheckCCompilerFlag) +include(SanitizeHelper) + +function(check_compiler_flag RESULT LANGUAGE FLAG) + sanitize_variable("have_${LANGUAGE}_" ${FLAG} TEST_NAME) + + if("${LANGUAGE}" STREQUAL "C") + CHECK_C_COMPILER_FLAG(${FLAG} ${TEST_NAME}) + elseif("${LANGUAGE}" STREQUAL "CXX") + CHECK_CXX_COMPILER_FLAG(${FLAG} ${TEST_NAME}) + else() + message(FATAL_ERROR "check_compiler_flag LANGUAGE should be C or CXX") + endif() + set(${RESULT} ${${TEST_NAME}} PARENT_SCOPE) +endfunction() function(add_c_compiler_flag) foreach(f ${ARGN}) - CHECK_C_COMPILER_FLAG(${f} FLAG_IS_SUPPORTED) - if(FLAG_IS_SUPPORTED) + check_compiler_flag(FLAG_IS_SUPPORTED C ${f}) + if(${FLAG_IS_SUPPORTED}) string(APPEND CMAKE_C_FLAGS " ${f}") endif() endforeach() set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} PARENT_SCOPE) endfunction() function(add_cxx_compiler_flag) foreach(f ${ARGN}) - CHECK_CXX_COMPILER_FLAG(${f} FLAG_IS_SUPPORTED) - if(FLAG_IS_SUPPORTED) + check_compiler_flag(FLAG_IS_SUPPORTED CXX ${f}) + if(${FLAG_IS_SUPPORTED}) string(APPEND CMAKE_CXX_FLAGS " ${f}") endif() endforeach() set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} PARENT_SCOPE) endfunction() macro(add_compiler_flag) add_c_compiler_flag(${ARGN}) add_cxx_compiler_flag(${ARGN}) endmacro() macro(remove_c_compiler_flags) if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "") string(TOUPPER ${CMAKE_BUILD_TYPE} BUILD_TYPE) set(BUILD_TYPE_C_FLAGS "CMAKE_C_FLAGS_${BUILD_TYPE}") endif() foreach(f ${ARGN}) string(REGEX REPLACE "${f}( |$)" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "") string(REGEX REPLACE "${f}( |$)" "" ${BUILD_TYPE_C_FLAGS} "${${BUILD_TYPE_C_FLAGS}}") endif() endforeach() endmacro() macro(remove_cxx_compiler_flags) if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "") string(TOUPPER ${CMAKE_BUILD_TYPE} BUILD_TYPE) set(BUILD_TYPE_CXX_FLAGS "CMAKE_CXX_FLAGS_${BUILD_TYPE}") endif() foreach(f ${ARGN}) string(REGEX REPLACE "${f}( |$)" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") if(NOT "${CMAKE_BUILD_TYPE}" STREQUAL "") string(REGEX REPLACE "${f}( |$)" "" ${BUILD_TYPE_CXX_FLAGS} "${${BUILD_TYPE_CXX_FLAGS}}") endif() endforeach() endmacro() macro(remove_compiler_flags) remove_c_compiler_flags(${ARGN}) remove_cxx_compiler_flags(${ARGN}) endmacro() # Note that CMake does not provide any facility to check that a linker flag is # supported by the compiler, but most linker will just drop any unsupported flag # (eventually with a warning). function(add_linker_flag) foreach(f ${ARGN}) string(APPEND CMAKE_EXE_LINKER_FLAGS " ${f}") endforeach() set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} PARENT_SCOPE) endfunction() diff --git a/cmake/modules/SanitizeHelper.cmake b/cmake/modules/SanitizeHelper.cmake new file mode 100644 index 0000000000..6677cc41e6 --- /dev/null +++ b/cmake/modules/SanitizeHelper.cmake @@ -0,0 +1,19 @@ +# Sanitize a variable according to cmake rules +# https://cmake.org/cmake/help/v3.10/manual/cmake-language.7.html#variable-references +# The NUL and ';' characters cannot be escaped in this context (see CMP0053) +macro(sanitize_variable PREFIX RAW_VAR SANITIZED_VAR) + # Escaping characters not in the supported list (see documentation) will + # work as long as the variable is not cached. + + # Variable caching is achieved by writing the variable to a CMakeCache.txt + # file, where the escaped chars get interpreted. The issue occurs when the + # cache is read, as the chars are not getting escaped again and cause the + # read to fail. + + # The safe way to sanitize a variable is not to escape these chars, but + # rather to replace them with a known supported one, here '_' is chosen. + # Not: this could lead to name collision in some rare case. These case can + # be handled manually by using a different prefix. + string(REGEX REPLACE + "([^a-zA-Z0-9/_.+-])" "_" ${SANITIZED_VAR} "${PREFIX}${RAW_VAR}") +endmacro()