Skip to content

Commit 86fb8c0

Browse files
authored
Merge pull request #865 from owenv/owenv/stub-processing
Unify stub binary processing for XCTRunner/messages apps/watch apps
2 parents bc2e7d9 + 2b1711c commit 86fb8c0

File tree

9 files changed

+59
-55
lines changed

9 files changed

+59
-55
lines changed

Sources/SWBApplePlatform/StubBinaryTaskProducer.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ fileprivate func generateStubBinaryTasks(stubBinarySourcePath: Path, archs: [Str
4141
func copyBinary(_ cbc: CommandBuildContext, executionDescription: String) async {
4242
// If we have no architectures, then simply copy the binary as-is
4343
if thinArchs && !archs.isEmpty {
44-
context.lipoSpec.constructCopyAndProcessArchsTasks(cbc, delegate, executionDescription: executionDescription, archsToPreserve: archs)
44+
delegate.access(path: stubBinarySourcePath)
45+
context.lipoSpec.constructCopyAndProcessArchsTasks(cbc, delegate, executionDescription: executionDescription, archsToPreserve: await context.availableMatchingArchitecturesInStubBinary(at: stubBinarySourcePath, requestedArchs: archs))
4546
} else {
4647
await context.copySpec.constructCopyTasks(cbc, delegate, executionDescription: executionDescription, stripUnsignedBinaries: false, stripBitcode: false)
4748
}

Sources/SWBCore/SpecImplementations/Tools/Lipo.swift

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,6 @@ public final class LipoToolSpec: GenericCommandLineToolSpec, SpecIdentifierType,
7272
delegate.createTask(type: self, ruleInfo: ["CreateUniversalBinary", outputPath.str, variant, archsString], commandLine: commandLine, environment: EnvironmentBindings(), workingDirectory: cbc.producer.defaultWorkingDirectory, inputs: cbc.inputs.map({ delegate.createNode($0.absolutePath) }), outputs: outputs, action: delegate.taskActionCreationDelegate.createDeferredExecutionTaskActionIfRequested(userPreferences: cbc.producer.userPreferences), execDescription: resolveExecutionDescription(cbc, delegate), enableSandboxing: enableSandboxing)
7373
}
7474

75-
/// Invoke lipo to copy a fat Mach-O to a destination path with certain architectures removed.
76-
public func constructCopyAndProcessArchsTasks(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate, executionDescription: String? = nil, archsToRemove: [String]) {
77-
return constructCopyAndProcessArchsTasks(cbc, delegate, executionDescription: executionDescription, archsToProcess: archsToRemove, flag: "-remove", ruleName: "CopyAndRemoveArchs")
78-
}
79-
8075
/// Invoke lipo to copy a fat Mach-O to a destination path with only certain architectures preserved, and the rest removed.
8176
public func constructCopyAndProcessArchsTasks(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate, executionDescription: String? = nil, archsToPreserve: [String]) {
8277
return constructCopyAndProcessArchsTasks(cbc, delegate, executionDescription: executionDescription, archsToProcess: archsToPreserve, flag: "-extract", ruleName: "CopyAndPreserveArchs")

Sources/SWBTaskConstruction/TaskProducers/OtherTaskProducers/XCTestProductTypeTaskProducer.swift

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -81,27 +81,6 @@ final class XCTestProductPostprocessingTaskProducer: PhasedTaskProducer, TaskPro
8181
return tasks
8282
}
8383

84-
private func archsForXCTRunner(_ scope: MacroEvaluationScope) -> (required: Set<String>, optional: Set<String>) {
85-
// The XCTestRunner is required to have at least the same ARCHS as our test bundle, minus the arm64e and/or x86_64h subtypes of their respective architecture family. The removal logic ensures we always get a link-compatible result.
86-
var requiredArchs = Set(scope.evaluate(BuiltinMacros.ARCHS))
87-
var optionalArchs = Set<String>()
88-
89-
let linkCompatibleArchPairs = [
90-
("arm64e", "arm64"),
91-
("x86_64h", "x86_64"),
92-
]
93-
94-
for (arch, baseline) in linkCompatibleArchPairs {
95-
if requiredArchs.contains(baseline) {
96-
if let foundArch = requiredArchs.remove(arch) {
97-
optionalArchs.insert(foundArch)
98-
}
99-
}
100-
}
101-
102-
return (requiredArchs, optionalArchs)
103-
}
104-
10584
/// A test target which is configured to use an XCTRunner will do the following:
10685
///
10786
/// - Copy `XCTRunner.app` out of the platform being built for into the original target build dir using the name `$(XCTRUNNER_PRODUCT_NAME)` (where `$(PRODUCT_NAME)` is the test target's product name).
@@ -218,19 +197,7 @@ final class XCTestProductPostprocessingTaskProducer: PhasedTaskProducer, TaskPro
218197
continue
219198
}
220199

221-
let (requiredArchs, optionalArchs) = archsForXCTRunner(scope)
222-
archsToPreserve = requiredArchs
223-
224-
// If we have any optional architectures, add the subset of those which the XCTRunner binary actually has
225-
if !optionalArchs.isEmpty {
226-
archsToPreserve.formUnion(optionalArchs.intersection(runnerArchs))
227-
}
228-
229-
let missingArchs = archsToPreserve.subtracting(runnerArchs)
230-
if !missingArchs.isEmpty {
231-
// This is a warning instead of an error to ease future architecture bringup
232-
delegate.warning("missing architectures (\(missingArchs.sorted().joined(separator: ", "))) in XCTRunner.app: \(inputPath.str)")
233-
}
200+
archsToPreserve = Set(await context.availableMatchingArchitecturesInStubBinary(at: inputPath, requestedArchs: scope.evaluate(BuiltinMacros.ARCHS)))
234201

235202
// If the runner has only one architecture, perform a direct file copy since lipo can't use -extract on thin Mach-Os
236203
if runnerArchs.count == 1 {

Sources/SWBTaskConstruction/TaskProducers/TaskProducer.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,31 @@ public class TaskProducerContext: StaleFileRemovalContext, BuildFileResolution
818818
return false
819819
}
820820

821+
public func availableMatchingArchitecturesInStubBinary(at stubBinary: Path, requestedArchs: [String]) async -> [String] {
822+
let stubArchs: Set<String>
823+
do {
824+
stubArchs = try globalProductPlan.planRequest.buildRequestContext.getCachedMachOInfo(at: stubBinary).architectures
825+
} catch {
826+
delegate.error("unable to create tasks to copy stub binary: can't determine architectures of binary: \(stubBinary.str): \(error)")
827+
return []
828+
}
829+
var archsToExtract: Set<String> = []
830+
for arch in requestedArchs {
831+
if stubArchs.contains(arch) {
832+
archsToExtract.insert(arch)
833+
} else {
834+
let specLookupContext = SpecLookupCtxt(specRegistry: workspaceContext.core.specRegistry, platform: settings.platform)
835+
let compatibilityArchs = (specLookupContext.getSpec(arch) as? ArchitectureSpec)?.compatibilityArchs
836+
if let compatibleArch = compatibilityArchs?.first(where: { stubArchs.contains($0) }) {
837+
archsToExtract.insert(compatibleArch)
838+
} else {
839+
delegate.warning("stub binary at '\(stubBinary.str)' does not contain a slice for '\(arch)' or a compatible architecture")
840+
}
841+
}
842+
}
843+
return archsToExtract.sorted()
844+
}
845+
821846
/// Returns true if we should emit errors when there are tasks that delay eager compilation.
822847
func requiresEagerCompilation(_ scope: MacroEvaluationScope) -> Bool {
823848
return scope.evaluate(BuiltinMacros.EAGER_COMPILATION_REQUIRE)

Sources/SWBTestSupport/FSUtilities.swift

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -397,15 +397,18 @@ package extension FSProxy {
397397

398398
func writeSimulatedWatchKitSupportFiles(watchosSDK: TestSDKInfo, watchSimulatorSDK: TestSDKInfo) throws {
399399
try createDirectory(watchosSDK.path.join("Library/Application Support/WatchKit"), recursive: true)
400-
try write(watchosSDK.path.join("Library/Application Support/WatchKit/WK"), contents: "WatchKitStub")
400+
let stubPath = watchosSDK.path.join("Library/Application Support/WatchKit/WK")
401+
try write(stubPath, contents: localFS.read(stubPath))
401402
try createDirectory(watchSimulatorSDK.path.join("Library/Application Support/WatchKit"), recursive: true)
402-
try write(watchSimulatorSDK.path.join("Library/Application Support/WatchKit/WK"), contents: "WatchKitStub")
403+
let simStubPath = watchSimulatorSDK.path.join("Library/Application Support/WatchKit/WK")
404+
try write(simStubPath, contents: localFS.read(simStubPath))
403405
}
404406

405407
func writeSimulatedMessagesAppSupportFiles(iosSDK: TestSDKInfo) async throws {
406408
try createDirectory(iosSDK.path.join("../../../Library/Application Support/MessagesApplicationStub"), recursive: true)
407409
try await writeAssetCatalog(iosSDK.path.join("../../../Library/Application Support/MessagesApplicationStub/MessagesApplicationStub.xcassets"), .appIcon("MessagesApplicationStub"))
408-
try write(iosSDK.path.join("../../../Library/Application Support/MessagesApplicationStub/MessagesApplicationStub"), contents: "stub")
410+
let messagesStubPath = iosSDK.path.join("../../../Library/Application Support/MessagesApplicationStub/MessagesApplicationStub")
411+
try write(messagesStubPath, contents: localFS.read(messagesStubPath))
409412
try await writeStoryboard(iosSDK.path.join("../../../Library/Application Support/MessagesApplicationStub/LaunchScreen.storyboard"), .iOS)
410413
}
411414

Tests/SWBBuildSystemTests/WatchBuildOperationTests.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,11 @@ fileprivate struct WatchBuildOperationTests: CoreBasedTests {
141141
try fs.createDirectory(Path("/Users/whoever/Library/MobileDevice/Provisioning Profiles"), recursive: true)
142142
try fs.write(Path("/Users/whoever/Library/MobileDevice/Provisioning Profiles/8db0e92c-592c-4f06-bfed-9d945841b78d.mobileprovision"), contents: "profile")
143143
try fs.createDirectory(core.loadSDK(.watchOS).path.join("Library/Application Support/WatchKit"), recursive: true)
144-
try fs.write(core.loadSDK(.watchOS).path.join("Library/Application Support/WatchKit/WK"), contents: "WatchKitStub")
144+
let stubPath = core.loadSDK(.watchOS).path.join("Library/Application Support/WatchKit/WK")
145+
try fs.write(stubPath, contents: localFS.read(stubPath))
145146
try fs.createDirectory(core.loadSDK(.watchOSSimulator).path.join("Library/Application Support/WatchKit"), recursive: true)
146-
try fs.write(core.loadSDK(.watchOSSimulator).path.join("Library/Application Support/WatchKit/WK"), contents: "WatchKitStub")
147+
let simStubPath = core.loadSDK(.watchOSSimulator).path.join("Library/Application Support/WatchKit/WK")
148+
try fs.write(simStubPath, contents: localFS.read(simStubPath))
147149

148150
// Create the iOS stub assets in the wrong SDK so the build doesn't fail early due to missing inputs.
149151
try fs.createDirectory(core.loadSDK(.watchOS).path.join("../../../Library/Application Support/MessagesApplicationStub"), recursive: true)
@@ -157,6 +159,7 @@ fileprivate struct WatchBuildOperationTests: CoreBasedTests {
157159
}
158160
results.checkWarning(.contains("Could not read serialized diagnostics file"))
159161
results.checkError(.equal("[targetIntegrity] Watch-Only Application Stubs are not available when building for watchOS. (in target 'Watchable' from project 'aProject')"))
162+
results.checkError(.prefix("unable to create tasks to copy stub binary"))
160163
results.checkWarning(.contains("Unable to perform dependency info modifications"))
161164
results.checkNoDiagnostics()
162165
}

Tests/SWBTaskConstructionTests/PlatformTaskConstructionTests.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -551,9 +551,11 @@ fileprivate struct PlatformTaskConstructionTests: CoreBasedTests {
551551
try fs.write(Path("/Users/whoever/Library/MobileDevice/Provisioning Profiles/8db0e92c-592c-4f06-bfed-9d945841b78d.mobileprovision"), contents: "profile")
552552
try fs.createDirectory(Path("/tmp/Test/aProject/Stickers.xcstickers/Sticker Pack.stickerpack"), recursive: true)
553553
try fs.createDirectory(platformPath.join("Library/Application Support/MessagesApplicationStub"), recursive: true)
554-
try fs.write(platformPath.join("Library/Application Support/MessagesApplicationStub/MessagesApplicationStub"), contents: "MessagesApplicationStub")
554+
let stubPath = platformPath.join("Library/Application Support/MessagesApplicationStub/MessagesApplicationStub")
555+
try fs.write(stubPath, contents: localFS.read(stubPath))
555556
try fs.createDirectory(platformPath.join("Library/Application Support/MessagesApplicationExtensionStub"), recursive: true)
556-
try fs.write(platformPath.join("Library/Application Support/MessagesApplicationExtensionStub/MessagesApplicationExtensionStub"), contents: "MessagesApplicationExtensionStub")
557+
let extensionStubPath = platformPath.join("Library/Application Support/MessagesApplicationExtensionStub/MessagesApplicationExtensionStub")
558+
try fs.write(extensionStubPath, contents: localFS.read(extensionStubPath))
557559
try fs.createDirectory(tester.workspace.projects[0].sourceRoot, recursive: true)
558560
try fs.write(tester.workspace.projects[0].sourceRoot.join("Info.plist"), contents: "<dict/>")
559561

Tests/SWBTaskConstructionTests/UnitTestTaskConstructionTests.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1310,9 +1310,11 @@ fileprivate struct UnitTestTaskConstructionTests: CoreBasedTests {
13101310
try fs.write(watchsimframeworkPath, contents: ByteString(encodingAsUTF8: watchosframeworkPath.basename))
13111311
}
13121312
try fs.createDirectory(core.loadSDK(.watchOS).path.join("Library/Application Support/WatchKit"), recursive: true)
1313-
try fs.write(core.loadSDK(.watchOS).path.join("Library/Application Support/WatchKit/WK"), contents: "WatchKitStub")
1313+
let stubPath = core.loadSDK(.watchOS).path.join("Library/Application Support/WatchKit/WK")
1314+
try fs.write(stubPath, contents: localFS.read(stubPath))
13141315
try fs.createDirectory(core.loadSDK(.watchOSSimulator).path.join("Library/Application Support/WatchKit"), recursive: true)
1315-
try fs.write(core.loadSDK(.watchOSSimulator).path.join("Library/Application Support/WatchKit/WK"), contents: "WatchKitStub")
1316+
let simStubPath = core.loadSDK(.watchOSSimulator).path.join("Library/Application Support/WatchKit/WK")
1317+
try fs.write(simStubPath, contents: localFS.read(simStubPath))
13161318

13171319
// We build the app target and the test target.
13181320
let topLevelTargets = [tester.workspace.projects[0].targets[0], tester.workspace.projects[0].targets[2]]

Tests/SWBTaskConstructionTests/WatchTaskConstructionTests.swift

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -198,9 +198,11 @@ fileprivate struct WatchTaskConstructionTests: CoreBasedTests {
198198
try fs.createDirectory(Path("/Users/whoever/Library/MobileDevice/Provisioning Profiles"), recursive: true)
199199
try fs.write(Path("/Users/whoever/Library/MobileDevice/Provisioning Profiles/8db0e92c-592c-4f06-bfed-9d945841b78d.mobileprovision"), contents: "profile")
200200
try fs.createDirectory(core.loadSDK(.watchOS).path.join("Library/Application Support/WatchKit"), recursive: true)
201-
try fs.write(core.loadSDK(.watchOS).path.join("Library/Application Support/WatchKit/WK"), contents: "WatchKitStub")
201+
let stubPath = core.loadSDK(.watchOS).path.join("Library/Application Support/WatchKit/WK")
202+
try fs.write(stubPath, contents: localFS.read(stubPath))
202203
try fs.createDirectory(core.loadSDK(.watchOSSimulator).path.join("Library/Application Support/WatchKit"), recursive: true)
203-
try fs.write(core.loadSDK(.watchOSSimulator).path.join("Library/Application Support/WatchKit/WK"), contents: "WatchKitStub")
204+
let simStubPath = core.loadSDK(.watchOSSimulator).path.join("Library/Application Support/WatchKit/WK")
205+
try fs.write(simStubPath, contents: localFS.read(simStubPath))
204206

205207
let actoolPath = try await self.actoolPath
206208

@@ -1111,12 +1113,15 @@ fileprivate struct WatchTaskConstructionTests: CoreBasedTests {
11111113
try fs.createDirectory(Path("/Users/whoever/Library/MobileDevice/Provisioning Profiles"), recursive: true)
11121114
try fs.write(Path("/Users/whoever/Library/MobileDevice/Provisioning Profiles/8db0e92c-592c-4f06-bfed-9d945841b78d.mobileprovision"), contents: "profile")
11131115
try fs.createDirectory(core.loadSDK(.watchOS).path.join("Library/Application Support/WatchKit"), recursive: true)
1114-
try fs.write(core.loadSDK(.watchOS).path.join("Library/Application Support/WatchKit/WK"), contents: "WatchKitStub")
1116+
let stubPath = core.loadSDK(.watchOS).path.join("Library/Application Support/WatchKit/WK")
1117+
try fs.write(stubPath, contents: localFS.read(stubPath))
11151118
try fs.createDirectory(core.loadSDK(.watchOSSimulator).path.join("Library/Application Support/WatchKit"), recursive: true)
1116-
try fs.write(core.loadSDK(.watchOSSimulator).path.join("Library/Application Support/WatchKit/WK"), contents: "WatchKitStub")
1119+
let simStubPath = core.loadSDK(.watchOSSimulator).path.join("Library/Application Support/WatchKit/WK")
1120+
try fs.write(simStubPath, contents: localFS.read(simStubPath))
11171121
try fs.createDirectory(core.loadSDK(.iOS).path.join("../../../Library/Application Support/MessagesApplicationStub"), recursive: true)
11181122
try await fs.writeAssetCatalog(core.loadSDK(.iOS).path.join("../../../Library/Application Support/MessagesApplicationStub/MessagesApplicationStub.xcassets"), .appIcon("MessagesApplicationStub"))
1119-
try fs.write(core.loadSDK(.iOS).path.join("../../../Library/Application Support/MessagesApplicationStub/MessagesApplicationStub"), contents: "stub")
1123+
let messagesStubPath = core.loadSDK(.iOS).path.join("../../../Library/Application Support/MessagesApplicationStub/MessagesApplicationStub")
1124+
try fs.write(messagesStubPath, contents: localFS.read(messagesStubPath))
11201125

11211126
let actoolPath = try await self.actoolPath
11221127

@@ -1346,7 +1351,8 @@ fileprivate struct WatchTaskConstructionTests: CoreBasedTests {
13461351

13471352
let fs = PseudoFS()
13481353
try fs.createDirectory(core.loadSDK(.watchOS).path.join("Library/Application Support/WatchKit"), recursive: true)
1349-
try fs.write(core.loadSDK(.watchOS).path.join("Library/Application Support/WatchKit/WK"), contents: "WatchKitStub")
1354+
let stubPath = core.loadSDK(.watchOS).path.join("Library/Application Support/WatchKit/WK")
1355+
try fs.write(stubPath, contents: localFS.read(stubPath))
13501356

13511357
let params = BuildParameters(action: .archive, configuration: "Debug", overrides: ["WATCHKIT_2_SUPPORT_FOLDER_PATH": "/tmp/SideCars"])
13521358
await tester.checkBuild(params, runDestination: .macOS, fs: fs) { results in

0 commit comments

Comments
 (0)