FollyFunctions.cmake 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. function(auto_sources RETURN_VALUE PATTERN SOURCE_SUBDIRS)
  2. if ("${SOURCE_SUBDIRS}" STREQUAL "RECURSE")
  3. SET(PATH ".")
  4. if (${ARGC} EQUAL 4)
  5. list(GET ARGV 3 PATH)
  6. endif ()
  7. endif()
  8. if ("${SOURCE_SUBDIRS}" STREQUAL "RECURSE")
  9. unset(${RETURN_VALUE})
  10. file(GLOB SUBDIR_FILES "${PATH}/${PATTERN}")
  11. list(APPEND ${RETURN_VALUE} ${SUBDIR_FILES})
  12. file(GLOB subdirs RELATIVE ${PATH} ${PATH}/*)
  13. foreach(DIR ${subdirs})
  14. if (IS_DIRECTORY ${PATH}/${DIR})
  15. if (NOT "${DIR}" STREQUAL "CMakeFiles")
  16. file(GLOB_RECURSE SUBDIR_FILES "${PATH}/${DIR}/${PATTERN}")
  17. list(APPEND ${RETURN_VALUE} ${SUBDIR_FILES})
  18. endif()
  19. endif()
  20. endforeach()
  21. else()
  22. file(GLOB ${RETURN_VALUE} "${PATTERN}")
  23. foreach (PATH ${SOURCE_SUBDIRS})
  24. file(GLOB SUBDIR_FILES "${PATH}/${PATTERN}")
  25. list(APPEND ${RETURN_VALUE} ${SUBDIR_FILES})
  26. endforeach()
  27. endif ()
  28. set(${RETURN_VALUE} ${${RETURN_VALUE}} PARENT_SCOPE)
  29. endfunction(auto_sources)
  30. # Remove all files matching a set of patterns, and,
  31. # optionally, not matching a second set of patterns,
  32. # from a set of lists.
  33. #
  34. # Example:
  35. # This will remove all files in the CPP_SOURCES list
  36. # matching "/test/" or "Test.cpp$", but not matching
  37. # "BobTest.cpp$".
  38. # REMOVE_MATCHES_FROM_LISTS(CPP_SOURCES MATCHES "/test/" "Test.cpp$" IGNORE_MATCHES "BobTest.cpp$")
  39. #
  40. # Parameters:
  41. #
  42. # [...]:
  43. # The names of the lists to remove matches from.
  44. #
  45. # [MATCHES ...]:
  46. # The matches to remove from the lists.
  47. #
  48. # [IGNORE_MATCHES ...]:
  49. # The matches not to remove, even if they match
  50. # the main set of matches to remove.
  51. function(REMOVE_MATCHES_FROM_LISTS)
  52. set(LISTS_TO_SEARCH)
  53. set(MATCHES_TO_REMOVE)
  54. set(MATCHES_TO_IGNORE)
  55. set(argumentState 0)
  56. foreach (arg ${ARGN})
  57. if ("x${arg}" STREQUAL "xMATCHES")
  58. set(argumentState 1)
  59. elseif ("x${arg}" STREQUAL "xIGNORE_MATCHES")
  60. set(argumentState 2)
  61. elseif (argumentState EQUAL 0)
  62. list(APPEND LISTS_TO_SEARCH ${arg})
  63. elseif (argumentState EQUAL 1)
  64. list(APPEND MATCHES_TO_REMOVE ${arg})
  65. elseif (argumentState EQUAL 2)
  66. list(APPEND MATCHES_TO_IGNORE ${arg})
  67. else()
  68. message(FATAL_ERROR "Unknown argument state!")
  69. endif()
  70. endforeach()
  71. foreach (theList ${LISTS_TO_SEARCH})
  72. foreach (entry ${${theList}})
  73. foreach (match ${MATCHES_TO_REMOVE})
  74. if (${entry} MATCHES ${match})
  75. set(SHOULD_IGNORE OFF)
  76. foreach (ign ${MATCHES_TO_IGNORE})
  77. if (${entry} MATCHES ${ign})
  78. set(SHOULD_IGNORE ON)
  79. break()
  80. endif()
  81. endforeach()
  82. if (NOT SHOULD_IGNORE)
  83. list(REMOVE_ITEM ${theList} ${entry})
  84. endif()
  85. endif()
  86. endforeach()
  87. endforeach()
  88. set(${theList} ${${theList}} PARENT_SCOPE)
  89. endforeach()
  90. endfunction()
  91. # Automatically create source_group directives for the sources passed in.
  92. function(auto_source_group rootName rootDir)
  93. file(TO_CMAKE_PATH "${rootDir}" rootDir)
  94. string(LENGTH "${rootDir}" rootDirLength)
  95. set(sourceGroups)
  96. foreach (fil ${ARGN})
  97. file(TO_CMAKE_PATH "${fil}" filePath)
  98. string(FIND "${filePath}" "/" rIdx REVERSE)
  99. if (rIdx EQUAL -1)
  100. message(FATAL_ERROR "Unable to locate the final forward slash in '${filePath}'!")
  101. endif()
  102. string(SUBSTRING "${filePath}" 0 ${rIdx} filePath)
  103. string(LENGTH "${filePath}" filePathLength)
  104. string(FIND "${filePath}" "${rootDir}" rIdx)
  105. if (rIdx EQUAL 0)
  106. math(EXPR filePathLength "${filePathLength} - ${rootDirLength}")
  107. string(SUBSTRING "${filePath}" ${rootDirLength} ${filePathLength} fileGroup)
  108. string(REPLACE "/" "\\" fileGroup "${fileGroup}")
  109. set(fileGroup "\\${rootName}${fileGroup}")
  110. list(FIND sourceGroups "${fileGroup}" rIdx)
  111. if (rIdx EQUAL -1)
  112. list(APPEND sourceGroups "${fileGroup}")
  113. source_group("${fileGroup}" REGULAR_EXPRESSION "${filePath}/[^/.]+.(cpp|h)$")
  114. endif()
  115. endif()
  116. endforeach()
  117. endfunction()
  118. # CMake is a pain and doesn't have an easy way to install only the files
  119. # we actually included in our build :(
  120. function(auto_install_files rootName rootDir)
  121. file(TO_CMAKE_PATH "${rootDir}" rootDir)
  122. string(LENGTH "${rootDir}" rootDirLength)
  123. set(sourceGroups)
  124. foreach (fil ${ARGN})
  125. file(TO_CMAKE_PATH "${fil}" filePath)
  126. string(FIND "${filePath}" "/" rIdx REVERSE)
  127. if (rIdx EQUAL -1)
  128. message(FATAL_ERROR "Unable to locate the final forward slash in '${filePath}'!")
  129. endif()
  130. string(SUBSTRING "${filePath}" 0 ${rIdx} filePath)
  131. string(LENGTH "${filePath}" filePathLength)
  132. string(FIND "${filePath}" "${rootDir}" rIdx)
  133. if (rIdx EQUAL 0)
  134. math(EXPR filePathLength "${filePathLength} - ${rootDirLength}")
  135. string(SUBSTRING "${filePath}" ${rootDirLength} ${filePathLength} fileGroup)
  136. install(FILES ${fil}
  137. DESTINATION ${INCLUDE_INSTALL_DIR}/${rootName}${fileGroup})
  138. endif()
  139. endforeach()
  140. endfunction()
  141. function(folly_define_tests)
  142. set(directory_count 0)
  143. set(test_count 0)
  144. set(currentArg 0)
  145. while (currentArg LESS ${ARGC})
  146. if ("x${ARGV${currentArg}}" STREQUAL "xDIRECTORY")
  147. math(EXPR currentArg "${currentArg} + 1")
  148. if (NOT currentArg LESS ${ARGC})
  149. message(FATAL_ERROR "Expected base directory!")
  150. endif()
  151. set(cur_dir ${directory_count})
  152. math(EXPR directory_count "${directory_count} + 1")
  153. set(directory_${cur_dir}_name "${ARGV${currentArg}}")
  154. # We need a single list of sources to get source_group to work nicely.
  155. set(directory_${cur_dir}_source_list)
  156. math(EXPR currentArg "${currentArg} + 1")
  157. while (currentArg LESS ${ARGC})
  158. if ("x${ARGV${currentArg}}" STREQUAL "xDIRECTORY")
  159. break()
  160. elseif ("x${ARGV${currentArg}}" STREQUAL "xTEST")
  161. math(EXPR currentArg "${currentArg} + 1")
  162. if (NOT currentArg LESS ${ARGC})
  163. message(FATAL_ERROR "Expected test name!")
  164. endif()
  165. set(cur_test ${test_count})
  166. math(EXPR test_count "${test_count} + 1")
  167. set(test_${cur_test}_name "${ARGV${currentArg}}")
  168. math(EXPR currentArg "${currentArg} + 1")
  169. set(test_${cur_test}_directory ${cur_dir})
  170. set(test_${cur_test}_content_dir)
  171. set(test_${cur_test}_headers)
  172. set(test_${cur_test}_sources)
  173. set(test_${cur_test}_tag "NONE")
  174. set(argumentState 0)
  175. while (currentArg LESS ${ARGC})
  176. if ("x${ARGV${currentArg}}" STREQUAL "xHEADERS")
  177. set(argumentState 1)
  178. elseif ("x${ARGV${currentArg}}" STREQUAL "xSOURCES")
  179. set(argumentState 2)
  180. elseif ("x${ARGV${currentArg}}" STREQUAL "xCONTENT_DIR")
  181. math(EXPR currentArg "${currentArg} + 1")
  182. if (NOT currentArg LESS ${ARGC})
  183. message(FATAL_ERROR "Expected content directory name!")
  184. endif()
  185. set(test_${cur_test}_content_dir "${ARGV${currentArg}}")
  186. elseif ("x${ARGV${currentArg}}" STREQUAL "xTEST" OR
  187. "x${ARGV${currentArg}}" STREQUAL "xDIRECTORY")
  188. break()
  189. elseif (argumentState EQUAL 0)
  190. if ("x${ARGV${currentArg}}" STREQUAL "xBROKEN")
  191. set(test_${cur_test}_tag "BROKEN")
  192. elseif ("x${ARGV${currentArg}}" STREQUAL "xHANGING")
  193. set(test_${cur_test}_tag "HANGING")
  194. elseif ("x${ARGV${currentArg}}" STREQUAL "xSLOW")
  195. set(test_${cur_test}_tag "SLOW")
  196. elseif ("x${ARGV${currentArg}}" STREQUAL "xWINDOWS_DISABLED")
  197. set(test_${cur_test}_tag "WINDOWS_DISABLED")
  198. else()
  199. message(FATAL_ERROR "Unknown test tag '${ARGV${currentArg}}'!")
  200. endif()
  201. elseif (argumentState EQUAL 1)
  202. list(APPEND test_${cur_test}_headers
  203. "${FOLLY_DIR}/${directory_${cur_dir}_name}${ARGV${currentArg}}"
  204. )
  205. elseif (argumentState EQUAL 2)
  206. list(APPEND test_${cur_test}_sources
  207. "${FOLLY_DIR}/${directory_${cur_dir}_name}${ARGV${currentArg}}"
  208. )
  209. else()
  210. message(FATAL_ERROR "Unknown argument state!")
  211. endif()
  212. math(EXPR currentArg "${currentArg} + 1")
  213. endwhile()
  214. list(APPEND directory_${cur_dir}_source_list
  215. ${test_${cur_test}_sources} ${test_${cur_test}_headers})
  216. else()
  217. message(FATAL_ERROR "Unknown argument inside directory '${ARGV${currentArg}}'!")
  218. endif()
  219. endwhile()
  220. else()
  221. message(FATAL_ERROR "Unknown argument '${ARGV${currentArg}}'!")
  222. endif()
  223. endwhile()
  224. set(cur_dir 0)
  225. while (cur_dir LESS directory_count)
  226. source_group("" FILES ${directory_${cur_dir}_source_list})
  227. math(EXPR cur_dir "${cur_dir} + 1")
  228. endwhile()
  229. set(cur_test 0)
  230. while (cur_test LESS test_count)
  231. if ("x${test_${cur_test}_tag}" STREQUAL "xNONE" OR
  232. ("x${test_${cur_test}_tag}" STREQUAL "xBROKEN" AND BUILD_BROKEN_TESTS) OR
  233. ("x${test_${cur_test}_tag}" STREQUAL "xSLOW" AND BUILD_SLOW_TESTS) OR
  234. ("x${test_${cur_test}_tag}" STREQUAL "xHANGING" AND BUILD_HANGING_TESTS) OR
  235. ("x${test_${cur_test}_tag}" STREQUAL "xWINDOWS_DISABLED" AND NOT WIN32)
  236. )
  237. set(cur_test_name ${test_${cur_test}_name})
  238. set(cur_dir_name ${directory_${test_${cur_test}_directory}_name})
  239. add_executable(${cur_test_name}
  240. ${test_${cur_test}_headers}
  241. ${test_${cur_test}_sources}
  242. )
  243. if (HAVE_CMAKE_GTEST)
  244. # If we have CMake's built-in gtest support use it to add each test
  245. # function as a separate test.
  246. gtest_add_tests(TARGET ${cur_test_name}
  247. WORKING_DIRECTORY "${TOP_DIR}"
  248. TEST_PREFIX "${cur_test_name}."
  249. TEST_LIST test_cases)
  250. set_tests_properties(${test_cases} PROPERTIES TIMEOUT 120)
  251. else()
  252. # Otherwise add each test executable as a single test.
  253. add_test(
  254. NAME ${cur_test_name}
  255. COMMAND ${cur_test_name}
  256. WORKING_DIRECTORY "${TOP_DIR}"
  257. )
  258. set_tests_properties(${cur_test_name} PROPERTIES TIMEOUT 120)
  259. endif()
  260. if (NOT "x${test_${cur_test}_content_dir}" STREQUAL "x")
  261. # Copy the content directory to the output directory tree so that
  262. # tests can be run easily from Visual Studio without having to change
  263. # the working directory for each test individually.
  264. file(
  265. COPY "${FOLLY_DIR}/${cur_dir_name}${test_${cur_test}_content_dir}"
  266. DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/folly/${cur_dir_name}${test_${cur_test}_content_dir}"
  267. )
  268. add_custom_command(TARGET ${cur_test_name} POST_BUILD COMMAND
  269. ${CMAKE_COMMAND} ARGS -E copy_directory
  270. "${FOLLY_DIR}/${cur_dir_name}${test_${cur_test}_content_dir}"
  271. "$<TARGET_FILE_DIR:${cur_test_name}>/folly/${cur_dir_name}${test_${cur_test}_content_dir}"
  272. COMMENT "Copying test content for ${cur_test_name}" VERBATIM
  273. )
  274. endif()
  275. # Strip the tailing test directory name for the folder name.
  276. string(REPLACE "test/" "" test_dir_name "${cur_dir_name}")
  277. set_property(TARGET ${cur_test_name} PROPERTY FOLDER "Tests/${test_dir_name}")
  278. target_link_libraries(${cur_test_name} PRIVATE folly_test_support)
  279. apply_folly_compile_options_to_target(${cur_test_name})
  280. endif()
  281. math(EXPR cur_test "${cur_test} + 1")
  282. endwhile()
  283. endfunction()