draco_flags.cmake 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. # Copyright 2021 The Draco Authors
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License"); you may not
  4. # use this file except in compliance with the License. You may obtain a copy of
  5. # the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. # License for the specific language governing permissions and limitations under
  13. # the License.
  14. if(DRACO_CMAKE_DRACO_FLAGS_CMAKE_)
  15. return()
  16. endif() # DRACO_CMAKE_DRACO_FLAGS_CMAKE_
  17. set(DRACO_CMAKE_DRACO_FLAGS_CMAKE_ 1)
  18. include(CheckCXXCompilerFlag)
  19. include(CheckCXXSourceCompiles)
  20. # Adds compiler flags specified by FLAGS to the sources specified by SOURCES:
  21. #
  22. # draco_set_compiler_flags_for_sources(SOURCES <sources> FLAGS <flags>)
  23. macro(draco_set_compiler_flags_for_sources)
  24. unset(compiler_SOURCES)
  25. unset(compiler_FLAGS)
  26. unset(optional_args)
  27. unset(single_value_args)
  28. set(multi_value_args SOURCES FLAGS)
  29. cmake_parse_arguments(compiler "${optional_args}" "${single_value_args}"
  30. "${multi_value_args}" ${ARGN})
  31. if(NOT (compiler_SOURCES AND compiler_FLAGS))
  32. draco_die("draco_set_compiler_flags_for_sources: SOURCES and "
  33. "FLAGS required.")
  34. endif()
  35. set_source_files_properties(${compiler_SOURCES} PROPERTIES COMPILE_FLAGS
  36. ${compiler_FLAGS})
  37. if(DRACO_VERBOSE GREATER 1)
  38. foreach(source ${compiler_SOURCES})
  39. foreach(flag ${compiler_FLAGS})
  40. message("draco_set_compiler_flags_for_sources: source:${source} "
  41. "flag:${flag}")
  42. endforeach()
  43. endforeach()
  44. endif()
  45. endmacro()
  46. # Tests compiler flags stored in list(s) specified by FLAG_LIST_VAR_NAMES, adds
  47. # flags to $DRACO_CXX_FLAGS when tests pass. Terminates configuration if
  48. # FLAG_REQUIRED is specified and any flag check fails.
  49. #
  50. # ~~~
  51. # draco_test_cxx_flag(<FLAG_LIST_VAR_NAMES <flag list variable(s)>>
  52. # [FLAG_REQUIRED])
  53. # ~~~
  54. macro(draco_test_cxx_flag)
  55. unset(cxx_test_FLAG_LIST_VAR_NAMES)
  56. unset(cxx_test_FLAG_REQUIRED)
  57. unset(single_value_args)
  58. set(optional_args FLAG_REQUIRED)
  59. set(multi_value_args FLAG_LIST_VAR_NAMES)
  60. cmake_parse_arguments(cxx_test "${optional_args}" "${single_value_args}"
  61. "${multi_value_args}" ${ARGN})
  62. if(NOT cxx_test_FLAG_LIST_VAR_NAMES)
  63. draco_die("draco_test_cxx_flag: FLAG_LIST_VAR_NAMES required")
  64. endif()
  65. unset(cxx_flags)
  66. foreach(list_var ${cxx_test_FLAG_LIST_VAR_NAMES})
  67. if(DRACO_VERBOSE)
  68. message("draco_test_cxx_flag: adding ${list_var} to cxx_flags")
  69. endif()
  70. list(APPEND cxx_flags ${${list_var}})
  71. endforeach()
  72. if(DRACO_VERBOSE)
  73. message("CXX test: all flags: ${cxx_flags}")
  74. endif()
  75. unset(all_cxx_flags)
  76. list(APPEND all_cxx_flags ${DRACO_CXX_FLAGS} ${cxx_flags})
  77. # Turn off output from check_cxx_source_compiles. Print status directly
  78. # instead since the logging messages from check_cxx_source_compiles can be
  79. # quite confusing.
  80. set(CMAKE_REQUIRED_QUIET TRUE)
  81. # Run the actual compile test.
  82. unset(draco_all_cxx_flags_pass CACHE)
  83. message("--- Running combined CXX flags test, flags: ${all_cxx_flags}")
  84. # check_cxx_compiler_flag() requires that the flags are a string. When flags
  85. # are passed as a list it will remove the list separators, and attempt to run
  86. # a compile command using list entries concatenated together as a single
  87. # argument. Avoid the problem by forcing the argument to be a string.
  88. draco_set_and_stringify(SOURCE_VARS all_cxx_flags DEST all_cxx_flags_string)
  89. check_cxx_compiler_flag("${all_cxx_flags_string}" draco_all_cxx_flags_pass)
  90. if(cxx_test_FLAG_REQUIRED AND NOT draco_all_cxx_flags_pass)
  91. draco_die("Flag test failed for required flag(s): "
  92. "${all_cxx_flags} and FLAG_REQUIRED specified.")
  93. endif()
  94. if(draco_all_cxx_flags_pass)
  95. # Test passed: update the global flag list used by the draco target creation
  96. # wrappers.
  97. set(DRACO_CXX_FLAGS ${cxx_flags})
  98. list(REMOVE_DUPLICATES DRACO_CXX_FLAGS)
  99. if(DRACO_VERBOSE)
  100. message("DRACO_CXX_FLAGS=${DRACO_CXX_FLAGS}")
  101. endif()
  102. message("--- Passed combined CXX flags test")
  103. else()
  104. message("--- Failed combined CXX flags test, testing flags individually.")
  105. if(cxx_flags)
  106. message("--- Testing flags from $cxx_flags: " "${cxx_flags}")
  107. foreach(cxx_flag ${cxx_flags})
  108. # Since 3.17.0 check_cxx_compiler_flag() sets a normal variable at
  109. # parent scope while check_cxx_source_compiles() continues to set an
  110. # internal cache variable, so we unset both to avoid the failure /
  111. # success state persisting between checks. This has been fixed in newer
  112. # CMake releases, but 3.17 is pretty common: we will need this to avoid
  113. # weird build breakages while the fix propagates.
  114. unset(cxx_flag_test_passed)
  115. unset(cxx_flag_test_passed CACHE)
  116. message("--- Testing flag: ${cxx_flag}")
  117. check_cxx_compiler_flag("${cxx_flag}" cxx_flag_test_passed)
  118. if(cxx_flag_test_passed)
  119. message("--- Passed test for ${cxx_flag}")
  120. else()
  121. list(REMOVE_ITEM cxx_flags ${cxx_flag})
  122. message("--- Failed test for ${cxx_flag}, flag removed.")
  123. endif()
  124. endforeach()
  125. set(DRACO_CXX_FLAGS ${cxx_flags})
  126. endif()
  127. endif()
  128. if(DRACO_CXX_FLAGS)
  129. list(REMOVE_DUPLICATES DRACO_CXX_FLAGS)
  130. endif()
  131. endmacro()
  132. # Tests executable linker flags stored in list specified by FLAG_LIST_VAR_NAME,
  133. # adds flags to $DRACO_EXE_LINKER_FLAGS when test passes. Terminates
  134. # configuration when flag check fails. draco_set_cxx_flags() must be called
  135. # before calling this macro because it assumes $DRACO_CXX_FLAGS contains only
  136. # valid CXX flags.
  137. #
  138. # draco_test_exe_linker_flag(<FLAG_LIST_VAR_NAME <flag list variable)>)
  139. macro(draco_test_exe_linker_flag)
  140. unset(link_FLAG_LIST_VAR_NAME)
  141. unset(optional_args)
  142. unset(multi_value_args)
  143. set(single_value_args FLAG_LIST_VAR_NAME)
  144. cmake_parse_arguments(link "${optional_args}" "${single_value_args}"
  145. "${multi_value_args}" ${ARGN})
  146. if(NOT link_FLAG_LIST_VAR_NAME)
  147. draco_die("draco_test_link_flag: FLAG_LIST_VAR_NAME required")
  148. endif()
  149. draco_set_and_stringify(DEST linker_flags SOURCE_VARS
  150. ${link_FLAG_LIST_VAR_NAME})
  151. if(DRACO_VERBOSE)
  152. message("EXE LINKER test: all flags: ${linker_flags}")
  153. endif()
  154. # Tests of $DRACO_CXX_FLAGS have already passed. Include them with the linker
  155. # test.
  156. draco_set_and_stringify(DEST CMAKE_REQUIRED_FLAGS SOURCE_VARS DRACO_CXX_FLAGS)
  157. # Cache the global exe linker flags.
  158. if(CMAKE_EXE_LINKER_FLAGS)
  159. set(cached_CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS})
  160. draco_set_and_stringify(DEST CMAKE_EXE_LINKER_FLAGS SOURCE ${linker_flags})
  161. endif()
  162. draco_set_and_stringify(DEST CMAKE_EXE_LINKER_FLAGS SOURCE ${linker_flags}
  163. ${CMAKE_EXE_LINKER_FLAGS})
  164. # Turn off output from check_cxx_source_compiles. Print status directly
  165. # instead since the logging messages from check_cxx_source_compiles can be
  166. # quite confusing.
  167. set(CMAKE_REQUIRED_QUIET TRUE)
  168. message("--- Running EXE LINKER test for flags: ${linker_flags}")
  169. unset(linker_flag_test_passed CACHE)
  170. set(draco_cxx_main "\nint main() { return 0; }")
  171. check_cxx_source_compiles("${draco_cxx_main}" linker_flag_test_passed)
  172. if(NOT linker_flag_test_passed)
  173. draco_die("EXE LINKER test failed.")
  174. endif()
  175. message("--- Passed EXE LINKER flag test.")
  176. # Restore cached global exe linker flags.
  177. if(cached_CMAKE_EXE_LINKER_FLAGS)
  178. set(CMAKE_EXE_LINKER_FLAGS ${cached_CMAKE_EXE_LINKER_FLAGS})
  179. else()
  180. unset(CMAKE_EXE_LINKER_FLAGS)
  181. endif()
  182. list(APPEND DRACO_EXE_LINKER_FLAGS ${${link_FLAG_LIST_VAR_NAME}})
  183. list(REMOVE_DUPLICATES DRACO_EXE_LINKER_FLAGS)
  184. endmacro()
  185. # Runs the draco compiler tests. This macro builds up the list of list var(s)
  186. # that is passed to draco_test_cxx_flag().
  187. #
  188. # Note: draco_set_build_definitions() must be called before this macro.
  189. macro(draco_set_cxx_flags)
  190. unset(cxx_flag_lists)
  191. if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
  192. list(APPEND cxx_flag_lists draco_base_cxx_flags)
  193. endif()
  194. # Append clang flags after the base set to allow -Wno* overrides to take
  195. # effect. Some of the base flags may enable a large set of warnings, e.g.,
  196. # -Wall.
  197. if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  198. list(APPEND cxx_flag_lists draco_clang_cxx_flags)
  199. endif()
  200. if(MSVC)
  201. list(APPEND cxx_flag_lists draco_msvc_cxx_flags)
  202. endif()
  203. draco_set_and_stringify(DEST cxx_flags SOURCE_VARS ${cxx_flag_lists})
  204. if(DRACO_VERBOSE)
  205. message("draco_set_cxx_flags: internal CXX flags: ${cxx_flags}")
  206. endif()
  207. if(DRACO_CXX_FLAGS)
  208. list(APPEND cxx_flag_lists DRACO_CXX_FLAGS)
  209. if(DRACO_VERBOSE)
  210. message("draco_set_cxx_flags: user CXX flags: ${DRACO_CXX_FLAGS}")
  211. endif()
  212. endif()
  213. draco_set_and_stringify(DEST cxx_flags SOURCE_VARS ${cxx_flag_lists})
  214. if(cxx_flags)
  215. draco_test_cxx_flag(FLAG_LIST_VAR_NAMES ${cxx_flag_lists})
  216. endif()
  217. endmacro()
  218. # Collects Draco built-in and user-specified linker flags and tests them. Halts
  219. # configuration and reports the error when any flags cause the build to fail.
  220. #
  221. # Note: draco_test_exe_linker_flag() does the real work of setting the flags and
  222. # running the test compile commands.
  223. macro(draco_set_exe_linker_flags)
  224. unset(linker_flag_lists)
  225. if(DRACO_VERBOSE)
  226. message("draco_set_exe_linker_flags: "
  227. "draco_base_exe_linker_flags=${draco_base_exe_linker_flags}")
  228. endif()
  229. if(draco_base_exe_linker_flags)
  230. list(APPEND linker_flag_lists draco_base_exe_linker_flags)
  231. endif()
  232. if(linker_flag_lists)
  233. unset(test_linker_flags)
  234. if(DRACO_VERBOSE)
  235. message("draco_set_exe_linker_flags: "
  236. "linker_flag_lists=${linker_flag_lists}")
  237. endif()
  238. draco_set_and_stringify(DEST test_linker_flags SOURCE_VARS
  239. ${linker_flag_lists})
  240. draco_test_exe_linker_flag(FLAG_LIST_VAR_NAME test_linker_flags)
  241. endif()
  242. endmacro()