@@ -66,7 +66,7 @@ platform-specific attention.
6666> These errors are produced when the configuration you're trying to build has
6767> conflicting requirements (for example, attempting to enable support for pipes
6868> without also enabling support for file I/O.) You should be able to resolve
69- > these issues by updating Package.swift and/or CompilerSettings.cmake.
69+ > these issues by updating ` Package.swift ` and/or ` CompilerSettings.cmake ` .
7070
7171Most platform dependencies can be resolved through the use of platform-specific
7272API. For example, Swift Testing uses the C11 standard [ ` timespec ` ] ( https://en.cppreference.com/w/c/chrono/timespec )
@@ -123,69 +123,110 @@ Once the header is included, we can call `GetDateTime()` from `Clock.swift`:
123123## Runtime test discovery
124124
125125When porting to a new platform, you may need to provide a new implementation for
126- ` enumerateTypeMetadataSections( )` in ` Discovery.cpp ` . Test discovery is
127- dependent on Swift metadata discovery which is an inherently platform-specific
128- operation.
129-
130- _ Most _ platforms will be able to reuse the implementation used by Linux and
131- Windows that calls an internal Swift runtime function to enumerate available
132- metadata. If you are porting Swift Testing to Classic, this function won't be
133- available, so you'll need to write a custom implementation instead. Assuming
134- that the Swift compiler emits section information into the resource fork on
135- Classic, you could use the [ Resource Manager] ( https://developer.apple.com/library/archive/documentation/mac/pdf/MoreMacintoshToolbox.pdf )
126+ ` _sectionBounds(_: )` in ` Discovery+Platform.swift ` . Test discovery is dependent
127+ on Swift metadata discovery which is an inherently platform-specific operation.
128+
129+ _ Most _ platforms in use today use the ELF image format and will be able to reuse
130+ the implementation used by Linux.
131+
132+ Classic does not use the ELF image format, so you'll need to write a custom
133+ implementation of ` _sectionBounds(_:) ` instead. Assuming that the Swift compiler
134+ emits section information into the resource fork on Classic, you would use the
135+ [ Resource Manager] ( https://developer.apple.com/library/archive/documentation/mac/pdf/MoreMacintoshToolbox.pdf )
136136to load that information:
137137
138138``` diff
139- --- a/Sources/_TestingInternals /Discovery.cpp
140- +++ b/Sources/_TestingInternals /Discovery.cpp
139+ --- a/Sources/Testing /Discovery+Platform.swift
140+ +++ b/Sources/Testing /Discovery+Platform.swift
141141
142142 // ...
143- + #elif defined(macintosh)
144- + template <typename SectionEnumerator>
145- + static void enumerateTypeMetadataSections(const SectionEnumerator& body) {
146- + ResFileRefNum refNum;
147- + if (noErr == GetTopResourceFile(&refNum)) {
148- + ResFileRefNum oldRefNum = refNum;
149- + do {
150- + UseResFile(refNum);
151- + Handle handle = Get1NamedResource('swft', "\p__swift5_types");
152- + if (handle && *handle) {
153- + auto imageAddress = reinterpret_cast<const void *>(static_cast<uintptr_t>(refNum));
154- + SWTSectionBounds sb = { imageAddress, *handle, GetHandleSize(handle) };
155- + bool stop = false;
156- + body(sb, &stop);
157- + if (stop) {
158- + break;
159- + }
160- + }
161- + } while (noErr == GetNextResourceFile(refNum, &refNum));
162- + UseResFile(oldRefNum);
143+ + #elseif os(Classic)
144+ + private func _sectionBounds(_ kind: SectionBounds.Kind) -> [SectionBounds] {
145+ + let resourceName: Str255 = switch kind {
146+ + case .testContent:
147+ + "__swift5_tests"
148+ + case .typeMetadata:
149+ + "__swift5_types"
150+ + }
151+ +
152+ + let oldRefNum = CurResFile()
153+ + defer {
154+ + UseResFile(oldRefNum)
155+ + }
156+ +
157+ + var refNum = ResFileRefNum(0)
158+ + guard noErr == GetTopResourceFile(&refNum) else {
159+ + return []
163160+ }
161+ +
162+ + var result = [SectionBounds]()
163+ + repeat {
164+ + UseResFile(refNum)
165+ + guard let handle = Get1NamedResource(ResType("swft"), resourceName) else {
166+ + continue
167+ + }
168+ + let sb = SectionBounds(
169+ + imageAddress: UnsafeRawPointer(bitPattern: UInt(refNum)),
170+ + start: handle.pointee!,
171+ + size: GetHandleSize(handle)
172+ + )
173+ + result.append(sb)
174+ + } while noErr == GetNextResourceFile(refNum, &refNum))
175+ + return result
164176+ }
165177 #else
166- #warning Platform-specific implementation missing: Runtime test discovery unavailable (dynamic)
167- template <typename SectionEnumerator>
168- static void enumerateTypeMetadataSections(const SectionEnumerator& body) {}
178+ private func _sectionBounds(_ kind: SectionBounds.Kind) -> [SectionBounds] {
179+ #warning("Platform-specific implementation missing: Runtime test discovery unavailable (dynamic)")
180+ return []
181+ }
169182 #endif
170183```
171184
185+ You will also need to update the ` makeTestContentRecordDecl() ` function in the
186+ ` TestingMacros ` target to emit the correct ` @_section ` attribute for your
187+ platform. If your platform uses the ELF image format and supports the
188+ ` dl_iterate_phdr() ` function, add it to the existing ` #elseif os(Linux) || ... `
189+ case. Otherwise, add a new case for your platform:
190+
191+ ``` diff
192+ --- a/Sources/TestingMacros/Support/TestContentGeneration.swift
193+ +++ b/Sources/TestingMacros/Support/TestContentGeneration.swift
194+ // ...
195+ + #elseif os(Classic)
196+ + @_section(".rsrc,swft,__swift5_tests")
197+ #else
198+ @__testing(warning: "Platform-specific implementation missing: test content section name unavailable")
199+ #endif
200+ ```
201+
202+ Keep in mind that this code is emitted by the ` @Test ` and ` @Suite ` macros
203+ directly into test authors' test targets, so you will not be able to use
204+ compiler conditionals defined in the Swift Testing package (including those that
205+ start with ` "SWT_" ` ).
206+
172207## Runtime test discovery with static linkage
173208
174209If your platform does not support dynamic linking and loading, you will need to
175210use static linkage instead. Define the ` "SWT_NO_DYNAMIC_LINKING" ` compiler
176- conditional for your platform in both Package.swift and CompilerSettings.cmake,
177- then define the ` sectionBegin ` and ` sectionEnd ` symbols in Discovery.cpp:
211+ conditional for your platform in both ` Package.swift ` and
212+ ` CompilerSettings.cmake ` , then define the symbols ` testContentSectionBegin ` ,
213+ ` testContentSectionEnd ` , ` typeMetadataSectionBegin ` , and
214+ ` typeMetadataSectionEnd ` in ` Discovery.cpp ` .
178215
179216``` diff
180217diff --git a/Sources/_TestingInternals/Discovery.cpp b/Sources/_TestingInternals/Discovery.cpp
181218 // ...
182219+ #elif defined(macintosh)
183- + extern "C" const char sectionBegin __asm__("...");
184- + extern "C" const char sectionEnd __asm__("...");
220+ + extern "C" const char testContentSectionBegin __asm__("...");
221+ + extern "C" const char testContentSectionEnd __asm__("...");
222+ + extern "C" const char typeMetadataSectionBegin __asm__("...");
223+ + extern "C" const char typeMetadataSectionEnd __asm__("...");
185224 #else
186225 #warning Platform-specific implementation missing: Runtime test discovery unavailable (static)
187- static const char sectionBegin = 0;
188- static const char& sectionEnd = sectionBegin;
226+ static const char testContentSectionBegin = 0;
227+ static const char& testContentSectionEnd = testContentSectionBegin;
228+ static const char typeMetadataSectionBegin = 0;
229+ static const char& typeMetadataSectionEnd = testContentSectionBegin;
189230 #endif
190231```
191232
@@ -195,27 +236,6 @@ respectively. Their linker-level names will be platform-dependent: refer to the
195236linker documentation for your platform to determine what names to place in the
196237` __asm__ ` attribute applied to each.
197238
198- If you can't use ` __asm__ ` on your platform, you can declare these symbols as
199- C++ references to linker-defined symbols:
200-
201- ``` diff
202- diff --git a/Sources/_TestingInternals/Discovery.cpp b/Sources/_TestingInternals/Discovery.cpp
203- // ...
204- + #elif defined(macintosh)
205- + extern "C" const char __linker_defined_begin_symbol;
206- + extern "C" const char __linker_defined_end_symbol;
207- + static const auto& sectionBegin = __linker_defined_begin_symbol;
208- + static const auto& sectionEnd = __linker_defined_end_symbol;
209- #else
210- #warning Platform-specific implementation missing: Runtime test discovery unavailable (static)
211- static const char sectionBegin = 0;
212- static const char& sectionEnd = sectionBegin;
213- #endif
214- ```
215-
216- The names of ` __linker_defined_begin_symbol ` and ` __linker_defined_end_symbol `
217- in this example are, as with the shorter implementation, platform-dependent.
218-
219239## C++ stub implementations
220240
221241Some symbols defined in C and C++ headers, especially "complex" macros, cannot
0 commit comments