ranges_flags.cmake 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. # Copyright Louis Dionne 2015
  2. # Copyright Gonzalo Brito Gadeschi 2015
  3. # Distributed under the Boost Software License, Version 1.0.
  4. # (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  5. #
  6. # Setup compiler flags (more can be set on a per-target basis or in
  7. # subdirectories)
  8. # Compilation flags
  9. include(CheckCXXCompilerFlag)
  10. macro(ranges_append_flag testname flag)
  11. # As -Wno-* flags do not lead to build failure when there are no other
  12. # diagnostics, we check positive option to determine their applicability.
  13. # Of course, we set the original flag that is requested in the parameters.
  14. string(REGEX REPLACE "^-Wno-" "-W" alt ${flag})
  15. check_cxx_compiler_flag(${alt} ${testname})
  16. if (${testname})
  17. add_compile_options(${flag})
  18. endif()
  19. endmacro()
  20. function(cxx_standard_normalize cxx_standard return_value)
  21. if("x${cxx_standard}" STREQUAL "x1y")
  22. set( ${return_value} "14" PARENT_SCOPE )
  23. elseif("x${cxx_standard}" STREQUAL "x1z")
  24. set( ${return_value} "17" PARENT_SCOPE )
  25. elseif("x${cxx_standard}" STREQUAL "xlatest" OR "x${cxx_standard}" STREQUAL "x2a")
  26. set( ${return_value} "20" PARENT_SCOPE )
  27. else()
  28. set( ${return_value} "${cxx_standard}" PARENT_SCOPE )
  29. endif()
  30. endfunction()
  31. function(cxx_standard_denormalize cxx_standard return_value)
  32. if("x${cxx_standard}" STREQUAL "x17")
  33. if (RANGES_CXX_COMPILER_CLANGCL OR RANGES_CXX_COMPILER_MSVC)
  34. set( ${return_value} 17 PARENT_SCOPE )
  35. else()
  36. set( ${return_value} 1z PARENT_SCOPE )
  37. endif()
  38. elseif("x${cxx_standard}" STREQUAL "x20")
  39. if (RANGES_CXX_COMPILER_CLANGCL OR RANGES_CXX_COMPILER_MSVC)
  40. set( ${return_value} latest PARENT_SCOPE )
  41. else()
  42. set( ${return_value} 2a PARENT_SCOPE )
  43. endif()
  44. else()
  45. set( ${return_value} ${cxx_standard} PARENT_SCOPE )
  46. endif()
  47. endfunction()
  48. if(CMAKE_CXX_STANDARD)
  49. if(NOT "x${RANGES_CXX_STD}" STREQUAL "xdefault")
  50. # Normalize RANGES_CXX_STD
  51. cxx_standard_normalize( ${RANGES_CXX_STD} ranges_cxx_std )
  52. if(NOT "x${ranges_cxx_std}" STREQUAL "x${CMAKE_CXX_STANDARD}")
  53. message(FATAL_ERROR "[range-v3]: Cannot specify both CMAKE_CXX_STANDARD and RANGES_CXX_STD, or they must match.")
  54. endif()
  55. else()
  56. cxx_standard_denormalize(${CMAKE_CXX_STANDARD} RANGES_CXX_STD)
  57. endif()
  58. elseif("x${RANGES_CXX_STD}" STREQUAL "xdefault")
  59. if (RANGES_CXX_COMPILER_CLANGCL OR RANGES_CXX_COMPILER_MSVC)
  60. set(RANGES_CXX_STD 17)
  61. else()
  62. set(RANGES_CXX_STD 14)
  63. endif()
  64. endif()
  65. # All compilation flags
  66. # Language flag: version of the C++ standard to use
  67. message(STATUS "[range-v3]: C++ std=${RANGES_CXX_STD}")
  68. if (RANGES_CXX_COMPILER_CLANGCL OR RANGES_CXX_COMPILER_MSVC)
  69. ranges_append_flag(RANGES_HAS_CXXSTDCOLON "/std:c++${RANGES_CXX_STD}")
  70. set(RANGES_STD_FLAG "/std:c++${RANGES_CXX_STD}")
  71. if (RANGES_CXX_COMPILER_CLANGCL)
  72. # The MSVC STL before VS 2019v16.6 with Clang 10 requires -fms-compatibility in C++17 mode, and
  73. # doesn't support C++20 mode at all. Let's drop this flag until AppVeyor updates to VS2016v16.6.
  74. # ranges_append_flag(RANGES_HAS_FNO_MS_COMPATIBIILITY "-fno-ms-compatibility")
  75. ranges_append_flag(RANGES_HAS_FNO_DELAYED_TEMPLATE_PARSING "-fno-delayed-template-parsing")
  76. endif()
  77. # Enable "normal" warnings and make them errors:
  78. ranges_append_flag(RANGES_HAS_W3 /W3)
  79. ranges_append_flag(RANGES_HAS_WX /WX)
  80. else()
  81. ranges_append_flag(RANGES_HAS_CXXSTD "-std=c++${RANGES_CXX_STD}")
  82. set(RANGES_STD_FLAG "-std=c++${RANGES_CXX_STD}")
  83. # Enable "normal" warnings and make them errors:
  84. ranges_append_flag(RANGES_HAS_WALL -Wall)
  85. ranges_append_flag(RANGES_HAS_WEXTRA -Wextra)
  86. if (RANGES_ENABLE_WERROR)
  87. ranges_append_flag(RANGES_HAS_WERROR -Werror)
  88. endif()
  89. endif()
  90. if (RANGES_ENV_LINUX AND RANGES_CXX_COMPILER_CLANG)
  91. # On linux libc++ re-exports the system math headers. The ones from libstdc++
  92. # use the GCC __extern_always_inline intrinsic which is not supported by clang
  93. # versions 3.6, 3.7, 3.8, 3.9, 4.0, and current trunk 5.0 (as of 2017.04.13).
  94. #
  95. # This works around it by replacing __extern_always_inline with inline using a
  96. # macro:
  97. ranges_append_flag(RANGES_HAS_D__EXTERN_ALWAYS_INLINE -D__extern_always_inline=inline)
  98. endif()
  99. # Deep integration support
  100. if (RANGES_DEEP_STL_INTEGRATION)
  101. if (RANGES_CXX_COMPILER_MSVC)
  102. add_compile_options(/I "${PROJECT_SOURCE_DIR}/include/std")
  103. add_compile_options(/I "${PROJECT_SOURCE_DIR}/include")
  104. else()
  105. add_compile_options(-isystem "${PROJECT_SOURCE_DIR}/include/std")
  106. add_compile_options(-I "${PROJECT_SOURCE_DIR}/include")
  107. endif()
  108. add_compile_options(-DRANGES_DEEP_STL_INTEGRATION=1)
  109. endif()
  110. # Template diagnostic flags
  111. ranges_append_flag(RANGES_HAS_FDIAGNOSTIC_SHOW_TEMPLATE_TREE -fdiagnostics-show-template-tree)
  112. ranges_append_flag(RANGES_HAS_FTEMPLATE_BACKTRACE_LIMIT "-ftemplate-backtrace-limit=0")
  113. ranges_append_flag(RANGES_HAS_FMACRO_BACKTRACE_LIMIT "-fmacro-backtrace-limit=1")
  114. # Clang modules support
  115. if (RANGES_MODULES)
  116. ranges_append_flag(RANGES_HAS_MODULES -fmodules)
  117. ranges_append_flag(RANGES_HAS_MODULE_MAP_FILE "-fmodule-map-file=${PROJECT_SOURCE_DIR}/include/module.modulemap")
  118. ranges_append_flag(RANGES_HAS_MODULE_CACHE_PATH "-fmodules-cache-path=${PROJECT_BINARY_DIR}/module.cache")
  119. if (RANGES_LIBCXX_MODULE)
  120. ranges_append_flag(RANGES_HAS_LIBCXX_MODULE_MAP_FILE "-fmodule-map-file=${RANGES_LIBCXX_MODULE}")
  121. endif()
  122. if (RANGES_ENV_MACOSX)
  123. ranges_append_flag(RANGES_HAS_NO_IMPLICIT_MODULE_MAPS -fno-implicit-module-maps)
  124. endif()
  125. if (RANGES_DEBUG_BUILD)
  126. ranges_append_flag(RANGES_HAS_GMODULES -gmodules)
  127. endif()
  128. endif()
  129. # Sanitizer support: detect incompatible sanitizer combinations
  130. if (RANGES_ASAN AND RANGES_MSAN)
  131. message(FATAL_ERROR "[range-v3 error]: AddressSanitizer and MemorySanitizer are both enabled at the same time!")
  132. endif()
  133. if (RANGES_MSAN AND RANGES_ENV_MACOSX)
  134. message(FATAL_ERROR "[range-v3 error]: MemorySanitizer is not supported on MacOSX!")
  135. endif()
  136. # AddressSanitizer support
  137. if (RANGES_ASAN)
  138. # This policy enables passing the linker flags to the linker when trying to
  139. # test the features, which is required to successfully link ASan binaries
  140. cmake_policy(SET CMP0056 NEW)
  141. set (ASAN_FLAGS "")
  142. if (RANGES_ENV_MACOSX) # LeakSanitizer not supported on MacOSX
  143. set (ASAN_FLAGS "-fsanitize=address,signed-integer-overflow,shift,integer-divide-by-zero,implicit-signed-integer-truncation,implicit-integer-sign-change,undefined,nullability")
  144. else()
  145. if (RANGES_CXX_COMPILER_CLANG AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.0")
  146. set (ASAN_FLAGS "-fsanitize=address")
  147. else()
  148. set (ASAN_FLAGS "-fsanitize=address,signed-integer-overflow,shift,integer-divide-by-zero,implicit-signed-integer-truncation,implicit-integer-sign-change,leak,nullability")
  149. endif()
  150. endif()
  151. ranges_append_flag(RANGES_HAS_ASAN "${ASAN_FLAGS}")
  152. if (RANGES_HAS_ASAN) #ASAN flags must be passed to the linker:
  153. set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${ASAN_FLAGS}")
  154. endif()
  155. ranges_append_flag(RANGES_HAS_SANITIZE_NO_RECOVER "-fno-sanitize-recover=all")
  156. ranges_append_flag(RANGES_HAS_NO_OMIT_FRAME_POINTER -fno-omit-frame-pointer)
  157. endif()
  158. # MemorySanitizer support
  159. if (RANGES_MSAN)
  160. # This policy enables passing the linker flags to the linker when trying to
  161. # compile the examples, which is required to successfully link MSan binaries
  162. cmake_policy(SET CMP0056 NEW)
  163. ranges_append_flag(RANGES_HAS_MSAN "-fsanitize=memory")
  164. ranges_append_flag(RANGES_HAS_MSAN_TRACK_ORIGINS -fsanitize-memory-track-origins)
  165. ranges_append_flag(RANGES_HAS_SANITIZE_RECOVER_ALL "-fno-sanitize-recover=all")
  166. ranges_append_flag(RANGES_HAS_NO_OMIT_FRAME_POINTER -fno-omit-frame-pointer)
  167. endif()
  168. # Build types:
  169. if (RANGES_DEBUG_BUILD AND RANGES_RELEASE_BUILD)
  170. message(FATAL_ERROR "[range-v3 error] Cannot simultaneously generate debug and release builds!")
  171. endif()
  172. if (RANGES_DEBUG_BUILD)
  173. ranges_append_flag(RANGES_HAS_NO_INLINE -fno-inline)
  174. ranges_append_flag(RANGES_HAS_STACK_PROTECTOR_ALL -fstack-protector-all)
  175. ranges_append_flag(RANGES_HAS_G3 -g3)
  176. # Clang can generate debug info tuned for LLDB or GDB
  177. if (RANGES_CXX_COMPILER_CLANG)
  178. if (RANGES_ENV_MACOSX)
  179. ranges_append_flag(RANGES_HAS_GLLDB -glldb)
  180. elseif(RANGES_ENV_LINUX OR RANGES_ENV_OPENBSD)
  181. ranges_append_flag(RANGES_HAS_GGDB -ggdb)
  182. endif()
  183. endif()
  184. endif()
  185. if (RANGES_RELEASE_BUILD)
  186. if (NOT RANGES_ASSERTIONS)
  187. ranges_append_flag(RANGES_HAS_DNDEBUG -DNDEBUG)
  188. endif()
  189. if (NOT RANGES_ASAN AND NOT RANGES_MSAN)
  190. # The quality of ASan and MSan error messages suffers if we disable the
  191. # frame pointer, so leave it enabled when compiling with either of them:
  192. ranges_append_flag(RANGES_HAS_OMIT_FRAME_POINTER -fomit-frame-pointer)
  193. endif()
  194. ranges_append_flag(RANGES_HAS_OFAST -Ofast)
  195. if (NOT RANGES_HAS_OFAST)
  196. ranges_append_flag(RANGES_HAS_O2 -O2)
  197. endif()
  198. ranges_append_flag(RANGES_HAS_STRICT_ALIASING -fstrict-aliasing)
  199. ranges_append_flag(RANGES_HAS_STRICT_VTABLE_POINTERS -fstrict-vtable-pointers)
  200. ranges_append_flag(RANGES_HAS_FAST_MATH -ffast-math)
  201. ranges_append_flag(RANGES_HAS_VECTORIZE -fvectorize)
  202. if (NOT RANGES_ENV_MACOSX)
  203. # Sized deallocation is not available in MacOSX:
  204. ranges_append_flag(RANGES_HAS_SIZED_DEALLOCATION -fsized-deallocation)
  205. endif()
  206. if (RANGES_LLVM_POLLY)
  207. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -polly -mllvm -polly-vectorizer=stripmine")
  208. endif()
  209. if (RANGES_CXX_COMPILER_CLANG AND (NOT (RANGES_INLINE_THRESHOLD EQUAL -1)))
  210. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -inline-threshold=${RANGES_INLINE_THRESHOLD}")
  211. endif()
  212. endif()
  213. if (RANGES_NATIVE)
  214. ranges_append_flag(RANGES_HAS_MARCH_NATIVE "-march=native")
  215. ranges_append_flag(RANGES_HAS_MTUNE_NATIVE "-mtune=native")
  216. endif()
  217. include(CheckCXXSourceCompiles)
  218. set(CMAKE_REQUIRED_FLAGS ${RANGES_STD_FLAG})
  219. # Probe for library and compiler support for aligned new
  220. file(READ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/aligned_new_probe.cpp" RANGE_V3_PROBE_CODE)
  221. check_cxx_source_compiles("${RANGE_V3_PROBE_CODE}" RANGE_V3_ALIGNED_NEW_PROBE)
  222. unset(RANGE_V3_PROBE_CODE)
  223. unset(CMAKE_REQUIRED_FLAGS)
  224. if (NOT RANGE_V3_ALIGNED_NEW_PROBE)
  225. add_compile_options("-DRANGES_CXX_ALIGNED_NEW=0")
  226. endif()
  227. # Probe for coroutine TS support
  228. file(READ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/coro_test_code.cpp" RANGE_V3_PROBE_CODE)
  229. if(RANGES_CXX_COMPILER_MSVC)
  230. set(CMAKE_REQUIRED_FLAGS "/await")
  231. check_cxx_source_compiles("${RANGE_V3_PROBE_CODE}" RANGES_HAS_AWAIT)
  232. if(RANGES_HAS_AWAIT)
  233. set(RANGE_V3_COROUTINE_FLAGS "/await")
  234. endif()
  235. elseif(RANGES_CXX_COMPILER_CLANG)
  236. set(CMAKE_REQUIRED_FLAGS "-fcoroutines-ts ${RANGES_STD_FLAG}")
  237. check_cxx_source_compiles("${RANGE_V3_PROBE_CODE}" RANGES_HAS_FCOROUTINES_TS)
  238. if(RANGES_HAS_FCOROUTINES_TS)
  239. set(RANGE_V3_COROUTINE_FLAGS "-fcoroutines-ts")
  240. endif()
  241. endif()
  242. unset(CMAKE_REQUIRED_FLAGS)
  243. unset(RANGE_V3_PROBE_CODE)
  244. if (RANGE_V3_COROUTINE_FLAGS)
  245. add_compile_options(${RANGE_V3_COROUTINE_FLAGS})
  246. endif()
  247. # Test for concepts support
  248. file(READ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/concepts_test_code.cpp" RANGE_V3_PROBE_CODE)
  249. if(RANGES_CXX_COMPILER_GCC OR RANGES_CXX_COMPILER_CLANG)
  250. set(CMAKE_REQUIRED_FLAGS "-fconcepts ${RANGES_STD_FLAG}")
  251. check_cxx_source_compiles("${RANGE_V3_PROBE_CODE}" RANGE_V3_HAS_FCONCEPTS)
  252. if(RANGE_V3_HAS_FCONCEPTS)
  253. set(RANGE_V3_CONCEPTS_FLAGS "-fconcepts")
  254. endif()
  255. endif()
  256. unset(CMAKE_REQUIRED_FLAGS)
  257. unset(RANGE_V3_PROBE_CODE)
  258. if (RANGE_V3_CONCEPTS_FLAGS AND RANGES_PREFER_REAL_CONCEPTS)
  259. add_compile_options(${RANGE_V3_CONCEPTS_FLAGS})
  260. endif()
  261. if (RANGES_VERBOSE_BUILD)
  262. get_directory_property(RANGES_COMPILE_OPTIONS COMPILE_OPTIONS)
  263. message(STATUS "[range-v3]: C++ flags: ${CMAKE_CXX_FLAGS}")
  264. message(STATUS "[range-v3]: C++ debug flags: ${CMAKE_CXX_FLAGS_DEBUG}")
  265. message(STATUS "[range-v3]: C++ Release Flags: ${CMAKE_CXX_FLAGS_RELEASE}")
  266. message(STATUS "[range-v3]: C++ Compile Flags: ${CMAKE_CXX_COMPILE_FLAGS}")
  267. message(STATUS "[range-v3]: Compile options: ${RANGES_COMPILE_OPTIONS}")
  268. message(STATUS "[range-v3]: C Flags: ${CMAKE_C_FLAGS}")
  269. message(STATUS "[range-v3]: C Compile Flags: ${CMAKE_C_COMPILE_FLAGS}")
  270. message(STATUS "[range-v3]: EXE Linker flags: ${CMAKE_EXE_LINKER_FLAGS}")
  271. message(STATUS "[range-v3]: C++ Linker flags: ${CMAKE_CXX_LINK_FLAGS}")
  272. message(STATUS "[range-v3]: MODULE Linker flags: ${CMAKE_MODULE_LINKER_FLAGS}")
  273. get_directory_property(CMakeCompDirDefs COMPILE_DEFINITIONS)
  274. message(STATUS "[range-v3]: Compile Definitions: ${CmakeCompDirDefs}")
  275. endif()