1 2# Copyright (C) 2011-2020 Daniel Scharrer 3# 4# This software is provided 'as-is', without any express or implied 5# warranty. In no event will the author(s) be held liable for any damages 6# arising from the use of this software. 7# 8# Permission is granted to anyone to use this software for any purpose, 9# including commercial applications, and to alter it and redistribute it 10# freely, subject to the following restrictions: 11# 12# 1. The origin of this software must not be misrepresented; you must not 13# claim that you wrote the original software. If you use this software 14# in a product, an acknowledgment in the product documentation would be 15# appreciated but is not required. 16# 2. Altered source versions must be plainly marked as such, and must not be 17# misrepresented as being the original software. 18# 3. This notice may not be removed or altered from any source distribution. 19 20# Note: In CMake before 3.0 set(var "" PARENT_SCOPE) *unsets* the variable in the 21# parent scope instead of setting it to the empty string. 22# This means if(var STREQUAL "") will be false since var is not defined and thus not expanded. 23 24function(check_compile RESULT FILE FLAG TYPE) 25 26 string(REGEX REPLACE "[^a-zA-Z0-9_][^a-zA-Z0-9_]*" "-" cachevar "${TYPE}-${FLAG}") 27 set(cahevar "CHECK_COMPILE_${cahevar}") 28 29 if(DEFINED ${cachevar}) 30 if(${cachevar}) 31 set(${RESULT} "${FLAG}" PARENT_SCOPE) 32 else() 33 set(${RESULT} "" PARENT_SCOPE) 34 endif() 35 return() 36 endif() 37 38 string(REGEX REPLACE "[^a-zA-Z0-9]" "\\\\\\0" escaped_flag ${FLAG} ) 39 40 # CMake already has a check_cxx_compiler_flag macro in CheckCXXCompilerFlag, but 41 # it prints the result variable in the output (which is ugly!) and also uses it 42 # as a key to cache checks - so it would need to be unique for each flag. 43 # Unfortunately it also naively pastes the variable name inside a regexp so 44 # if we tried to use the flag itself in the variable name it will fail for -std=c++11. 45 # But we can at least use the expressions for warnings from that macro (and more): 46 set(fail_regexps 47 "warning:" # general 48 "unrecognized .*option" # GNU 49 "${escaped_flag}.* not supported" # GNU 50 "unknown .*option" # Clang 51 "ignoring unknown option" # MSVC 52 "warning D9002" # MSVC, any lang 53 "warning #[0-9]*:" # Intel 54 "option.*not supported" # Intel 55 "invalid argument .*option" # Intel 56 "ignoring option .*argument required" # Intel 57 "command line warning" # Intel 58 "[Uu]nknown option" # HP 59 "[Ww]arning: [Oo]ption" # SunPro 60 "command option .* is not recognized" # XL 61 "not supported in this configuration; ignored" # AIX 62 "File with unknown suffix passed to linker" # PGI 63 "WARNING: unknown flag:" # Open64 64 ) 65 66 # Set the flags to check 67 set(old_CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 68 set(old_CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") 69 set(old_CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}") 70 set(old_CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS}") 71 if(TYPE STREQUAL "linker flag") 72 set(CMAKE_EXE_LINKER_FLAGS "${old_CMAKE_EXE_LINKER_FLAGS} ${FLAG}") 73 set(CMAKE_SHARED_LINKER_FLAGS "${old_CMAKE_SHARED_LINKER_FLAGS} ${FLAG}") 74 set(CMAKE_MODULE_LINKER_FLAGS "${old_CMAKE_MODULE_LINKER_FLAGS} ${FLAG}") 75 elseif(TYPE STREQUAL "compiler flag") 76 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAG}") 77 endif() 78 79 # Check if we can compile and link a simple file with the new flags 80 try_compile( 81 check_compiler_flag ${PROJECT_BINARY_DIR} ${FILE} 82 CMAKE_FLAGS "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}" 83 "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}" 84 "-DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS}" 85 "-DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_MODULE_LINKER_FLAGS}" 86 OUTPUT_VARIABLE ERRORLOG 87 ) 88 89 # Restore the old flags 90 set(CMAKE_CXX_FLAGS "${old_CMAKE_CXX_FLAGS}") 91 set(CMAKE_EXE_LINKER_FLAGS "${old_CMAKE_EXE_LINKER_FLAGS}") 92 set(CMAKE_SHARED_LINKER_FLAGS "${old_CMAKE_SHARED_LINKER_FLAGS}") 93 set(CMAKE_MODULE_LINKER_FLAGS "${old_CMAKE_MODULE_LINKER_FLAGS}") 94 95 if(NOT check_compiler_flag) 96 message(STATUS "Checking ${TYPE}: ${FLAG} - unsupported") 97 set(${RESULT} "" PARENT_SCOPE) 98 set("${cachevar}" 0 CACHE INTERNAL "...") 99 else() 100 101 set(has_warning 0) 102 foreach(expr IN LISTS fail_regexps) 103 if("${ERRORLOG}" MATCHES "${expr}") 104 set(has_warning 1) 105 endif() 106 endforeach() 107 108 if(has_warning) 109 message(STATUS "Checking ${TYPE}: ${FLAG} - unsupported (warning)") 110 set(${RESULT} "" PARENT_SCOPE) 111 set("${cachevar}" 0 CACHE INTERNAL "...") 112 else() 113 message(STATUS "Checking ${TYPE}: ${FLAG}") 114 set(${RESULT} "${FLAG}" PARENT_SCOPE) 115 set("${cachevar}" 1 CACHE INTERNAL "...") 116 endif() 117 118 endif() 119 120endfunction(check_compile) 121 122function(check_flag RESULT FLAG TYPE) 123 set(compile_test_file "${CMAKE_CURRENT_BINARY_DIR}/compile_flag_test.cpp") 124 if(MSVC) 125 file(WRITE ${compile_test_file} "int main(){ return 0; }\n") 126 else() 127 file(WRITE ${compile_test_file} "__attribute__((const)) int main(){ return 0; }\n") 128 endif() 129 check_compile(result "${compile_test_file}" "${FLAG}" "${TYPE} flag") 130 set(${RESULT} "${result}" PARENT_SCOPE) 131endfunction(check_flag) 132 133macro(strip_warning_flags VAR) 134 string(REGEX REPLACE "(^| )\\-(W[^ l][^ ]*|Wl[^,][^ ]*|pedantic)" "" ${VAR} "${${VAR}}") 135endmacro() 136 137function(check_builtin RESULT EXPR) 138 string(REGEX REPLACE "[^a-zA-Z0-9_][^a-zA-Z0-9_]*" "-" check "${EXPR}") 139 string(REGEX REPLACE "_*\\-_*" "-" check "${check}") 140 string(REGEX REPLACE "^[_\\-]+" "" check "${check}") 141 string(REGEX REPLACE "[_\\-]+$" "" check "${check}") 142 set(compile_test_file "${CMAKE_CURRENT_BINARY_DIR}/check-builtin-${check}.cpp") 143 string(REGEX MATCH "[a-zA-Z_][a-zA-Z_0-9]*" type "${EXPR}") 144 file(WRITE ${compile_test_file} "__attribute__((const)) int main(){ (void)(${EXPR}); return 0; }\n") 145 set(old_CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 146 set(old_CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") 147 strip_warning_flags(CMAKE_CXX_FLAGS) 148 strip_warning_flags(CMAKE_EXE_LINKER_FLAGS) 149 check_compile(result "${compile_test_file}" "${type}" "compiler builtin") 150 set(CMAKE_CXX_FLAGS "${old_CMAKE_CXX_FLAGS}") 151 set(CMAKE_EXE_LINKER_FLAGS "${old_CMAKE_EXE_LINKER_FLAGS}") 152 set(${RESULT} "${result}" PARENT_SCOPE) 153endfunction(check_builtin) 154 155function(check_compiler_flag RESULT FLAG) 156 check_flag(result "${FLAG}" compiler) 157 set(${RESULT} "${result}" PARENT_SCOPE) 158endfunction(check_compiler_flag) 159 160function(check_linker_flag RESULT FLAG) 161 check_flag(result "${FLAG}" linker) 162 set(${RESULT} "${result}" PARENT_SCOPE) 163endfunction(check_linker_flag) 164 165function(add_cxxflag FLAG) 166 167 check_compiler_flag(RESULT "${FLAG}") 168 169 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RESULT}" PARENT_SCOPE) 170 171 if(NOT DEFINED RESULT OR RESULT STREQUAL "") 172 set(FLAG_FOUND 0 PARENT_SCOPE) 173 else() 174 set(FLAG_FOUND 1 PARENT_SCOPE) 175 endif() 176 177endfunction(add_cxxflag) 178 179function(add_ldflag FLAG) 180 181 check_linker_flag(RESULT "${FLAG}") 182 183 set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${RESULT}" PARENT_SCOPE) 184 set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${RESULT}" PARENT_SCOPE) 185 set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${RESULT}" PARENT_SCOPE) 186 187 if(NOT DEFINED RESULT OR RESULT STREQUAL "") 188 set(FLAG_FOUND 0 PARENT_SCOPE) 189 else() 190 set(FLAG_FOUND 1 PARENT_SCOPE) 191 endif() 192 193endfunction(add_ldflag) 194