cc_rules.cmake 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  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_cc_library(
  132. # target
  133. # SOURCES sources...
  134. # DEPENDS libraries...
  135. # [EXCLUDE_FROM_ALL]
  136. # )
  137. #
  138. # Defines a new library target with the given target name, sources, and
  139. # dependencies.
  140. function(firebase_ios_cc_library name)
  141. set(flag DISABLE_STRICT_WARNINGS EXCLUDE_FROM_ALL HEADER_ONLY)
  142. set(multi DEPENDS SOURCES)
  143. cmake_parse_arguments(ccl "${flag}" "" "${multi}" ${ARGN})
  144. if(ccl_HEADER_ONLY)
  145. firebase_ios_generate_dummy_source(${name} ccl_SOURCES)
  146. endif()
  147. firebase_ios_maybe_remove_objc_sources(sources ${ccl_SOURCES})
  148. add_library(${name} ${sources})
  149. set(warnings_flag "")
  150. if(ccl_DISABLE_STRICT_WARNINGS)
  151. set(warnings_flag DISABLE_STRICT_WARNINGS)
  152. endif()
  153. firebase_ios_add_compile_options(${name} ${warnings_flag} ${sources})
  154. target_compile_options(${name} PRIVATE ${FIREBASE_IOS_CXX_FLAGS})
  155. target_link_libraries(${name} PUBLIC ${ccl_DEPENDS})
  156. if(ccl_EXCLUDE_FROM_ALL)
  157. set_property(
  158. TARGET ${name}
  159. PROPERTY EXCLUDE_FROM_ALL ON
  160. )
  161. endif()
  162. endfunction()
  163. # firebase_ios_cc_select(
  164. # interface_library
  165. # CONDITION1 implementation_library1
  166. # [CONDITION2 implementation_library2 ...]
  167. # [DEFAULT implementation_library_default]
  168. # )
  169. #
  170. # Creates an INTERFACE library named `interface_library`.
  171. #
  172. # For each pair of condition and implementation_library, evaluates the condition
  173. # and if true makes that library an INTERFACE link library of
  174. # `interface_library`.
  175. #
  176. # If supplied, uses the `DEFAULT` implementation if no other condition matches.
  177. #
  178. # If no condition matches, fails the configuration cycle with an error message
  179. # indicating that no suitable implementation was found.
  180. function(firebase_ios_cc_select library_name)
  181. add_library(${library_name} INTERFACE)
  182. list(LENGTH ARGN length)
  183. if(length GREATER 0)
  184. math(EXPR length "${length} - 1")
  185. foreach(key RANGE 0 ${length} 2)
  186. math(EXPR value "${key} + 1")
  187. list(GET ARGN ${key} condition)
  188. list(GET ARGN ${value} impl_library)
  189. if((${condition} STREQUAL "DEFAULT") OR (${${condition}}))
  190. message("Using ${library_name} = ${impl_library}")
  191. target_link_libraries(
  192. ${library_name} INTERFACE ${impl_library}
  193. )
  194. return()
  195. endif()
  196. endforeach()
  197. endif()
  198. message(FATAL_ERROR "Could not find implementation for ${library_name}")
  199. endfunction()
  200. # firebase_ios_cc_binary(
  201. # target
  202. # SOURCES sources...
  203. # DEPENDS libraries...
  204. # [EXCLUDE_FROM_ALL]
  205. # )
  206. #
  207. # Defines a new executable target with the given target name, sources, and
  208. # dependencies.
  209. function(firebase_ios_cc_binary name)
  210. set(flag DISABLE_STRICT_WARNINGS EXCLUDE_FROM_ALL)
  211. set(multi DEPENDS SOURCES)
  212. cmake_parse_arguments(ccb "${flag}" "" "${multi}" ${ARGN})
  213. firebase_ios_maybe_remove_objc_sources(sources ${ccb_SOURCES})
  214. add_executable(${name} ${sources})
  215. set(warnings_flag "")
  216. if(ccb_DISABLE_STRICT_WARNINGS)
  217. set(warnings_flag DISABLE_STRICT_WARNINGS)
  218. endif()
  219. firebase_ios_add_compile_options(${name} ${warnings_flag} ${sources})
  220. target_compile_options(${name} PRIVATE ${FIREBASE_CXX_FLAGS})
  221. target_include_directories(${name} PRIVATE ${FIREBASE_SOURCE_DIR})
  222. target_link_libraries(${name} PRIVATE ${ccb_DEPENDS})
  223. if(ccb_EXCLUDE_FROM_ALL)
  224. set_property(
  225. TARGET ${name}
  226. PROPERTY EXCLUDE_FROM_ALL ON
  227. )
  228. endif()
  229. endfunction()
  230. # firebase_ios_cc_test(
  231. # target
  232. # SOURCES sources...
  233. # DEPENDS libraries...
  234. # )
  235. #
  236. # Defines a new test executable target with the given target name, sources, and
  237. # dependencies. Implicitly adds DEPENDS on GTest::GTest and GTest::Main.
  238. function(firebase_ios_cc_test name)
  239. if(NOT FIREBASE_IOS_BUILD_TESTS)
  240. return()
  241. endif()
  242. set(flag DISABLE_STRICT_WARNINGS)
  243. set(multi DEPENDS SOURCES)
  244. cmake_parse_arguments(cct "${flag}" "" "${multi}" ${ARGN})
  245. list(APPEND cct_DEPENDS GTest::GTest GTest::Main)
  246. firebase_ios_maybe_remove_objc_sources(sources ${cct_SOURCES})
  247. add_executable(${name} ${sources})
  248. set(warnings_flag "")
  249. if(cct_DISABLE_STRICT_WARNINGS)
  250. set(warnings_flag DISABLE_STRICT_WARNINGS)
  251. endif()
  252. firebase_ios_add_compile_options(${name} ${warnings_flag} ${sources})
  253. add_test(${name} ${name})
  254. target_compile_options(${name} PRIVATE ${FIREBASE_CXX_FLAGS})
  255. target_include_directories(${name} PRIVATE ${FIREBASE_SOURCE_DIR})
  256. target_link_libraries(${name} PRIVATE ${cct_DEPENDS})
  257. endfunction()
  258. # firebase_ios_add_fuzz_test(
  259. # target
  260. # DICTIONARY dict_file
  261. # CORPUS corpus_dir
  262. # sources...
  263. # )
  264. #
  265. # Defines a new executable fuzz testing target with the given target name,
  266. # (optional) dictionary file, (optional) corpus directory, along with the given
  267. # sources and arguments you might pass to add_executable.
  268. #
  269. # Implicitly adds a dependency on the `Fuzzer` library, which corresponds to
  270. # libFuzzer if fuzzing runs locally or a provided fuzzing library if fuzzing
  271. # runs on OSS Fuzz.
  272. #
  273. # If provided, copies the DICTIONARY file as '${target}.dict' and copies the
  274. # CORPUS directory as '${target}_seed_corpus' after building the target. This
  275. # naming convention is critical for OSS Fuzz build script to capture new fuzzing
  276. # targets.
  277. function(firebase_ios_add_fuzz_test target)
  278. firebase_ios_split_target_options(flag ${ARGN})
  279. set(single DICTIONARY CORPUS)
  280. cmake_parse_arguments(args "" "${single}" "" ${flag_REST})
  281. firebase_ios_add_executable(${target} ${args_UNPARSED_ARGUMENTS})
  282. firebase_ios_set_common_target_options(${target} ${flag_OPTIONS})
  283. target_link_libraries(${target} PRIVATE Fuzzer)
  284. # Copy the dictionary file and corpus directory, if they are defined.
  285. if(DEFINED ccf_DICTIONARY)
  286. add_custom_command(
  287. TARGET ${target} POST_BUILD
  288. COMMAND ${CMAKE_COMMAND} -E copy
  289. ${ccf_DICTIONARY} ${target}.dict
  290. )
  291. endif()
  292. if(DEFINED ccf_CORPUS)
  293. add_custom_command(
  294. TARGET ${target} POST_BUILD
  295. COMMAND ${CMAKE_COMMAND} -E copy_directory
  296. ${ccf_CORPUS} ${target}_seed_corpus
  297. )
  298. endif()
  299. endfunction()
  300. # maybe_remove_objc_sources(output_var sources...)
  301. #
  302. # Removes Objective-C/C++ sources from the given sources if not on an Apple
  303. # platform. Stores the resulting list in the variable named by `output_var`.
  304. function(firebase_ios_maybe_remove_objc_sources output_var)
  305. unset(sources)
  306. foreach(source ${ARGN})
  307. get_filename_component(ext ${source} EXT)
  308. if(NOT APPLE AND ((ext STREQUAL ".m") OR (ext STREQUAL ".mm")))
  309. continue()
  310. endif()
  311. list(APPEND sources ${source})
  312. endforeach()
  313. set(${output_var} ${sources} PARENT_SCOPE)
  314. endfunction()
  315. # firebase_ios_add_compile_options(target [DISABLE_STRICT_WARNINGS] sources...)
  316. #
  317. # Adds FIREBASE_IOS_CXX_FLAGS or FIREBASE_IOS_CXX_FLAGS_STRICT to the compile
  318. # options of the given target depending on whether or not
  319. # DISABLE_STRICT_WARNINGS was passed.
  320. #
  321. # If any of the sources have filenames that indicate they are Objective-C adds
  322. # Either FIREBASE_IOS_OBJC_FLAGS or FIREBASE_IOS_OBJC_FLAGS_STRICT depending on
  323. # whether or not DISABLE_STRICT_WARNINGS was passed.
  324. function(firebase_ios_add_compile_options target)
  325. set(flag DISABLE_STRICT_WARNINGS)
  326. cmake_parse_arguments(aco "${flag}" "" "" ${ARGN})
  327. # Only set Objective-C flags if there's at least once source file to which
  328. # that applies.
  329. set(has_objc OFF)
  330. # Default to applying the strict warnings to all targets, but targets can
  331. # opt out.
  332. set(suffix _STRICT)
  333. if(aco_DISABLE_STRICT_WARNINGS)
  334. set(suffix "")
  335. endif()
  336. foreach(source ${ARGN})
  337. get_filename_component(ext ${source} EXT)
  338. if((ext STREQUAL ".m") OR (ext STREQUAL ".mm"))
  339. set(has_objc ON)
  340. endif()
  341. endforeach()
  342. target_compile_options(
  343. ${target}
  344. PRIVATE
  345. ${FIREBASE_IOS_CXX_FLAGS${suffix}}
  346. )
  347. if(has_objc)
  348. target_compile_options(
  349. ${target}
  350. PRIVATE
  351. ${FIREBASE_IOS_OBJC_FLAGS${suffix}}
  352. )
  353. endif()
  354. target_include_directories(
  355. ${target}
  356. PRIVATE
  357. # Put the binary dir first so that the generated config.h trumps any one
  358. # generated statically by a Cocoapods-based build in the same source tree.
  359. ${FIREBASE_BINARY_DIR}
  360. ${FIREBASE_SOURCE_DIR}
  361. )
  362. endfunction()
  363. # firebase_ios_add_alias(alias_target actual_target)
  364. #
  365. # Adds a library alias target `alias_target` if it does not already exist,
  366. # aliasing to the given `actual_target` target. This allows library dependencies
  367. # to be specified uniformly in terms of the targets found in various
  368. # find_package modules even if the library is being built internally.
  369. function(firebase_ios_add_alias ALIAS_TARGET ACTUAL_TARGET)
  370. if(NOT TARGET ${ALIAS_TARGET})
  371. add_library(${ALIAS_TARGET} ALIAS ${ACTUAL_TARGET})
  372. endif()
  373. endfunction()
  374. function(firebase_ios_objc_test target)
  375. if(NOT APPLE OR NOT FIREBASE_IOS_BUILD_TESTS)
  376. return()
  377. endif()
  378. set(flag DISABLE_STRICT_WARNINGS EXCLUDE_FROM_ALL)
  379. set(single HOST VERSION WORKING_DIRECTORY)
  380. set(multi DEPENDS DEFINES HEADERS INCLUDES SOURCES)
  381. cmake_parse_arguments(ot "${flag}" "${single}" "${multi}" ${ARGN})
  382. xctest_add_bundle(
  383. ${target}
  384. ${ot_HOST}
  385. ${ot_SOURCES}
  386. )
  387. set(warnings_flag "")
  388. if(ot_DISABLE_STRICT_WARNINGS)
  389. set(warnings_flag DISABLE_STRICT_WARNINGS)
  390. endif()
  391. firebase_ios_add_compile_options(${target} ${warnings_flag} ${ot_SOURCES})
  392. target_compile_options(${target} PRIVATE ${FIREBASE_CXX_FLAGS})
  393. target_link_libraries(${target} PRIVATE ${ot_DEPENDS})
  394. xctest_add_test(
  395. ${target}
  396. ${target}
  397. )
  398. if(ot_WORKING_DIRECTORY)
  399. set_property(
  400. TEST ${target} PROPERTY
  401. WORKING_DIRECTORY ${ot_WORKING_DIRECTORY}
  402. )
  403. endif()
  404. if(WITH_ASAN)
  405. set_property(
  406. TEST ${target} APPEND PROPERTY
  407. ENVIRONMENT
  408. DYLD_INSERT_LIBRARIES=${CLANG_ASAN_DYLIB}
  409. )
  410. endif()
  411. if(WITH_TSAN)
  412. set_property(
  413. TEST ${target} APPEND PROPERTY
  414. ENVIRONMENT
  415. DYLD_INSERT_LIBRARIES=${CLANG_TSAN_DYLIB}
  416. )
  417. endif()
  418. endfunction()
  419. # firebase_ios_generate_dummy_source(target, sources_list)
  420. #
  421. # Generates a dummy source file containing a single symbol, suitable for use as
  422. # a source file in when defining a header-only library.
  423. #
  424. # Appends the generated source file target to the list named by sources_list.
  425. macro(firebase_ios_generate_dummy_source target sources_list)
  426. set(
  427. __empty_header_only_file
  428. "${CMAKE_CURRENT_BINARY_DIR}/${target}_header_only_empty.cc"
  429. )
  430. if(NOT EXISTS ${__empty_header_only_file})
  431. file(WRITE ${__empty_header_only_file}
  432. "// Generated file that keeps header-only CMake libraries happy.
  433. // single meaningless symbol
  434. void ${target}_header_only_fakesym() {}
  435. "
  436. )
  437. endif()
  438. list(APPEND ${sources_list} ${__empty_header_only_file})
  439. endmacro()
  440. # Splits the given arguments into two lists: those suitable for passing to
  441. # `firebase_ios_set_common_target_options` and everything else, usually passed
  442. # to `add_library`, `add_executable`, or similar.
  443. #
  444. # The resulting lists are set in the parent scope as `${prefix}_OPTIONS` for use
  445. # when calling `firebase_ios_set_common_target_options`, and `${prefix}_REST`
  446. # that contains any arguments that were unrecognized.
  447. #
  448. # See `firebase_ios_set_common_target_options` for details on which arguments
  449. # are split out.
  450. function(firebase_ios_split_target_options prefix)
  451. set(option_names DISABLE_STRICT_WARNINGS)
  452. set(${prefix}_OPTIONS)
  453. set(${prefix}_REST)
  454. foreach(arg ${ARGN})
  455. list(FIND option_names ${arg} option_index)
  456. if(NOT option_index EQUAL -1)
  457. list(APPEND ${prefix}_OPTIONS ${arg})
  458. else()
  459. list(APPEND ${prefix}_REST ${arg})
  460. endif()
  461. endforeach()
  462. set(${prefix}_OPTIONS ${${prefix}_OPTIONS} PARENT_SCOPE)
  463. set(${prefix}_REST ${${prefix}_REST} PARENT_SCOPE)
  464. endfunction()
  465. # Sets common options for a given target. This includes:
  466. #
  467. # * `DISABLE_STRICT_WARNINGS`: disables stricter warnings usually applied to
  468. # targets in this repo. Use this to compile code that's local but doesn't
  469. # hold itself to Firestore's warning strictness.
  470. #
  471. # All other arguments are ignored.
  472. function(firebase_ios_set_common_target_options target)
  473. set(options DISABLE_STRICT_WARNINGS)
  474. cmake_parse_arguments(flag "${options}" "" "" ${ARGN})
  475. if(flag_DISABLE_STRICT_WARNINGS)
  476. set(cxx_flags ${FIREBASE_IOS_CXX_FLAGS})
  477. set(objc_flags ${FIREBASE_IOS_OBJC_FLAGS})
  478. else()
  479. set(cxx_flags ${FIREBASE_IOS_CXX_FLAGS_STRICT})
  480. set(objc_flags ${FIREBASE_IOS_OBJC_FLAGS_STRICT})
  481. endif()
  482. target_compile_options(${target} PRIVATE ${cxx_flags})
  483. if(APPLE)
  484. target_compile_options(${target} PRIVATE ${objc_flags})
  485. endif()
  486. target_include_directories(
  487. ${target} PRIVATE
  488. # Put the binary dir first so that the generated config.h trumps any one
  489. # generated statically by a Cocoapods-based build in the same source tree.
  490. ${PROJECT_BINARY_DIR}
  491. ${PROJECT_SOURCE_DIR}
  492. )
  493. endfunction()
  494. # firebase_ios_glob(
  495. # list_variable
  496. # [APPEND]
  497. # [globs...]
  498. # [EXCLUDE globs...]
  499. # [INCLUDE globs...]
  500. # )
  501. #
  502. # Applies globbing rules, accumulating a list of matching files, and sets the
  503. # result to list_variable in the parent scope.
  504. #
  505. # If APPEND is specified, the result will start with any existing values in the
  506. # list_variable. Otherwise, the list_variable will be overwritten with only the
  507. # matches of this invocation.
  508. #
  509. # EXCLUDE and INCLUDE change the direction of the match. EXCLUDE will subtract
  510. # files matching the glob patterns from the result. INCLUDE will again add
  511. # files matching the glob patterns to the result. These can be used sequentially
  512. # to finely tune the match.
  513. #
  514. # As a special case, if invoked with EXCLUDE in the first argument position,
  515. # this is treated as if APPEND had been passed. This makes the common case of
  516. # subtracting something from the list less prone to error. That is, these two
  517. # invocations are equivalent:
  518. #
  519. # firebase_ios_glob(sources APPEND EXCLUDE *.h)
  520. # firebase_ios_glob(sources EXCLUDE *.h)
  521. #
  522. # Without this exception, the second form would always end up an empty list and
  523. # would never be useful.
  524. function(firebase_ios_glob list_variable)
  525. set(result)
  526. set(list_op APPEND)
  527. set(first_arg TRUE)
  528. foreach(arg IN LISTS ARGN)
  529. if(arg STREQUAL "APPEND")
  530. list(APPEND result ${${list_variable}})
  531. elseif(arg STREQUAL "INCLUDE")
  532. set(list_op APPEND)
  533. elseif(arg STREQUAL "EXCLUDE")
  534. if(first_arg)
  535. list(APPEND result ${${list_variable}})
  536. endif()
  537. set(list_op REMOVE_ITEM)
  538. else()
  539. # Anything else is a glob pattern. Match the pattern and perform the list
  540. # operation implied by the current INCLUDE or EXCLUDE mode.
  541. file(GLOB matched ${arg})
  542. list(${list_op} result ${matched})
  543. endif()
  544. set(first_arg FALSE)
  545. endforeach()
  546. set(${list_variable} ${result} PARENT_SCOPE)
  547. endfunction()