cc_rules.cmake 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. # Copyright 2017 Google
  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. # cc_library(
  16. # target
  17. # SOURCES sources...
  18. # DEPENDS libraries...
  19. # [EXCLUDE_FROM_ALL]
  20. # )
  21. #
  22. # Defines a new library target with the given target name, sources, and
  23. # dependencies.
  24. function(cc_library name)
  25. set(flag EXCLUDE_FROM_ALL HEADER_ONLY)
  26. set(multi DEPENDS SOURCES)
  27. cmake_parse_arguments(ccl "${flag}" "" "${multi}" ${ARGN})
  28. if(ccl_HEADER_ONLY)
  29. set(__empty_header_only_file "${CMAKE_CURRENT_BINARY_DIR}/${name}_header_only_empty.cc")
  30. if(NOT EXISTS ${__empty_header_only_file})
  31. file(WRITE ${__empty_header_only_file}
  32. "// Generated file that keeps header-only CMake libraries happy.
  33. namespace firebase {
  34. // single meaningless symbol
  35. void ${name}_header_only_fakesym() {}
  36. } // namespace firebase
  37. "
  38. )
  39. endif()
  40. list(APPEND ccl_SOURCES ${__empty_header_only_file})
  41. endif()
  42. maybe_remove_objc_sources(sources ${ccl_SOURCES})
  43. add_library(${name} ${sources})
  44. add_objc_flags(${name} ${sources})
  45. target_include_directories(
  46. ${name}
  47. PUBLIC
  48. # Put the binary dir first so that the generated config.h trumps any one
  49. # generated statically by a Cocoapods-based build in the same source tree.
  50. ${FIREBASE_BINARY_DIR}
  51. ${FIREBASE_SOURCE_DIR}
  52. )
  53. target_compile_options(${name} PRIVATE ${FIREBASE_CXX_FLAGS})
  54. target_link_libraries(${name} PUBLIC ${ccl_DEPENDS})
  55. if(ccl_EXCLUDE_FROM_ALL)
  56. set_property(
  57. TARGET ${name}
  58. PROPERTY EXCLUDE_FROM_ALL ON
  59. )
  60. endif()
  61. endfunction()
  62. # cc_select(
  63. # interface_library
  64. # CONDITION1 implementation_library1
  65. # [CONDITION2 implementation_library2 ...]
  66. # [DEFAULT implementation_library_default]
  67. # )
  68. #
  69. # Creates an INTERFACE library named `interface_library`.
  70. #
  71. # For each pair of condition and implementation_library, evaluates the condition
  72. # and if true makes that library an INTERFACE link library of
  73. # `interface_library`.
  74. #
  75. # If supplied, uses the `DEFAULT` implementation if no other condition matches.
  76. #
  77. # If no condition matches, fails the configuration cycle with an error message
  78. # indicating that no suitable implementation was found.
  79. function(cc_select library_name)
  80. add_library(${library_name} INTERFACE)
  81. list(LENGTH ARGN length)
  82. if(length GREATER 0)
  83. math(EXPR length "${length} - 1")
  84. foreach(key RANGE 0 ${length} 2)
  85. math(EXPR value "${key} + 1")
  86. list(GET ARGN ${key} condition)
  87. list(GET ARGN ${value} impl_library)
  88. if((${condition} STREQUAL "DEFAULT") OR (${${condition}}))
  89. message("Using ${library_name} = ${impl_library}")
  90. target_link_libraries(
  91. ${library_name} INTERFACE ${impl_library}
  92. )
  93. return()
  94. endif()
  95. endforeach()
  96. endif()
  97. message(FATAL_ERROR "Could not find implementation for ${library_name}")
  98. endfunction()
  99. # cc_binary(
  100. # target
  101. # SOURCES sources...
  102. # DEPENDS libraries...
  103. # [EXCLUDE_FROM_ALL]
  104. # )
  105. #
  106. # Defines a new executable target with the given target name, sources, and
  107. # dependencies.
  108. function(cc_binary name)
  109. set(flag EXCLUDE_FROM_ALL)
  110. set(multi DEPENDS SOURCES)
  111. cmake_parse_arguments(ccb "${flag}" "" "${multi}" ${ARGN})
  112. maybe_remove_objc_sources(sources ${ccb_SOURCES})
  113. add_executable(${name} ${sources})
  114. add_objc_flags(${name} ${sources})
  115. target_compile_options(${name} PRIVATE ${FIREBASE_CXX_FLAGS})
  116. target_include_directories(${name} PRIVATE ${FIREBASE_SOURCE_DIR})
  117. target_link_libraries(${name} PRIVATE ${ccb_DEPENDS})
  118. if(ccb_EXCLUDE_FROM_ALL)
  119. set_property(
  120. TARGET ${name}
  121. PROPERTY EXCLUDE_FROM_ALL ON
  122. )
  123. endif()
  124. endfunction()
  125. # cc_test(
  126. # target
  127. # SOURCES sources...
  128. # DEPENDS libraries...
  129. # )
  130. #
  131. # Defines a new test executable target with the given target name, sources, and
  132. # dependencies. Implicitly adds DEPENDS on GTest::GTest and GTest::Main.
  133. function(cc_test name)
  134. set(multi DEPENDS SOURCES)
  135. cmake_parse_arguments(cct "" "" "${multi}" ${ARGN})
  136. list(APPEND cct_DEPENDS GTest::GTest GTest::Main)
  137. maybe_remove_objc_sources(sources ${cct_SOURCES})
  138. add_executable(${name} ${sources})
  139. add_objc_flags(${name} ${sources})
  140. add_test(${name} ${name})
  141. target_compile_options(${name} PRIVATE ${FIREBASE_CXX_FLAGS})
  142. target_include_directories(${name} PRIVATE ${FIREBASE_SOURCE_DIR})
  143. target_link_libraries(${name} PRIVATE ${cct_DEPENDS})
  144. endfunction()
  145. # cc_fuzz_test(
  146. # target
  147. # DICTIONARY dict_file
  148. # CORPUS corpus_dir
  149. # SOURCES sources...
  150. # DEPENDS libraries...
  151. # )
  152. #
  153. # Defines a new executable fuzz testing target with the given target name,
  154. # (optional) dictionary file, (optional) corpus directory, sources, and
  155. # dependencies. Implicitly adds DEPENDS on 'Fuzzer', which corresponds to
  156. # libFuzzer if fuzzing runs locally or a provided fuzzing library if fuzzing
  157. # runs on OSS Fuzz. If provided, copies the DICTIONARY file as '${target}.dict'
  158. # and copies the CORPUS directory as '${target}_seed_corpus' after building the
  159. # target. This naming convention is critical for OSS Fuzz build script to
  160. # capture new fuzzing targets.
  161. function(cc_fuzz_test name)
  162. # Finds the fuzzer library that is either provided by OSS Fuzz or libFuzzer
  163. # that is manually built from sources.
  164. find_package(Fuzzer REQUIRED)
  165. # Parse arguments of the cc_fuzz_test macro.
  166. set(single DICTIONARY CORPUS)
  167. set(multi DEPENDS SOURCES)
  168. cmake_parse_arguments(ccf "" "${single}" "${multi}" ${ARGN})
  169. list(APPEND ccf_DEPENDS Fuzzer)
  170. cc_binary(
  171. ${name}
  172. SOURCES ${ccf_SOURCES}
  173. DEPENDS ${ccf_DEPENDS}
  174. )
  175. # Copy the dictionary file and corpus directory, if they are defined.
  176. if(DEFINED ccf_DICTIONARY)
  177. add_custom_command(
  178. TARGET ${name} POST_BUILD
  179. COMMAND ${CMAKE_COMMAND} -E copy
  180. ${ccf_DICTIONARY} ${name}.dict
  181. )
  182. endif()
  183. if(DEFINED ccf_CORPUS)
  184. add_custom_command(
  185. TARGET ${name} POST_BUILD
  186. COMMAND ${CMAKE_COMMAND} -E copy_directory
  187. ${ccf_CORPUS} ${name}_seed_corpus
  188. )
  189. endif()
  190. endfunction()
  191. # maybe_remove_objc_sources(output_var sources...)
  192. #
  193. # Removes Objective-C/C++ sources from the given sources if not on an Apple
  194. # platform. Stores the resulting list in the variable named by `output_var`.
  195. function(maybe_remove_objc_sources output_var)
  196. unset(sources)
  197. foreach(source ${ARGN})
  198. get_filename_component(ext ${source} EXT)
  199. if(NOT APPLE AND ((ext STREQUAL ".m") OR (ext STREQUAL ".mm")))
  200. continue()
  201. endif()
  202. list(APPEND sources ${source})
  203. endforeach()
  204. set(${output_var} ${sources} PARENT_SCOPE)
  205. endfunction()
  206. # add_objc_flags(target sources...)
  207. #
  208. # Adds OBJC_FLAGS to the compile options of the given target if any of the
  209. # sources have filenames that indicate they are Objective-C.
  210. function(add_objc_flags target)
  211. set(_has_objc OFF)
  212. foreach(source ${ARGN})
  213. get_filename_component(ext ${source} EXT)
  214. if((ext STREQUAL ".m") OR (ext STREQUAL ".mm"))
  215. set(_has_objc ON)
  216. endif()
  217. endforeach()
  218. if(_has_objc)
  219. target_compile_options(
  220. ${target}
  221. PRIVATE
  222. ${OBJC_FLAGS}
  223. )
  224. target_link_libraries(
  225. ${target}
  226. PRIVATE
  227. "-framework Foundation"
  228. )
  229. endif()
  230. endfunction()
  231. # add_alias(alias_target actual_target)
  232. #
  233. # Adds a library alias target `alias_target` if it does not already exist,
  234. # aliasing to the given `actual_target` target. This allows library dependencies
  235. # to be specified uniformly in terms of the targets found in various
  236. # find_package modules even if the library is being built internally.
  237. function(add_alias ALIAS_TARGET ACTUAL_TARGET)
  238. if(NOT TARGET ${ALIAS_TARGET})
  239. add_library(${ALIAS_TARGET} ALIAS ${ACTUAL_TARGET})
  240. endif()
  241. endfunction()