-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathFindSwiftXCTest.cmake
283 lines (226 loc) · 9.87 KB
/
FindSwiftXCTest.cmake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# Distributed under the Apache License, Version 2.0, with Runtime Library
# Exception. See accompanying file LICENSE for details.
#[=======================================================================[.rst:
FindSwiftXCTest
---------------
Finds the XCTest library for use by Swift code and provides functions for
adding Swift tests.
Module Functions
^^^^^^^^^^^^^^^^
.. command:: add_swift_xctest
The ``add_swift_xctest`` function creates a XCTest target named <test_target>
that will test the target <testee>, whose ``XCTestCase``s are declared in
<test_files>. <testee> can name an Application bundle target on macOS, but for
cross-platform CMake code it must be a library target. If it is a shared
library, its ``FRAMEWORK`` property must be set to a true value::
add_swift_xctest(<test_target> <testee> <test_files>)
On non-Apple platforms, the resulting test will depend on the executable
target ``GenerateSwiftXCTestMain`` supplied by
https://github.com/hylo-lang/GenerateSwiftXCTestMain.
Imported Targets
^^^^^^^^^^^^^^^^
This module provides the following imported targets, if found:
``SwiftXCTest``
The SwiftXCTest library
``XCTest``
The base XCTest library for use by Objective-C
Result Variables
^^^^^^^^^^^^^^^^
On macOS, this module sets the same variables as the ``FindXCTest`` module,
which see. On other platforms, it sets no variables.
Cache Variables
^^^^^^^^^^^^^^^
On non-macOS platforms, this module sets no variables. On macOS, this module
sets the same cache variables as the ``FindXCTest`` module (which see), plus:
.. variable:: APPLE_PLATFORM_DEVELOPER_DIRECTORY
The .../<Platform>.platform/Developer directory of Swift's target platform in
the current Swift toolchain.
#]=======================================================================]
# FindXCTest is an old-style find-module; instead of creating imported
# targets, it sets variables like XCTest_FOUND in the current
# CMakeList directory of the find_package invocation. It contains
# functions we need to call that will fatal error if XCTest_FOUND is not set.
# Therefore we must unconditionally find XCTest from each directory where
# SwiftXCTest is needed, and this must precede the include guard.
find_package(XCTest QUIET)
include_guard(GLOBAL)
# Adds the XCTest target.
function(_FindSwiftXCTest_add_XCTest)
if(APPLE)
_FindSwiftXCTest_add_XCTest_apple()
elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
_FindSwiftXCTest_add_XCTest_windows()
else()
_FindSwiftXCTest_add_XCTest_unknown_host()
endif()
endfunction()
# adds the XCTest library using the Apple-only support in CMake's
# FindXCTest module.
function(_FindSwiftXCTest_add_XCTest_apple)
if(NOT XCTest_FOUND)
message(FATAL_ERROR "XCTest is required, but was not found.")
endif()
add_library(XCTest INTERFACE) # the Objective-C XCTest module
target_link_libraries(XCTest INTERFACE ${XCTest_LIBRARIES})
endfunction()
# Adds the XCTest library using the same logic as Swift Package
# Manager uses.
function(_FindSwiftXCTest_add_XCTest_windows)
add_library(XCTest SHARED IMPORTED)
#
# Logic lifted from
# https://github.com/apple/swift-package-manager/blob/e10ff906c/Sources/PackageModel/UserToolchain.swift#L361-L447
# with thanks to @compnerd. The code is ugly, but it intentionally
# matches the structure from Swift Package Manager to make it easy
# to maintain the correspondence.
#
cmake_path(CONVERT $ENV{SDKROOT} TO_CMAKE_PATH_LIST sdkroot NORMALIZE)
if(${sdkroot} MATCHES ".*/$") # CMake is nutty about trailing slashes; strip any that are there.
cmake_path(GET sdkroot PARENT_PATH sdkroot)
endif()
cmake_path(GET sdkroot PARENT_PATH platform)
cmake_path(GET platform PARENT_PATH platform)
cmake_path(GET platform PARENT_PATH platform)
# Crude XML parsing to find the xctest version
file(READ ${platform}/Info.plist plistXML)
string(REGEX REPLACE ".*<key>XCTEST_VERSION</key>[ \t\r\n]*<string>([^<]+)</string>.*" "\\1" xctestVersion "${plistXML}")
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "ARM64")
set(archName aarch64)
set(archBin bin64a)
elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES "AMD64|IA64|EM64T|x64")
set(archName x86_64)
set(archBin bin64)
else()
set(archName i686)
set(archBin bin32)
endif()
cmake_path(APPEND platform Developer Library XCTest-${xctestVersion} OUTPUT_VARIABLE installation)
target_include_directories(XCTest INTERFACE "${installation}/usr/lib/swift/windows")
# Migration Path
#
# Older Swift (<=5.7) installations placed the XCTest Swift module into the architecture specified
# directory in order to match the SDK setup.
target_include_directories(XCTest INTERFACE
"${installation}/usr/lib/swift/windows/${archName}"
)
target_link_directories(XCTest INTERFACE
"${installation}/usr/lib/swift/windows/${archName}"
)
set_target_properties(XCTest PROPERTIES
# There's no analogy for this in the Swift code but CMake insists on it.
IMPORTED_IMPLIB "${installation}/usr/lib/swift/windows/${archName}/XCTest.lib"
# This doesn't seem to have any effect on its own, but it needs to be in the the PATH in order
# to run the test executable.
IMPORTED_LOCATION "${installation}/usr/${archBin}/XCTest.dll"
)
# Migration Path
#
# Before multiple parallel SDK installations were supported (~5.7), we always had a singular
# installed SDK. Add it as a fallback if it exists.
set(implib "${installation}/usr/lib/swift/windows/XCTest.lib")
if(EXISTS ${implib})
cmake_path(GET implib PARENT_PATH p)
target_link_directories(XCTest INTERFACE ${p})
endif()
endfunction()
# Adds the XCTest library target using the normal logic for
# pre-installed libraries.
function(_FindSwiftXCTest_add_XCTest_unknown_host)
find_library(
XCTest_LIBRARY
NAMES XCTest
DOC "XCTest library")
endfunction()
# If APPLE_PLATFORM_DEVELOPER_DIRECTORY is unset, sets it to the
# .../<Platform>.platform/Developer directory of Swift's target
# platform in the current Swift toolchain, or exits with a fatal error
# if that directory can't be found.
#
# Requires: ${APPLE}
function(_FindSwiftXCTest_apple_swift_Platform_Developer_directory)
if(DEFINED APPLE_PLATFORM_DEVELOPER_DIRECTORY)
return()
endif()
set(platform_developer "")
foreach(d ${CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES})
if(${d} MATCHES "^(.*[.]platform/Developer)/SDKs/.*")
string(REGEX REPLACE "^(.*[.]platform/Developer)/SDKs/.*" "\\1" platform_developer ${d})
break()
endif()
endforeach()
if(platform_developer STREQUAL "")
set(platform_developer "APPLE_PLATFORM_DEVELOPER_DIRECTORY-NOTFOUND")
endif()
set(APPLE_PLATFORM_DEVELOPER_DIRECTORY
"${platform_developer}" CACHE PATH
"The .../<Platform>.platform/Developer directory of Swift's target platform in the current Swift toolchain.")
if(NOT APPLE_PLATFORM_DEVELOPER_DIRECTORY)
message(FATAL_ERROR
"failed to find platform developer directory in ${CMAKE_Swift_IMPLICIT_INCLUDE_DIRECTORIES}")
endif()
endfunction()
# Adds the swift-only SwiftXCTest target.
#
# - Precondition: the XCTest target exists
function(_FindSwiftXCTest_add_SwiftXCTest)
add_library(SwiftXCTest INTERFACE)
target_link_libraries(SwiftXCTest INTERFACE XCTest)
if(APPLE)
_FindSwiftXCTest_apple_swift_Platform_Developer_directory(platform_developer)
# Where to find the XCTestSwiftSupport.swiftmodule
target_include_directories(SwiftXCTest
INTERFACE ${APPLE_PLATFORM_DEVELOPER_DIRECTORY}/usr/lib/)
# Where to find libXCTestSwiftSupport.dylib
set_target_properties(SwiftXCTest
PROPERTIES INTERFACE_LINK_DIRECTORIES ${APPLE_PLATFORM_DEVELOPER_DIRECTORY}/usr/lib)
endif()
endfunction()
# add_swift_xctest(
# <name> <testee>
# <swift_source> ...
# DEPENDENCIES <target> ...
# )
#
# Creates a CTest test target named `<name>`, testing `<testee>`, that runs the tests in the given
# Swift source files.
#
# On Apple platforms, `<testee>` must be a target type supported by `xctest_add_bundle` (officially,
# Frameworks and App Bundles, although static modules seem to work also). On other platforms
# `<testee>` can be any target type that works as a dependency in `target_link_libraries`.
function(add_swift_xctest test_target testee)
cmake_parse_arguments(ARG "" "" "DEPENDENCIES" ${ARGN})
set(sources ${ARG_UNPARSED_ARGUMENTS})
set(dependencies ${ARG_DEPENDENCIES})
if(APPLE)
if(NOT TARGET SwiftXCTest)
message(FATAL_ERROR "SwiftXCTest is required, but was not found.")
endif()
xctest_add_bundle(${test_target} ${testee} ${sources})
target_link_libraries(${test_target} PRIVATE SwiftXCTest ${dependencies})
xctest_add_test(XCTest.${test_target} ${test_target})
else()
set(test_main "${PROJECT_BINARY_DIR}/${test_target}-test_main/main.swift")
add_custom_command(
OUTPUT ${test_main}
# If the executable target depends on DLLs their directories need to be injected into the PATH
# or they won't be found and the target will fail to run, so invoke it through cmake. Because
COMMAND
${CMAKE_COMMAND} -E env
"PATH=$<SHELL_PATH:$<TARGET_RUNTIME_DLL_DIRS:GenerateSwiftXCTestMain>;$ENV{PATH}>"
--
$<TARGET_FILE:GenerateSwiftXCTestMain> -o ${test_main} ${sources}
DEPENDS ${sources} GenerateSwiftXCTestMain
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
COMMENT "Generate runner for test target ${test_target}")
add_executable(${test_target} ${test_main} ${sources})
target_link_libraries(${test_target} PRIVATE ${testee} SwiftXCTest ${dependencies})
add_test(NAME ${test_target}
COMMAND ${test_target})
set_tests_properties(${test_target}
PROPERTIES ENVIRONMENT_MODIFICATION
# For each DLL dependency X, make the PATH=path_list_prepend:X environment modification.
"$<LIST:TRANSFORM,$<TARGET_RUNTIME_DLL_DIRS:${test_target}>,PREPEND,PATH=path_list_prepend:>")
endif()
endfunction()
_FindSwiftXCTest_add_XCTest()
_FindSwiftXCTest_add_SwiftXCTest()