FindXCTest.cmake 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. # Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. # file Copyright.txt or https://cmake.org/licensing for details.
  3. #[=======================================================================[.rst:
  4. FindXCTest
  5. ----------
  6. .. versionadded:: 3.3
  7. Functions to help creating and executing XCTest bundles.
  8. An XCTest bundle is a CFBundle with a special product-type
  9. and bundle extension. The Mac Developer Library provides more
  10. information in the `Testing with Xcode`_ document.
  11. .. _Testing with Xcode: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/testing_with_xcode/
  12. Module Functions
  13. ^^^^^^^^^^^^^^^^
  14. .. command:: xctest_add_bundle
  15. The ``xctest_add_bundle`` function creates a XCTest bundle named
  16. <target> which will test the target <testee>. Supported target types
  17. for testee are Frameworks and App Bundles::
  18. xctest_add_bundle(
  19. <target> # Name of the XCTest bundle
  20. <testee> # Target name of the testee
  21. )
  22. .. command:: xctest_add_test
  23. The ``xctest_add_test`` function adds an XCTest bundle to the
  24. project to be run by :manual:`ctest(1)`. The test will be named
  25. <name> and tests <bundle>::
  26. xctest_add_test(
  27. <name> # Test name
  28. <bundle> # Target name of XCTest bundle
  29. )
  30. Module Variables
  31. ^^^^^^^^^^^^^^^^
  32. The following variables are set by including this module:
  33. .. variable:: XCTest_FOUND
  34. True if the XCTest Framework and executable were found.
  35. .. variable:: XCTest_EXECUTABLE
  36. The path to the xctest command line tool used to execute XCTest bundles.
  37. .. variable:: XCTest_INCLUDE_DIRS
  38. The directory containing the XCTest Framework headers.
  39. .. variable:: XCTest_LIBRARIES
  40. The location of the XCTest Framework.
  41. #]=======================================================================]
  42. set(_PRESERVED_CMAKE_FIND_ROOT_PATH "${CMAKE_FIND_ROOT_PATH}")
  43. if(CMAKE_EFFECTIVE_SYSTEM_NAME STREQUAL "Apple"
  44. AND NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  45. # Non-macos systems set the CMAKE_FIND_ROOT_PATH_MODE to "ONLY" which
  46. # restricts the search paths too much to find XCTest.framework. In
  47. # contrast to the regular system frameworks which reside within the
  48. # SDK direectory the XCTest framework is located in the respective
  49. # platform directory which is not added to the CMAKE_FIND_ROOT_PATH
  50. # (only to CMAKE_SYSTEM_FRAMEWORK_PATH) and therefore not searched.
  51. #
  52. # Until this is properly addressed, temporarily add the platform
  53. # directory to CMAKE_FIND_ROOT_PATH.
  54. list(APPEND CMAKE_FIND_ROOT_PATH "${_CMAKE_OSX_SYSROOT_PATH}/../..")
  55. endif()
  56. find_path(XCTest_INCLUDE_DIR
  57. NAMES "XCTest/XCTest.h"
  58. DOC "XCTest include directory")
  59. mark_as_advanced(XCTest_INCLUDE_DIR)
  60. find_library(XCTest_LIBRARY
  61. NAMES XCTest
  62. DOC "XCTest Framework library")
  63. mark_as_advanced(XCTest_LIBRARY)
  64. set(CMAKE_FIND_ROOT_PATH "${_PRESERVED_CMAKE_FIND_ROOT_PATH}")
  65. unset(_PRESERVED_CMAKE_FIND_ROOT_PATH)
  66. execute_process(
  67. COMMAND xcrun --find xctest
  68. OUTPUT_VARIABLE _xcrun_out OUTPUT_STRIP_TRAILING_WHITESPACE
  69. ERROR_VARIABLE _xcrun_err)
  70. if(_xcrun_out)
  71. set(XCTest_EXECUTABLE "${_xcrun_out}" CACHE FILEPATH "XCTest executable")
  72. mark_as_advanced(XCTest_EXECUTABLE)
  73. endif()
  74. include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
  75. find_package_handle_standard_args(XCTest
  76. FOUND_VAR XCTest_FOUND
  77. REQUIRED_VARS XCTest_LIBRARY XCTest_INCLUDE_DIR XCTest_EXECUTABLE)
  78. if(XCTest_FOUND)
  79. set(XCTest_INCLUDE_DIRS "${XCTest_INCLUDE_DIR}")
  80. set(XCTest_LIBRARIES "${XCTest_LIBRARY}")
  81. endif(XCTest_FOUND)
  82. function(xctest_add_bundle target testee)
  83. if(NOT XCTest_FOUND)
  84. message(FATAL_ERROR "XCTest is required to create a XCTest Bundle.")
  85. endif(NOT XCTest_FOUND)
  86. if(NOT CMAKE_OSX_SYSROOT)
  87. message(FATAL_ERROR "Adding XCTest bundles requires CMAKE_OSX_SYSROOT to be set.")
  88. endif()
  89. add_library(${target} MODULE ${ARGN})
  90. set_target_properties(${target} PROPERTIES
  91. BUNDLE TRUE
  92. XCTEST TRUE
  93. XCTEST_TESTEE ${testee})
  94. target_link_libraries(${target} PRIVATE "-framework Foundation")
  95. target_link_libraries(${target} PRIVATE ${XCTest_LIBRARIES})
  96. target_include_directories(${target} PRIVATE ${XCTest_INCLUDE_DIRS})
  97. # retrieve testee target type
  98. if(NOT TARGET ${testee})
  99. message(FATAL_ERROR "${testee} is not a target.")
  100. endif()
  101. get_property(_testee_type TARGET ${testee} PROPERTY TYPE)
  102. get_property(_testee_framework TARGET ${testee} PROPERTY FRAMEWORK)
  103. get_property(_testee_macosx_bundle TARGET ${testee} PROPERTY MACOSX_BUNDLE)
  104. if(_testee_type STREQUAL "SHARED_LIBRARY" AND _testee_framework)
  105. # testee is a Framework
  106. target_link_libraries(${target} PRIVATE ${testee})
  107. elseif(_testee_type STREQUAL "STATIC_LIBRARY")
  108. # testee is a static library
  109. target_link_libraries(${target} PRIVATE ${testee})
  110. elseif(_testee_type STREQUAL "EXECUTABLE" AND _testee_macosx_bundle)
  111. # testee is an App Bundle
  112. add_dependencies(${target} ${testee})
  113. if(XCODE)
  114. set_target_properties(${target} PROPERTIES
  115. XCODE_ATTRIBUTE_BUNDLE_LOADER "$(TEST_HOST)"
  116. XCODE_ATTRIBUTE_TEST_HOST "$<TARGET_FILE:${testee}>")
  117. if(XCODE_VERSION VERSION_GREATER_EQUAL 7.3)
  118. # The Xcode "new build system" used a different path until Xcode 12.5.
  119. if(CMAKE_XCODE_BUILD_SYSTEM EQUAL 12 AND
  120. XCODE_VERSION VERSION_LESS 12.5 AND
  121. NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  122. set(_output_directory "$<TARGET_BUNDLE_CONTENT_DIR:${testee}>")
  123. else()
  124. set(_output_directory "$<TARGET_BUNDLE_CONTENT_DIR:${testee}>/PlugIns")
  125. endif()
  126. set_target_properties(${target} PROPERTIES
  127. LIBRARY_OUTPUT_DIRECTORY "${_output_directory}")
  128. endif()
  129. else(XCODE)
  130. target_link_libraries(${target}
  131. PRIVATE -bundle_loader $<TARGET_FILE:${testee}>)
  132. endif(XCODE)
  133. else()
  134. message(FATAL_ERROR "Testee ${testee} is of unsupported type.")
  135. endif()
  136. endfunction(xctest_add_bundle)
  137. function(xctest_add_test name bundle)
  138. if(NOT XCTest_EXECUTABLE)
  139. message(FATAL_ERROR "XCTest executable is required to register a test.")
  140. endif()
  141. # check that bundle is a XCTest Bundle
  142. if(NOT TARGET ${bundle})
  143. message(FATAL_ERROR "${bundle} is not a target.")
  144. endif(NOT TARGET ${bundle})
  145. get_property(_test_type TARGET ${bundle} PROPERTY TYPE)
  146. get_property(_test_bundle TARGET ${bundle} PROPERTY BUNDLE)
  147. get_property(_test_xctest TARGET ${bundle} PROPERTY XCTEST)
  148. if(NOT _test_type STREQUAL "MODULE_LIBRARY"
  149. OR NOT _test_xctest OR NOT _test_bundle)
  150. message(FATAL_ERROR "Test ${bundle} is not an XCTest Bundle")
  151. endif()
  152. # get and check testee properties
  153. get_property(_testee TARGET ${bundle} PROPERTY XCTEST_TESTEE)
  154. if(NOT TARGET ${_testee})
  155. message(FATAL_ERROR "${_testee} is not a target.")
  156. endif()
  157. get_property(_testee_type TARGET ${_testee} PROPERTY TYPE)
  158. get_property(_testee_framework TARGET ${_testee} PROPERTY FRAMEWORK)
  159. # register test
  160. # There's no target used for this command, so we don't need to do anything
  161. # here for CMP0178.
  162. add_test(
  163. NAME ${name}
  164. COMMAND ${XCTest_EXECUTABLE} $<TARGET_BUNDLE_DIR:${bundle}>)
  165. # point loader to testee in case rpath is disabled
  166. if(_testee_type STREQUAL "SHARED_LIBRARY" AND _testee_framework)
  167. set_property(TEST ${name} APPEND PROPERTY
  168. ENVIRONMENT DYLD_FRAMEWORK_PATH=$<TARGET_LINKER_FILE_DIR:${_testee}>/..)
  169. endif()
  170. endfunction(xctest_add_test)