cc_rules.cmake 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. # Copyright 2017 Google LLC
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of 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,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. include(CMakeParseArguments)
  15. include(FindASANDylib)
  16. # firebase_ios_cc_library(
  17. # target
  18. # SOURCES sources...
  19. # DEPENDS libraries...
  20. # [EXCLUDE_FROM_ALL]
  21. # )
  22. #
  23. # Defines a new library target with the given target name, sources, and
  24. # dependencies.
  25. function(firebase_ios_cc_library name)
  26. set(flag DISABLE_STRICT_WARNINGS EXCLUDE_FROM_ALL HEADER_ONLY)
  27. set(multi DEPENDS SOURCES)
  28. cmake_parse_arguments(ccl "${flag}" "" "${multi}" ${ARGN})
  29. if(ccl_HEADER_ONLY)
  30. firebase_ios_generate_dummy_source(${name} ccl_SOURCES)
  31. endif()
  32. firebase_ios_maybe_remove_objc_sources(sources ${ccl_SOURCES})
  33. add_library(${name} ${sources})
  34. set(warnings_flag "")
  35. if(ccl_DISABLE_STRICT_WARNINGS)
  36. set(warnings_flag DISABLE_STRICT_WARNINGS)
  37. endif()
  38. firebase_ios_add_compile_options(${name} ${warnings_flag} ${sources})
  39. target_compile_options(${name} PRIVATE ${FIREBASE_IOS_CXX_FLAGS})
  40. target_link_libraries(${name} PUBLIC ${ccl_DEPENDS})
  41. if(ccl_EXCLUDE_FROM_ALL)
  42. set_property(
  43. TARGET ${name}
  44. PROPERTY EXCLUDE_FROM_ALL ON
  45. )
  46. endif()
  47. endfunction()
  48. # firebase_ios_cc_select(
  49. # interface_library
  50. # CONDITION1 implementation_library1
  51. # [CONDITION2 implementation_library2 ...]
  52. # [DEFAULT implementation_library_default]
  53. # )
  54. #
  55. # Creates an INTERFACE library named `interface_library`.
  56. #
  57. # For each pair of condition and implementation_library, evaluates the condition
  58. # and if true makes that library an INTERFACE link library of
  59. # `interface_library`.
  60. #
  61. # If supplied, uses the `DEFAULT` implementation if no other condition matches.
  62. #
  63. # If no condition matches, fails the configuration cycle with an error message
  64. # indicating that no suitable implementation was found.
  65. function(firebase_ios_cc_select library_name)
  66. add_library(${library_name} INTERFACE)
  67. list(LENGTH ARGN length)
  68. if(length GREATER 0)
  69. math(EXPR length "${length} - 1")
  70. foreach(key RANGE 0 ${length} 2)
  71. math(EXPR value "${key} + 1")
  72. list(GET ARGN ${key} condition)
  73. list(GET ARGN ${value} impl_library)
  74. if((${condition} STREQUAL "DEFAULT") OR (${${condition}}))
  75. message("Using ${library_name} = ${impl_library}")
  76. target_link_libraries(
  77. ${library_name} INTERFACE ${impl_library}
  78. )
  79. return()
  80. endif()
  81. endforeach()
  82. endif()
  83. message(FATAL_ERROR "Could not find implementation for ${library_name}")
  84. endfunction()
  85. # firebase_ios_cc_binary(
  86. # target
  87. # SOURCES sources...
  88. # DEPENDS libraries...
  89. # [EXCLUDE_FROM_ALL]
  90. # )
  91. #
  92. # Defines a new executable target with the given target name, sources, and
  93. # dependencies.
  94. function(firebase_ios_cc_binary name)
  95. set(flag DISABLE_STRICT_WARNINGS EXCLUDE_FROM_ALL)
  96. set(multi DEPENDS SOURCES)
  97. cmake_parse_arguments(ccb "${flag}" "" "${multi}" ${ARGN})
  98. firebase_ios_maybe_remove_objc_sources(sources ${ccb_SOURCES})
  99. add_executable(${name} ${sources})
  100. set(warnings_flag "")
  101. if(ccb_DISABLE_STRICT_WARNINGS)
  102. set(warnings_flag DISABLE_STRICT_WARNINGS)
  103. endif()
  104. firebase_ios_add_compile_options(${name} ${warnings_flag} ${sources})
  105. target_compile_options(${name} PRIVATE ${FIREBASE_CXX_FLAGS})
  106. target_include_directories(${name} PRIVATE ${FIREBASE_SOURCE_DIR})
  107. target_link_libraries(${name} PRIVATE ${ccb_DEPENDS})
  108. if(ccb_EXCLUDE_FROM_ALL)
  109. set_property(
  110. TARGET ${name}
  111. PROPERTY EXCLUDE_FROM_ALL ON
  112. )
  113. endif()
  114. endfunction()
  115. # firebase_ios_cc_test(
  116. # target
  117. # SOURCES sources...
  118. # DEPENDS libraries...
  119. # )
  120. #
  121. # Defines a new test executable target with the given target name, sources, and
  122. # dependencies. Implicitly adds DEPENDS on GTest::GTest and GTest::Main.
  123. function(firebase_ios_cc_test name)
  124. if(NOT FIREBASE_IOS_BUILD_TESTS)
  125. return()
  126. endif()
  127. set(flag DISABLE_STRICT_WARNINGS)
  128. set(multi DEPENDS SOURCES)
  129. cmake_parse_arguments(cct "${flag}" "" "${multi}" ${ARGN})
  130. list(APPEND cct_DEPENDS GTest::GTest GTest::Main)
  131. firebase_ios_maybe_remove_objc_sources(sources ${cct_SOURCES})
  132. add_executable(${name} ${sources})
  133. set(warnings_flag "")
  134. if(cct_DISABLE_STRICT_WARNINGS)
  135. set(warnings_flag DISABLE_STRICT_WARNINGS)
  136. endif()
  137. firebase_ios_add_compile_options(${name} ${warnings_flag} ${sources})
  138. add_test(${name} ${name})
  139. target_compile_options(${name} PRIVATE ${FIREBASE_CXX_FLAGS})
  140. target_include_directories(${name} PRIVATE ${FIREBASE_SOURCE_DIR})
  141. target_link_libraries(${name} PRIVATE ${cct_DEPENDS})
  142. endfunction()
  143. # firebase_ios_cc_fuzz_test(
  144. # target
  145. # DICTIONARY dict_file
  146. # CORPUS corpus_dir
  147. # SOURCES sources...
  148. # DEPENDS libraries...
  149. # )
  150. #
  151. # Defines a new executable fuzz testing target with the given target name,
  152. # (optional) dictionary file, (optional) corpus directory, sources, and
  153. # dependencies. Implicitly adds DEPENDS on 'Fuzzer', which corresponds to
  154. # libFuzzer if fuzzing runs locally or a provided fuzzing library if fuzzing
  155. # runs on OSS Fuzz. If provided, copies the DICTIONARY file as '${target}.dict'
  156. # and copies the CORPUS directory as '${target}_seed_corpus' after building the
  157. # target. This naming convention is critical for OSS Fuzz build script to
  158. # capture new fuzzing targets.
  159. function(firebase_ios_cc_fuzz_test name)
  160. # Finds the fuzzer library that is either provided by OSS Fuzz or libFuzzer
  161. # that is manually built from sources.
  162. find_package(Fuzzer REQUIRED)
  163. # Parse arguments of the firebase_ios_cc_fuzz_test macro.
  164. set(single DICTIONARY CORPUS)
  165. set(multi DEPENDS SOURCES)
  166. cmake_parse_arguments(ccf "" "${single}" "${multi}" ${ARGN})
  167. list(APPEND ccf_DEPENDS Fuzzer)
  168. firebase_ios_cc_binary(
  169. ${name}
  170. SOURCES ${ccf_SOURCES}
  171. DEPENDS ${ccf_DEPENDS}
  172. )
  173. target_compile_options(${name} PRIVATE ${FIREBASE_CXX_FLAGS})
  174. # Copy the dictionary file and corpus directory, if they are defined.
  175. if(DEFINED ccf_DICTIONARY)
  176. add_custom_command(
  177. TARGET ${name} POST_BUILD
  178. COMMAND ${CMAKE_COMMAND} -E copy
  179. ${ccf_DICTIONARY} ${name}.dict
  180. )
  181. endif()
  182. if(DEFINED ccf_CORPUS)
  183. add_custom_command(
  184. TARGET ${name} POST_BUILD
  185. COMMAND ${CMAKE_COMMAND} -E copy_directory
  186. ${ccf_CORPUS} ${name}_seed_corpus
  187. )
  188. endif()
  189. endfunction()
  190. # maybe_remove_objc_sources(output_var sources...)
  191. #
  192. # Removes Objective-C/C++ sources from the given sources if not on an Apple
  193. # platform. Stores the resulting list in the variable named by `output_var`.
  194. function(firebase_ios_maybe_remove_objc_sources output_var)
  195. unset(sources)
  196. foreach(source ${ARGN})
  197. get_filename_component(ext ${source} EXT)
  198. if(NOT APPLE AND ((ext STREQUAL ".m") OR (ext STREQUAL ".mm")))
  199. continue()
  200. endif()
  201. list(APPEND sources ${source})
  202. endforeach()
  203. set(${output_var} ${sources} PARENT_SCOPE)
  204. endfunction()
  205. # firebase_ios_add_compile_options(target [DISABLE_STRICT_WARNINGS] sources...)
  206. #
  207. # Adds FIREBASE_IOS_CXX_FLAGS or FIREBASE_IOS_CXX_FLAGS_STRICT to the compile
  208. # options of the given target depending on whether or not
  209. # DISABLE_STRICT_WARNINGS was passed.
  210. #
  211. # If any of the sources have filenames that indicate they are Objective-C adds
  212. # Either FIREBASE_IOS_OBJC_FLAGS or FIREBASE_IOS_OBJC_FLAGS_STRICT depending on
  213. # whether or not DISABLE_STRICT_WARNINGS was passed.
  214. function(firebase_ios_add_compile_options target)
  215. set(flag DISABLE_STRICT_WARNINGS)
  216. cmake_parse_arguments(aco "${flag}" "" "" ${ARGN})
  217. # Only set Objective-C flags if there's at least once source file to which
  218. # that applies.
  219. set(has_objc OFF)
  220. # Default to applying the strict warnings to all targets, but targets can
  221. # opt out.
  222. set(suffix _STRICT)
  223. if(aco_DISABLE_STRICT_WARNINGS)
  224. set(suffix "")
  225. endif()
  226. foreach(source ${ARGN})
  227. get_filename_component(ext ${source} EXT)
  228. if((ext STREQUAL ".m") OR (ext STREQUAL ".mm"))
  229. set(has_objc ON)
  230. endif()
  231. endforeach()
  232. target_compile_options(
  233. ${target}
  234. PRIVATE
  235. ${FIREBASE_IOS_CXX_FLAGS${suffix}}
  236. )
  237. if(has_objc)
  238. target_compile_options(
  239. ${target}
  240. PRIVATE
  241. ${FIREBASE_IOS_OBJC_FLAGS${suffix}}
  242. )
  243. endif()
  244. target_include_directories(
  245. ${target}
  246. PRIVATE
  247. # Put the binary dir first so that the generated config.h trumps any one
  248. # generated statically by a Cocoapods-based build in the same source tree.
  249. ${FIREBASE_BINARY_DIR}
  250. ${FIREBASE_SOURCE_DIR}
  251. )
  252. endfunction()
  253. # firebase_ios_add_alias(alias_target actual_target)
  254. #
  255. # Adds a library alias target `alias_target` if it does not already exist,
  256. # aliasing to the given `actual_target` target. This allows library dependencies
  257. # to be specified uniformly in terms of the targets found in various
  258. # find_package modules even if the library is being built internally.
  259. function(firebase_ios_add_alias ALIAS_TARGET ACTUAL_TARGET)
  260. if(NOT TARGET ${ALIAS_TARGET})
  261. add_library(${ALIAS_TARGET} ALIAS ${ACTUAL_TARGET})
  262. endif()
  263. endfunction()
  264. # firebase_ios_objc_framework(
  265. # target
  266. # HEADERS headers...
  267. # SOURCES sources...
  268. # INCLUDES include_directories...
  269. # DEFINES macros...
  270. # DEPENDS libraries...
  271. # [EXCLUDE_FROM_ALL]
  272. # )
  273. #
  274. # Defines a new framework target with the given target name and parameters.
  275. #
  276. # If SOURCES is not included, a dummy file will be generated.
  277. function(firebase_ios_objc_framework target)
  278. if(APPLE)
  279. set(flag DISABLE_STRICT_WARNINGS EXCLUDE_FROM_ALL SHARED)
  280. set(single VERSION)
  281. set(multi DEPENDS DEFINES HEADERS INCLUDES SOURCES)
  282. cmake_parse_arguments(of "${flag}" "${single}" "${multi}" ${ARGN})
  283. if (NOT of_SOURCES)
  284. firebase_ios_generate_dummy_source(${target} of_SOURCES)
  285. endif()
  286. set(shared_flag "")
  287. if(of_SHARED)
  288. set(shared_flag SHARED)
  289. endif()
  290. add_library(
  291. ${target}
  292. ${shared_flag}
  293. ${of_HEADERS}
  294. ${of_SOURCES}
  295. )
  296. set(warnings_flag "")
  297. if(of_DISABLE_STRICT_WARNINGS)
  298. set(warnings_flag DISABLE_STRICT_WARNINGS)
  299. endif()
  300. firebase_ios_add_compile_options(${target} ${warnings_flag} ${of_SOURCES})
  301. set_property(TARGET ${target} PROPERTY PUBLIC_HEADER ${of_HEADERS})
  302. set_property(TARGET ${target} PROPERTY FRAMEWORK ON)
  303. set_property(TARGET ${target} PROPERTY VERSION ${of_VERSION})
  304. if(of_EXCLUDE_FROM_ALL)
  305. set_property(TARGET ${target} PROPERTY EXCLUDE_FROM_ALL ON)
  306. endif()
  307. target_compile_definitions(${target} PUBLIC ${of_DEFINES})
  308. target_compile_options(${target} INTERFACE -F${CMAKE_CURRENT_BINARY_DIR})
  309. # Include directories are carefully crafted to support the following forms
  310. # of import, both before and after the framework is built.
  311. # * #import <Framework/Header.h>
  312. # * #import "Header.h"
  313. #
  314. # Do not use #import "Firestore/Source/Public/Header.h".
  315. podspec_prep_headers(${target} ${of_HEADERS})
  316. target_include_directories(
  317. ${target}
  318. # Before the framework is built, Framework.framework/Headers isn't
  319. # available yet, so use podspec_prep_headers to create symbolic links
  320. # fitting the <Framework/Header.h> pattern.
  321. PRIVATE ${PROJECT_BINARY_DIR}/Headers
  322. # Also support unqualified imports of public headers to work, fitting the
  323. # "Header.h" pattern.
  324. PRIVATE ${PROJECT_BINARY_DIR}/Headers/${target}
  325. # Building the framework copies public headers into it. Unfortunately
  326. # these copies defeat Clang's #import deduplication mechanism, so the
  327. # podspec_prep_headers versions (and any original locations) must not be
  328. # made available to clients of the framework. Clients get the qualified
  329. # form through the public header support in Clang's module system, and
  330. # unqualified names through this additional entry.
  331. INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/${target}.framework/Headers
  332. PRIVATE ${of_INCLUDES}
  333. )
  334. target_link_options(${target} PRIVATE -ObjC)
  335. target_link_libraries(${target} PUBLIC ${of_DEPENDS})
  336. endif()
  337. endfunction()
  338. function(firebase_ios_objc_test target)
  339. if(NOT APPLE OR NOT FIREBASE_IOS_BUILD_TESTS)
  340. return()
  341. endif()
  342. set(flag DISABLE_STRICT_WARNINGS EXCLUDE_FROM_ALL)
  343. set(single HOST VERSION WORKING_DIRECTORY)
  344. set(multi DEPENDS DEFINES HEADERS INCLUDES SOURCES)
  345. cmake_parse_arguments(ot "${flag}" "${single}" "${multi}" ${ARGN})
  346. xctest_add_bundle(
  347. ${target}
  348. ${ot_HOST}
  349. ${ot_SOURCES}
  350. )
  351. set(warnings_flag "")
  352. if(ot_DISABLE_STRICT_WARNINGS)
  353. set(warnings_flag DISABLE_STRICT_WARNINGS)
  354. endif()
  355. firebase_ios_add_compile_options(${target} ${warnings_flag} ${ot_SOURCES})
  356. target_compile_options(${target} PRIVATE ${FIREBASE_CXX_FLAGS})
  357. target_link_libraries(${target} PRIVATE ${ot_DEPENDS})
  358. xctest_add_test(
  359. ${target}
  360. ${target}
  361. )
  362. if(ot_WORKING_DIRECTORY)
  363. set_property(
  364. TEST ${target} PROPERTY
  365. WORKING_DIRECTORY ${ot_WORKING_DIRECTORY}
  366. )
  367. endif()
  368. if(WITH_ASAN)
  369. set_property(
  370. TEST ${target} APPEND PROPERTY
  371. ENVIRONMENT
  372. DYLD_INSERT_LIBRARIES=${CLANG_ASAN_DYLIB}
  373. )
  374. endif()
  375. if(WITH_TSAN)
  376. set_property(
  377. TEST ${target} APPEND PROPERTY
  378. ENVIRONMENT
  379. DYLD_INSERT_LIBRARIES=${CLANG_TSAN_DYLIB}
  380. )
  381. endif()
  382. endfunction()
  383. # firebase_ios_generate_dummy_source(name, sources_list)
  384. #
  385. # Generates a dummy source file containing a single symbol, suitable for use as
  386. # a source file in when defining a header-only library.
  387. #
  388. # Appends the generated source file name to the list named by sources_list.
  389. macro(firebase_ios_generate_dummy_source name sources_list)
  390. set(__empty_header_only_file "${CMAKE_CURRENT_BINARY_DIR}/${name}_header_only_empty.cc")
  391. if(NOT EXISTS ${__empty_header_only_file})
  392. file(WRITE ${__empty_header_only_file}
  393. "// Generated file that keeps header-only CMake libraries happy.
  394. // single meaningless symbol
  395. void ${name}_header_only_fakesym() {}
  396. "
  397. )
  398. endif()
  399. list(APPEND ${sources_list} ${__empty_header_only_file})
  400. endmacro()