cc_rules.cmake 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  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_add_executable(
  17. # target
  18. # sources...
  19. # )
  20. #
  21. # Wraps a call to add_executable (including arguments like EXCLUDE_FROM_ALL)
  22. # that additionally sets common options that apply to all executables in this
  23. # repo.
  24. function(firebase_ios_add_executable target)
  25. firebase_ios_split_target_options(flag ${ARGN})
  26. add_executable(${target} ${flag_REST})
  27. firebase_ios_set_common_target_options(${target} ${flag_OPTIONS})
  28. endfunction()
  29. # firebase_ios_add_library(
  30. # target
  31. # sources...
  32. # )
  33. #
  34. # Wraps a call to add_library (including any arguments like EXCLUDE_FROM_ALL)
  35. # that additionally sets common options that apply to all libraries in this
  36. # repo.
  37. function(firebase_ios_add_library target)
  38. firebase_ios_split_target_options(flag ${ARGN})
  39. add_library(${target} ${flag_REST})
  40. firebase_ios_set_common_target_options(${target} ${flag_OPTIONS})
  41. endfunction()
  42. # firebase_ios_add_framework(
  43. # target
  44. # sources...
  45. # )
  46. #
  47. # Wraps a call to add_library (including arguments like EXCLUDE_FROM_ALL) that
  48. # additionally sets common options that apply to all frameworks in this repo.
  49. #
  50. # Note that this does not build an actual framework bundle--even recent versions
  51. # of CMake (3.15.5 as of this writing) produce problematic output when
  52. # frameworks are enabled. However `firebase_ios_add_framework` along with
  53. # `firebase_ios_framework_public_headers` produces a library target that
  54. # can be compiled against as if it *were* a framework. Notably, imports of the
  55. # form #import <Framework/Framework.h> and public headers that refer to each
  56. # other unqualified will work.
  57. function(firebase_ios_add_framework target)
  58. firebase_ios_split_target_options(flag ${ARGN})
  59. add_library(${target} ${flag_REST})
  60. firebase_ios_set_common_target_options(${target} ${flag_OPTIONS})
  61. target_link_libraries(${target} INTERFACE -ObjC)
  62. endfunction()
  63. # firebase_ios_framework_public_headers(
  64. # target
  65. # headers...
  66. # )
  67. #
  68. # Prepares the given headers for use as public headers of the given target.
  69. # This emulates CocoaPods behavior of flattening public headers by creating
  70. # a separate directory tree in the build output, consisting of symbolic links to
  71. # the actual header files. This makes it possible to use imports of these forms:
  72. #
  73. # * #import <Framework/Header.h>
  74. # * #import "Header.h"
  75. function(firebase_ios_framework_public_headers target)
  76. target_sources(${target} PRIVATE ${ARGN})
  77. podspec_prep_headers(${target} ${ARGN})
  78. target_include_directories(
  79. ${target}
  80. # ${target} is a subdirectory, making <Framework/Header.h> work.
  81. PUBLIC ${PROJECT_BINARY_DIR}/Headers
  82. # Make unqualified imports work too, often needed for peer imports from
  83. # one public header to another.
  84. PUBLIC ${PROJECT_BINARY_DIR}/Headers/${target}
  85. )
  86. endfunction()
  87. # firebase_ios_add_test(
  88. # target
  89. # sources...
  90. # )
  91. #
  92. # Wraps a call to `add_executable` (including arguments like `EXCLUDE_FROM_ALL`)
  93. # and `add_test` that additionally sets common options that apply to all tests
  94. # in this repo.
  95. #
  96. # Also adds dependencies on GTest::GTest and GTest::Main.
  97. function(firebase_ios_add_test target)
  98. firebase_ios_split_target_options(flag ${ARGN})
  99. add_executable(${target} ${flag_REST})
  100. add_test(${target} ${target})
  101. firebase_ios_set_common_target_options(${target} ${flag_OPTIONS})
  102. target_link_libraries(${target} PRIVATE GTest::GTest GTest::Main)
  103. endfunction()
  104. # firebase_ios_add_objc_test(
  105. # target
  106. # host_app
  107. # sources...
  108. # )
  109. #
  110. # Creates an XCTest bundle suitable for running tests written in Objective-C by
  111. # wrapping a call to `xctest_add_bundle` (including arguments like
  112. # `EXCLUDE_FROM_ALL`) and `xctest_add_test` that additionally sets common
  113. # options that apply to all tests in this repo.
  114. function(firebase_ios_add_objc_test target host)
  115. xctest_add_bundle(${target} ${host} ${ARGN})
  116. firebase_ios_set_common_target_options(${target})
  117. xctest_add_test(${target} ${target})
  118. if(WITH_ASAN)
  119. set_property(
  120. TEST ${target} APPEND PROPERTY
  121. ENVIRONMENT DYLD_INSERT_LIBRARIES=${CLANG_ASAN_DYLIB}
  122. )
  123. endif()
  124. if(WITH_TSAN)
  125. set_property(
  126. TEST ${target} APPEND PROPERTY
  127. ENVIRONMENT DYLD_INSERT_LIBRARIES=${CLANG_TSAN_DYLIB}
  128. )
  129. endif()
  130. endfunction()
  131. # firebase_ios_add_fuzz_test(
  132. # target
  133. # DICTIONARY dict_file
  134. # CORPUS corpus_dir
  135. # sources...
  136. # )
  137. #
  138. # Defines a new executable fuzz testing target with the given target name,
  139. # (optional) dictionary file, (optional) corpus directory, along with the given
  140. # sources and arguments you might pass to add_executable.
  141. #
  142. # Implicitly adds a dependency on the `Fuzzer` library, which corresponds to
  143. # libFuzzer if fuzzing runs locally or a provided fuzzing library if fuzzing
  144. # runs on OSS Fuzz.
  145. #
  146. # If provided, copies the DICTIONARY file as '${target}.dict' and copies the
  147. # CORPUS directory as '${target}_seed_corpus' after building the target. This
  148. # naming convention is critical for OSS Fuzz build script to capture new fuzzing
  149. # targets.
  150. function(firebase_ios_add_fuzz_test target)
  151. firebase_ios_split_target_options(flag ${ARGN})
  152. set(single DICTIONARY CORPUS)
  153. cmake_parse_arguments(args "" "${single}" "" ${flag_REST})
  154. firebase_ios_add_executable(${target} ${args_UNPARSED_ARGUMENTS})
  155. firebase_ios_set_common_target_options(${target} ${flag_OPTIONS})
  156. target_link_libraries(${target} PRIVATE Fuzzer)
  157. # Copy the dictionary file and corpus directory, if they are defined.
  158. if(DEFINED ccf_DICTIONARY)
  159. add_custom_command(
  160. TARGET ${target} POST_BUILD
  161. COMMAND ${CMAKE_COMMAND} -E copy
  162. ${ccf_DICTIONARY} ${target}.dict
  163. )
  164. endif()
  165. if(DEFINED ccf_CORPUS)
  166. add_custom_command(
  167. TARGET ${target} POST_BUILD
  168. COMMAND ${CMAKE_COMMAND} -E copy_directory
  169. ${ccf_CORPUS} ${target}_seed_corpus
  170. )
  171. endif()
  172. endfunction()
  173. # firebase_ios_add_alias(alias_target actual_target)
  174. #
  175. # Adds a library alias target `alias_target` if it does not already exist,
  176. # aliasing to the given `actual_target` target. This allows library dependencies
  177. # to be specified uniformly in terms of the targets found in various
  178. # find_package modules even if the library is being built internally.
  179. function(firebase_ios_add_alias ALIAS_TARGET ACTUAL_TARGET)
  180. if(NOT TARGET ${ALIAS_TARGET})
  181. add_library(${ALIAS_TARGET} ALIAS ${ACTUAL_TARGET})
  182. endif()
  183. endfunction()
  184. # firebase_ios_generate_dummy_source(target, sources_list)
  185. #
  186. # Generates a dummy source file containing a single symbol, suitable for use as
  187. # a source file in when defining a header-only library.
  188. #
  189. # Appends the generated source file target to the list named by sources_list.
  190. macro(firebase_ios_generate_dummy_source target sources_list)
  191. set(
  192. __empty_header_only_file
  193. "${CMAKE_CURRENT_BINARY_DIR}/${target}_header_only_empty.cc"
  194. )
  195. if(NOT EXISTS ${__empty_header_only_file})
  196. file(WRITE ${__empty_header_only_file}
  197. "// Generated file that keeps header-only CMake libraries happy.
  198. // single meaningless symbol
  199. void ${target}_header_only_fakesym() {}
  200. "
  201. )
  202. endif()
  203. list(APPEND ${sources_list} ${__empty_header_only_file})
  204. endmacro()
  205. # Splits the given arguments into two lists: those suitable for passing to
  206. # `firebase_ios_set_common_target_options` and everything else, usually passed
  207. # to `add_library`, `add_executable`, or similar.
  208. #
  209. # The resulting lists are set in the parent scope as `${prefix}_OPTIONS` for use
  210. # when calling `firebase_ios_set_common_target_options`, and `${prefix}_REST`
  211. # that contains any arguments that were unrecognized.
  212. #
  213. # See `firebase_ios_set_common_target_options` for details on which arguments
  214. # are split out.
  215. function(firebase_ios_split_target_options prefix)
  216. set(option_names DISABLE_STRICT_WARNINGS)
  217. set(${prefix}_OPTIONS)
  218. set(${prefix}_REST)
  219. foreach(arg ${ARGN})
  220. list(FIND option_names ${arg} option_index)
  221. if(NOT option_index EQUAL -1)
  222. list(APPEND ${prefix}_OPTIONS ${arg})
  223. else()
  224. list(APPEND ${prefix}_REST ${arg})
  225. endif()
  226. endforeach()
  227. set(${prefix}_OPTIONS ${${prefix}_OPTIONS} PARENT_SCOPE)
  228. set(${prefix}_REST ${${prefix}_REST} PARENT_SCOPE)
  229. endfunction()
  230. # Sets common options for a given target. This includes:
  231. #
  232. # * `DISABLE_STRICT_WARNINGS`: disables stricter warnings usually applied to
  233. # targets in this repo. Use this to compile code that's local but doesn't
  234. # hold itself to Firestore's warning strictness.
  235. #
  236. # All other arguments are ignored.
  237. function(firebase_ios_set_common_target_options target)
  238. set(options DISABLE_STRICT_WARNINGS)
  239. cmake_parse_arguments(flag "${options}" "" "" ${ARGN})
  240. if(flag_DISABLE_STRICT_WARNINGS)
  241. set(cxx_flags ${FIREBASE_IOS_CXX_FLAGS})
  242. set(objc_flags ${FIREBASE_IOS_OBJC_FLAGS})
  243. else()
  244. set(cxx_flags ${FIREBASE_IOS_CXX_FLAGS_STRICT})
  245. set(objc_flags ${FIREBASE_IOS_OBJC_FLAGS_STRICT})
  246. endif()
  247. target_compile_options(${target} PRIVATE ${cxx_flags})
  248. if(APPLE)
  249. target_compile_options(${target} PRIVATE ${objc_flags})
  250. endif()
  251. target_include_directories(
  252. ${target} PRIVATE
  253. # Put the binary dir first so that the generated config.h trumps any one
  254. # generated statically by a Cocoapods-based build in the same source tree.
  255. ${PROJECT_BINARY_DIR}
  256. ${PROJECT_SOURCE_DIR}
  257. )
  258. endfunction()
  259. # firebase_ios_glob(
  260. # list_variable
  261. # [APPEND]
  262. # [globs...]
  263. # [EXCLUDE globs...]
  264. # [INCLUDE globs...]
  265. # )
  266. #
  267. # Applies globbing rules, accumulating a list of matching files, and sets the
  268. # result to list_variable in the parent scope.
  269. #
  270. # If APPEND is specified, the result will start with any existing values in the
  271. # list_variable. Otherwise, the list_variable will be overwritten with only the
  272. # matches of this invocation.
  273. #
  274. # EXCLUDE and INCLUDE change the direction of the match. EXCLUDE will subtract
  275. # files matching the glob patterns from the result. INCLUDE will again add
  276. # files matching the glob patterns to the result. These can be used sequentially
  277. # to finely tune the match.
  278. #
  279. # As a special case, if invoked with EXCLUDE in the first argument position,
  280. # this is treated as if APPEND had been passed. This makes the common case of
  281. # subtracting something from the list less prone to error. That is, these two
  282. # invocations are equivalent:
  283. #
  284. # firebase_ios_glob(sources APPEND EXCLUDE *.h)
  285. # firebase_ios_glob(sources EXCLUDE *.h)
  286. #
  287. # Without this exception, the second form would always end up an empty list and
  288. # would never be useful.
  289. function(firebase_ios_glob list_variable)
  290. set(result)
  291. set(list_op APPEND)
  292. set(first_arg TRUE)
  293. foreach(arg IN LISTS ARGN)
  294. if(arg STREQUAL "APPEND")
  295. list(APPEND result ${${list_variable}})
  296. elseif(arg STREQUAL "INCLUDE")
  297. set(list_op APPEND)
  298. elseif(arg STREQUAL "EXCLUDE")
  299. if(first_arg)
  300. list(APPEND result ${${list_variable}})
  301. endif()
  302. set(list_op REMOVE_ITEM)
  303. else()
  304. # Anything else is a glob pattern. Match the pattern and perform the list
  305. # operation implied by the current INCLUDE or EXCLUDE mode.
  306. file(GLOB matched ${arg})
  307. list(${list_op} result ${matched})
  308. endif()
  309. set(first_arg FALSE)
  310. endforeach()
  311. set(${list_variable} ${result} PARENT_SCOPE)
  312. endfunction()