draco_flags.cmake 8.5 KB

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