draco_targets.cmake 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  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_TARGETS_CMAKE_)
  15. return()
  16. endif() # DRACO_CMAKE_DRACO_TARGETS_CMAKE_
  17. set(DRACO_CMAKE_DRACO_TARGETS_CMAKE_ 1)
  18. # Resets list variables used to track draco targets.
  19. macro(draco_reset_target_lists)
  20. unset(draco_targets)
  21. unset(draco_exe_targets)
  22. unset(draco_lib_targets)
  23. unset(draco_objlib_targets)
  24. unset(draco_module_targets)
  25. unset(draco_sources)
  26. unset(draco_test_targets)
  27. endmacro()
  28. # Creates an executable target. The target name is passed as a parameter to the
  29. # NAME argument, and the sources passed as a parameter to the SOURCES argument:
  30. # draco_add_executable(NAME <name> SOURCES <sources> [optional args])
  31. #
  32. # Optional args:
  33. # cmake-format: off
  34. # - OUTPUT_NAME: Override output file basename. Target basename defaults to
  35. # NAME.
  36. # - TEST: Flag. Presence means treat executable as a test.
  37. # - DEFINES: List of preprocessor macro definitions.
  38. # - INCLUDES: list of include directories for the target.
  39. # - COMPILE_FLAGS: list of compiler flags for the target.
  40. # - LINK_FLAGS: List of linker flags for the target.
  41. # - OBJLIB_DEPS: List of CMake object library target dependencies.
  42. # - LIB_DEPS: List of CMake library dependencies.
  43. # cmake-format: on
  44. #
  45. # Sources passed to this macro are added to $draco_test_sources when TEST is
  46. # specified. Otherwise sources are added to $draco_sources.
  47. #
  48. # Targets passed to this macro are always added to the $draco_targets list. When
  49. # TEST is specified targets are also added to the $draco_test_targets list.
  50. # Otherwise targets are added to $draco_exe_targets.
  51. macro(draco_add_executable)
  52. unset(exe_TEST)
  53. unset(exe_TEST_DEFINES_MAIN)
  54. unset(exe_NAME)
  55. unset(exe_OUTPUT_NAME)
  56. unset(exe_SOURCES)
  57. unset(exe_DEFINES)
  58. unset(exe_INCLUDES)
  59. unset(exe_COMPILE_FLAGS)
  60. unset(exe_LINK_FLAGS)
  61. unset(exe_OBJLIB_DEPS)
  62. unset(exe_LIB_DEPS)
  63. set(optional_args TEST)
  64. set(single_value_args NAME OUTPUT_NAME)
  65. set(multi_value_args
  66. SOURCES
  67. DEFINES
  68. INCLUDES
  69. COMPILE_FLAGS
  70. LINK_FLAGS
  71. OBJLIB_DEPS
  72. LIB_DEPS)
  73. cmake_parse_arguments(exe "${optional_args}" "${single_value_args}"
  74. "${multi_value_args}" ${ARGN})
  75. if(DRACO_VERBOSE GREATER 1)
  76. message(
  77. "--------- draco_add_executable ---------\n"
  78. "exe_TEST=${exe_TEST}\n"
  79. "exe_TEST_DEFINES_MAIN=${exe_TEST_DEFINES_MAIN}\n"
  80. "exe_NAME=${exe_NAME}\n"
  81. "exe_OUTPUT_NAME=${exe_OUTPUT_NAME}\n"
  82. "exe_SOURCES=${exe_SOURCES}\n"
  83. "exe_DEFINES=${exe_DEFINES}\n"
  84. "exe_INCLUDES=${exe_INCLUDES}\n"
  85. "exe_COMPILE_FLAGS=${exe_COMPILE_FLAGS}\n"
  86. "exe_LINK_FLAGS=${exe_LINK_FLAGS}\n"
  87. "exe_OBJLIB_DEPS=${exe_OBJLIB_DEPS}\n"
  88. "exe_LIB_DEPS=${exe_LIB_DEPS}\n"
  89. "------------------------------------------\n")
  90. endif()
  91. if(NOT (exe_NAME AND exe_SOURCES))
  92. message(FATAL_ERROR "draco_add_executable: NAME and SOURCES required.")
  93. endif()
  94. list(APPEND draco_targets ${exe_NAME})
  95. if(exe_TEST)
  96. list(APPEND draco_test_targets ${exe_NAME})
  97. list(APPEND draco_test_sources ${exe_SOURCES})
  98. else()
  99. list(APPEND draco_exe_targets ${exe_NAME})
  100. list(APPEND draco_sources ${exe_SOURCES})
  101. endif()
  102. add_executable(${exe_NAME} ${exe_SOURCES})
  103. target_compile_features(${exe_NAME} PUBLIC cxx_std_11)
  104. if(NOT EMSCRIPTEN)
  105. set_target_properties(${exe_NAME} PROPERTIES VERSION ${DRACO_VERSION})
  106. endif()
  107. if(exe_OUTPUT_NAME)
  108. set_target_properties(${exe_NAME} PROPERTIES OUTPUT_NAME ${exe_OUTPUT_NAME})
  109. endif()
  110. draco_process_intrinsics_sources(TARGET ${exe_NAME} SOURCES ${exe_SOURCES})
  111. if(exe_DEFINES)
  112. target_compile_definitions(${exe_NAME} PRIVATE ${exe_DEFINES})
  113. endif()
  114. if(exe_INCLUDES)
  115. target_include_directories(${exe_NAME} PRIVATE ${exe_INCLUDES})
  116. endif()
  117. if(exe_COMPILE_FLAGS OR DRACO_CXX_FLAGS)
  118. target_compile_options(${exe_NAME} PRIVATE ${exe_COMPILE_FLAGS}
  119. ${DRACO_CXX_FLAGS})
  120. endif()
  121. if(exe_LINK_FLAGS OR DRACO_EXE_LINKER_FLAGS)
  122. if(${CMAKE_VERSION} VERSION_LESS "3.13")
  123. list(APPEND exe_LINK_FLAGS "${DRACO_EXE_LINKER_FLAGS}")
  124. # LINK_FLAGS is managed as a string.
  125. draco_set_and_stringify(SOURCE "${exe_LINK_FLAGS}" DEST exe_LINK_FLAGS)
  126. set_target_properties(${exe_NAME} PROPERTIES LINK_FLAGS
  127. "${exe_LINK_FLAGS}")
  128. else()
  129. target_link_options(${exe_NAME} PRIVATE ${exe_LINK_FLAGS}
  130. ${DRACO_EXE_LINKER_FLAGS})
  131. endif()
  132. endif()
  133. if(exe_OBJLIB_DEPS)
  134. foreach(objlib_dep ${exe_OBJLIB_DEPS})
  135. target_sources(${exe_NAME} PRIVATE $<TARGET_OBJECTS:${objlib_dep}>)
  136. endforeach()
  137. endif()
  138. if(CMAKE_THREAD_LIBS_INIT)
  139. list(APPEND exe_LIB_DEPS ${CMAKE_THREAD_LIBS_INIT})
  140. endif()
  141. if(BUILD_SHARED_LIBS AND (MSVC OR WIN32))
  142. target_compile_definitions(${exe_NAME} PRIVATE "DRACO_BUILDING_DLL=0")
  143. endif()
  144. if(exe_LIB_DEPS)
  145. if(CMAKE_CXX_COMPILER_ID MATCHES "^Clang|^GNU")
  146. # Third party dependencies can introduce dependencies on system and test
  147. # libraries. Since the target created here is an executable, and CMake
  148. # does not provide a method of controlling order of link dependencies,
  149. # wrap all of the dependencies of this target in start/end group flags to
  150. # ensure that dependencies of third party targets can be resolved when
  151. # those dependencies happen to be resolved by dependencies of the current
  152. # target.
  153. # TODO(tomfinegan): For portability use LINK_GROUP with RESCAN instead of
  154. # directly (ab)using compiler/linker specific flags once CMake v3.24 is in
  155. # wider use. See:
  156. # https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#genex:LINK_GROUP
  157. list(INSERT exe_LIB_DEPS 0 -Wl,--start-group)
  158. list(APPEND exe_LIB_DEPS -Wl,--end-group)
  159. endif()
  160. target_link_libraries(${exe_NAME} PRIVATE ${exe_LIB_DEPS})
  161. endif()
  162. endmacro()
  163. # Creates a library target of the specified type. The target name is passed as a
  164. # parameter to the NAME argument, the type as a parameter to the TYPE argument,
  165. # and the sources passed as a parameter to the SOURCES argument:
  166. # draco_add_library(NAME <name> TYPE <type> SOURCES <sources> [optional args])
  167. #
  168. # Optional args:
  169. # cmake-format: off
  170. # - OUTPUT_NAME: Override output file basename. Target basename defaults to
  171. # NAME. OUTPUT_NAME is ignored when BUILD_SHARED_LIBS is enabled and CMake
  172. # is generating a build for which MSVC is true. This is to avoid output
  173. # basename collisions with DLL import libraries.
  174. # - TEST: Flag. Presence means treat library as a test.
  175. # - DEFINES: List of preprocessor macro definitions.
  176. # - INCLUDES: list of include directories for the target.
  177. # - COMPILE_FLAGS: list of compiler flags for the target.
  178. # - LINK_FLAGS: List of linker flags for the target.
  179. # - OBJLIB_DEPS: List of CMake object library target dependencies.
  180. # - LIB_DEPS: List of CMake library dependencies.
  181. # - PUBLIC_INCLUDES: List of include paths to export to dependents.
  182. # cmake-format: on
  183. #
  184. # Sources passed to the macro are added to the lists tracking draco sources:
  185. # cmake-format: off
  186. # - When TEST is specified sources are added to $draco_test_sources.
  187. # - Otherwise sources are added to $draco_sources.
  188. # cmake-format: on
  189. #
  190. # Targets passed to this macro are added to the lists tracking draco targets:
  191. # cmake-format: off
  192. # - Targets are always added to $draco_targets.
  193. # - When the TEST flag is specified, targets are added to
  194. # $draco_test_targets.
  195. # - When TEST is not specified:
  196. # - Libraries of type SHARED are added to $draco_dylib_targets.
  197. # - Libraries of type OBJECT are added to $draco_objlib_targets.
  198. # - Libraries of type STATIC are added to $draco_lib_targets.
  199. # cmake-format: on
  200. macro(draco_add_library)
  201. unset(lib_TEST)
  202. unset(lib_NAME)
  203. unset(lib_OUTPUT_NAME)
  204. unset(lib_TYPE)
  205. unset(lib_SOURCES)
  206. unset(lib_DEFINES)
  207. unset(lib_INCLUDES)
  208. unset(lib_COMPILE_FLAGS)
  209. unset(lib_LINK_FLAGS)
  210. unset(lib_OBJLIB_DEPS)
  211. unset(lib_LIB_DEPS)
  212. unset(lib_PUBLIC_INCLUDES)
  213. unset(lib_TARGET_PROPERTIES)
  214. set(optional_args TEST)
  215. set(single_value_args NAME OUTPUT_NAME TYPE)
  216. set(multi_value_args
  217. SOURCES
  218. DEFINES
  219. INCLUDES
  220. COMPILE_FLAGS
  221. LINK_FLAGS
  222. OBJLIB_DEPS
  223. LIB_DEPS
  224. PUBLIC_INCLUDES
  225. TARGET_PROPERTIES)
  226. cmake_parse_arguments(lib "${optional_args}" "${single_value_args}"
  227. "${multi_value_args}" ${ARGN})
  228. if(DRACO_VERBOSE GREATER 1)
  229. message(
  230. "--------- draco_add_library ---------\n"
  231. "lib_TEST=${lib_TEST}\n"
  232. "lib_NAME=${lib_NAME}\n"
  233. "lib_OUTPUT_NAME=${lib_OUTPUT_NAME}\n"
  234. "lib_TYPE=${lib_TYPE}\n"
  235. "lib_SOURCES=${lib_SOURCES}\n"
  236. "lib_DEFINES=${lib_DEFINES}\n"
  237. "lib_INCLUDES=${lib_INCLUDES}\n"
  238. "lib_COMPILE_FLAGS=${lib_COMPILE_FLAGS}\n"
  239. "lib_LINK_FLAGS=${lib_LINK_FLAGS}\n"
  240. "lib_OBJLIB_DEPS=${lib_OBJLIB_DEPS}\n"
  241. "lib_LIB_DEPS=${lib_LIB_DEPS}\n"
  242. "lib_PUBLIC_INCLUDES=${lib_PUBLIC_INCLUDES}\n"
  243. "---------------------------------------\n")
  244. endif()
  245. if(NOT (lib_NAME AND lib_TYPE))
  246. message(FATAL_ERROR "draco_add_library: NAME and TYPE required.")
  247. endif()
  248. list(APPEND draco_targets ${lib_NAME})
  249. if(lib_TEST)
  250. list(APPEND draco_test_targets ${lib_NAME})
  251. list(APPEND draco_test_sources ${lib_SOURCES})
  252. else()
  253. list(APPEND draco_sources ${lib_SOURCES})
  254. if(lib_TYPE STREQUAL MODULE)
  255. list(APPEND draco_module_targets ${lib_NAME})
  256. elseif(lib_TYPE STREQUAL OBJECT)
  257. list(APPEND draco_objlib_targets ${lib_NAME})
  258. elseif(lib_TYPE STREQUAL SHARED)
  259. list(APPEND draco_dylib_targets ${lib_NAME})
  260. elseif(lib_TYPE STREQUAL STATIC)
  261. list(APPEND draco_lib_targets ${lib_NAME})
  262. else()
  263. message(WARNING "draco_add_library: Unhandled type: ${lib_TYPE}")
  264. endif()
  265. endif()
  266. add_library(${lib_NAME} ${lib_TYPE} ${lib_SOURCES})
  267. target_compile_features(${lib_NAME} PUBLIC cxx_std_11)
  268. target_include_directories(${lib_NAME} PUBLIC $<INSTALL_INTERFACE:include>)
  269. if(BUILD_SHARED_LIBS)
  270. # Enable PIC for all targets in shared configurations.
  271. set_target_properties(${lib_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
  272. endif()
  273. if(lib_SOURCES)
  274. draco_process_intrinsics_sources(TARGET ${lib_NAME} SOURCES ${lib_SOURCES})
  275. endif()
  276. if(lib_OUTPUT_NAME)
  277. if(NOT (BUILD_SHARED_LIBS AND MSVC))
  278. set_target_properties(${lib_NAME} PROPERTIES OUTPUT_NAME
  279. ${lib_OUTPUT_NAME})
  280. endif()
  281. endif()
  282. if(lib_DEFINES)
  283. target_compile_definitions(${lib_NAME} PRIVATE ${lib_DEFINES})
  284. endif()
  285. if(lib_INCLUDES)
  286. target_include_directories(${lib_NAME} PRIVATE ${lib_INCLUDES})
  287. endif()
  288. if(lib_PUBLIC_INCLUDES)
  289. target_include_directories(${lib_NAME} PUBLIC ${lib_PUBLIC_INCLUDES})
  290. endif()
  291. if(lib_COMPILE_FLAGS OR DRACO_CXX_FLAGS)
  292. target_compile_options(${lib_NAME} PRIVATE ${lib_COMPILE_FLAGS}
  293. ${DRACO_CXX_FLAGS})
  294. endif()
  295. if(lib_LINK_FLAGS)
  296. set_target_properties(${lib_NAME} PROPERTIES LINK_FLAGS ${lib_LINK_FLAGS})
  297. endif()
  298. if(lib_OBJLIB_DEPS)
  299. foreach(objlib_dep ${lib_OBJLIB_DEPS})
  300. target_sources(${lib_NAME} PRIVATE $<TARGET_OBJECTS:${objlib_dep}>)
  301. endforeach()
  302. endif()
  303. if(lib_LIB_DEPS)
  304. if(lib_TYPE STREQUAL STATIC)
  305. set(link_type PUBLIC)
  306. else()
  307. set(link_type PRIVATE)
  308. if(lib_TYPE STREQUAL SHARED AND CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
  309. # The draco shared object uses the static draco as input to turn it into
  310. # a shared object. Include everything from the static library in the
  311. # shared object.
  312. if(APPLE)
  313. list(INSERT lib_LIB_DEPS 0 -Wl,-force_load)
  314. else()
  315. list(INSERT lib_LIB_DEPS 0 -Wl,--whole-archive)
  316. list(APPEND lib_LIB_DEPS -Wl,--no-whole-archive)
  317. endif()
  318. endif()
  319. endif()
  320. target_link_libraries(${lib_NAME} ${link_type} ${lib_LIB_DEPS})
  321. endif()
  322. if(NOT MSVC AND lib_NAME MATCHES "^lib")
  323. # Non-MSVC generators prepend lib to static lib target file names. Libdraco
  324. # already includes lib in its name. Avoid naming output files liblib*.
  325. set_target_properties(${lib_NAME} PROPERTIES PREFIX "")
  326. endif()
  327. if(NOT EMSCRIPTEN)
  328. # VERSION and SOVERSION as necessary
  329. if((lib_TYPE STREQUAL BUNDLE OR lib_TYPE STREQUAL SHARED) AND NOT MSVC)
  330. set_target_properties(
  331. ${lib_NAME} PROPERTIES VERSION ${DRACO_SOVERSION}
  332. SOVERSION ${DRACO_SOVERSION_MAJOR})
  333. endif()
  334. endif()
  335. if(BUILD_SHARED_LIBS AND (MSVC OR WIN32))
  336. if(lib_TYPE STREQUAL SHARED)
  337. target_compile_definitions(${lib_NAME} PRIVATE "DRACO_BUILDING_DLL=1")
  338. else()
  339. target_compile_definitions(${lib_NAME} PRIVATE "DRACO_BUILDING_DLL=0")
  340. endif()
  341. endif()
  342. # Determine if $lib_NAME is a header only target.
  343. unset(sources_list)
  344. if(lib_SOURCES)
  345. set(sources_list ${lib_SOURCES})
  346. list(FILTER sources_list INCLUDE REGEX cc$)
  347. endif()
  348. if(NOT sources_list)
  349. if(NOT XCODE)
  350. # This is a header only target. Tell CMake the link language.
  351. set_target_properties(${lib_NAME} PROPERTIES LINKER_LANGUAGE CXX)
  352. else()
  353. # The Xcode generator ignores LINKER_LANGUAGE. Add a dummy cc file.
  354. draco_create_dummy_source_file(TARGET ${lib_NAME} BASENAME ${lib_NAME})
  355. endif()
  356. endif()
  357. endmacro()