Skip to content

Commit 10769c3

Browse files
authored
Merge pull request #971 from owenv/owenv/zipperplatformversion
Correctly specify platform_version when prelinking zippered binaries
2 parents bd8b331 + f4aa139 commit 10769c3

File tree

3 files changed

+161
-6
lines changed

3 files changed

+161
-6
lines changed

Sources/SWBCore/SpecImplementations/Tools/PrelinkedObjectLink.swift

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,23 @@ public final class PrelinkedObjectLinkSpec: CommandLineToolSpec, SpecImplementat
3535
var commandLine = [toolSpecInfo.toolPath.str]
3636
commandLine += ["-r", "-arch", arch]
3737

38-
if let buildPlatform = cbc.producer.sdk?.targetBuildVersionPlatform(sdkVariant: cbc.producer.sdkVariant),
39-
let deploymentTargetMacro = cbc.producer.platform?.deploymentTargetMacro,
40-
let minDeploymentTarget = cbc.scope.evaluate(deploymentTargetMacro).nilIfEmpty,
41-
let sdkVersion = cbc.producer.sdk?.version {
42-
commandLine += ["-platform_version", "\(buildPlatform.rawValue)", minDeploymentTarget, sdkVersion.canonicalDeploymentTargetForm.description]
38+
if let sdk = cbc.producer.sdk, let sdkVersion = sdk.version {
39+
for buildPlatform in cbc.producer.targetBuildVersionPlatforms(in: cbc.scope)?.sorted() ?? [] {
40+
let deploymentTargetSettingName = buildPlatform.deploymentTargetSettingName(infoLookup: cbc.producer)
41+
if let minDeploymentTarget = cbc.scope.evaluate(cbc.scope.namespace.parseString("$(\(deploymentTargetSettingName)")).nilIfEmpty {
42+
let version: Version
43+
if cbc.scope.evaluate(BuiltinMacros.IS_ZIPPERED) && buildPlatform == .macCatalyst {
44+
guard let correspondingVersion = sdk.versionMap["macOS_iOSMac"]?[sdkVersion] else {
45+
delegate.error("'\(sdk.canonicalName)' is missing a Mac Catalyst version mapping for '\(sdkVersion)'")
46+
continue
47+
}
48+
version = correspondingVersion
49+
} else {
50+
version = sdkVersion
51+
}
52+
commandLine += ["-platform_version", "\(buildPlatform.rawValue)", minDeploymentTarget, version.canonicalDeploymentTargetForm.description]
53+
}
54+
}
4355
}
4456

4557
// We do not pass the deployment target to the linker here. Instead the linker infers the platform and deployment target from the .o files being collected. We did briefly pass it to the linker to silence a linker warning - if we ever see issues here we should confer with the linker folks to make sure we do the right thing. See <rdar://problem/51800525> for more about the history here.

Sources/SWBUtil/MachO.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public protocol PlatformInfoProvider {
8181
public struct BuildVersion: Equatable, Hashable, Sendable {
8282
/// Enumerates platforms as defined by dyld.
8383
///
84-
public struct Platform: RawRepresentable, Equatable, Hashable, Serializable, Sendable {
84+
public struct Platform: RawRepresentable, Equatable, Hashable, Serializable, Sendable, Comparable {
8585
public typealias RawValue = UInt32
8686

8787
public static let macOS = Self(platformID: 1)

Tests/SWBTaskConstructionTests/PrelinkedObjectFileTests.swift

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,149 @@ fileprivate struct PrelinkedObjectFileTests: CoreBasedTests {
221221
}
222222
}
223223

224+
@Test(.requireSDKs(.macOS, .iOS))
225+
func prelinkedObjectFileGenerationVariant_zippered() async throws {
226+
let core = try await getCore()
227+
// Test that a prelinked object file gets generated even if the target contains no sources or libraries in its build phases.
228+
let testProject = TestProject(
229+
"aProject",
230+
groupTree: TestGroup(
231+
"SomeFiles", path: "Sources",
232+
children: [
233+
]),
234+
buildConfigurations: [
235+
TestBuildConfiguration(
236+
"Debug",
237+
buildSettings: [
238+
"PRODUCT_NAME": "$(TARGET_NAME)",
239+
"MACOSX_DEPLOYMENT_TARGET": core.loadSDK(.macOS).defaultDeploymentTarget,
240+
"IPHONEOS_DEPLOYMENT_TARGET": core.loadSDK(.iOS).defaultDeploymentTarget,
241+
"SDKROOT": "macosx",
242+
"IS_ZIPPERED": "YES",
243+
]),
244+
],
245+
targets: [
246+
TestStandardTarget(
247+
"AllLibraries",
248+
type: .staticLibrary,
249+
buildConfigurations: [
250+
TestBuildConfiguration(
251+
"Debug",
252+
buildSettings: [
253+
"GENERATE_PRELINK_OBJECT_FILE": "YES",
254+
]),
255+
],
256+
buildPhases: [
257+
TestSourcesBuildPhase([]),
258+
TestFrameworksBuildPhase([]),
259+
],
260+
dependencies: ["Tool"]),
261+
])
262+
let testWorkspace = TestWorkspace("aWorkspace", projects: [testProject])
263+
let tester = try TaskConstructionTester(core, testWorkspace)
264+
let SRCROOT = tester.workspace.projects[0].sourceRoot.str
265+
266+
// Check a build for MacCatalyst.
267+
await tester.checkBuild(runDestination: .macCatalyst, fs: localFS) { results in
268+
// Ignore all tasks we don't want to check.
269+
results.checkTasks(.matchRuleType("Gate")) { _ in }
270+
results.checkTasks(.matchRuleType("WriteAuxiliaryFile")) { _ in }
271+
results.checkTasks(.matchRuleType("CreateBuildDirectory")) { _ in }
272+
results.checkTasks(.matchRuleType("RegisterExecutionPolicyException")) { _ in }
273+
274+
results.checkTarget("AllLibraries") { target in
275+
// There should be tasks to create the prelinked object file and then the static library.
276+
results.checkTask(.matchTarget(target), .matchRuleType("PrelinkedObjectLink")) { task in
277+
task.checkCommandLineMatches([.suffix("ld"), "-r", "-arch", .equal(results.runDestinationTargetArchitecture), "-platform_version", "1", .any, .any, "-platform_version", "6", .any, .any, "-syslibroot", .equal(core.loadSDK(.macOS).path.str), "-o", .equal("\(SRCROOT)/build/aProject.build/Debug/AllLibraries.build/Objects-normal/libAllLibraries.a-\(results.runDestinationTargetArchitecture)-prelink.o")])
278+
}
279+
results.checkTask(.matchTarget(target), .matchRuleType("Libtool")) { task in
280+
task.checkCommandLineMatches([.suffix("libtool"), "-static", "-arch_only", .equal(results.runDestinationTargetArchitecture), "-D", "-syslibroot", .equal(core.loadSDK(.macOS).path.str), .equal("-L\(SRCROOT)/build/Debug"), "-filelist", .equal("\(SRCROOT)/build/aProject.build/Debug/AllLibraries.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AllLibraries.LinkFileList"), "-dependency_info", "\(SRCROOT)/build/aProject.build/Debug/AllLibraries.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AllLibraries_libtool_dependency_info.dat", "-o", .equal("\(SRCROOT)/build/Debug/libAllLibraries.a")])
281+
}
282+
}
283+
284+
// There should be no other tasks.
285+
results.checkNoTask()
286+
287+
// There shouldn't be any diagnostics.
288+
results.checkNoDiagnostics()
289+
290+
// Check there are no other targets.
291+
#expect(results.otherTargets == [])
292+
}
293+
}
294+
295+
@Test(.requireSDKs(.macOS, .iOS))
296+
func prelinkedObjectFileGenerationVariant_reverseZippered() async throws {
297+
let core = try await getCore()
298+
// Test that a prelinked object file gets generated even if the target contains no sources or libraries in its build phases.
299+
let testProject = TestProject(
300+
"aProject",
301+
groupTree: TestGroup(
302+
"SomeFiles", path: "Sources",
303+
children: [
304+
]),
305+
buildConfigurations: [
306+
TestBuildConfiguration(
307+
"Debug",
308+
buildSettings: [
309+
"PRODUCT_NAME": "$(TARGET_NAME)",
310+
"MACOSX_DEPLOYMENT_TARGET": core.loadSDK(.macOS).defaultDeploymentTarget,
311+
"IPHONEOS_DEPLOYMENT_TARGET": core.loadSDK(.iOS).defaultDeploymentTarget,
312+
"SDKROOT": "macosx",
313+
"IS_ZIPPERED": "YES",
314+
"SDK_VARIANT": MacCatalystInfo.sdkVariantName,
315+
]),
316+
],
317+
targets: [
318+
TestStandardTarget(
319+
"AllLibraries",
320+
type: .staticLibrary,
321+
buildConfigurations: [
322+
TestBuildConfiguration(
323+
"Debug",
324+
buildSettings: [
325+
"GENERATE_PRELINK_OBJECT_FILE": "YES",
326+
]),
327+
],
328+
buildPhases: [
329+
TestSourcesBuildPhase([]),
330+
TestFrameworksBuildPhase([]),
331+
],
332+
dependencies: ["Tool"]),
333+
])
334+
let testWorkspace = TestWorkspace("aWorkspace", projects: [testProject])
335+
let tester = try TaskConstructionTester(core, testWorkspace)
336+
let SRCROOT = tester.workspace.projects[0].sourceRoot.str
337+
338+
// Check a build for MacCatalyst.
339+
await tester.checkBuild(runDestination: .macCatalyst, fs: localFS) { results in
340+
// Ignore all tasks we don't want to check.
341+
results.checkTasks(.matchRuleType("Gate")) { _ in }
342+
results.checkTasks(.matchRuleType("WriteAuxiliaryFile")) { _ in }
343+
results.checkTasks(.matchRuleType("CreateBuildDirectory")) { _ in }
344+
results.checkTasks(.matchRuleType("RegisterExecutionPolicyException")) { _ in }
345+
346+
results.checkTarget("AllLibraries") { target in
347+
// There should be tasks to create the prelinked object file and then the static library.
348+
results.checkTask(.matchTarget(target), .matchRuleType("PrelinkedObjectLink")) { task in
349+
task.checkCommandLineMatches([.suffix("ld"), "-r", "-arch", .equal(results.runDestinationTargetArchitecture), "-platform_version", "1", .any, .any, "-platform_version", "6", .any, .any, "-syslibroot", .equal(core.loadSDK(.macOS).path.str), "-o", .equal("\(SRCROOT)/build/aProject.build/Debug-maccatalyst/AllLibraries.build/Objects-normal/libAllLibraries.a-\(results.runDestinationTargetArchitecture)-prelink.o")])
350+
}
351+
results.checkTask(.matchTarget(target), .matchRuleType("Libtool")) { task in
352+
task.checkCommandLineMatches([.suffix("libtool"), "-static", "-arch_only", .equal(results.runDestinationTargetArchitecture), "-D", "-syslibroot", .equal(core.loadSDK(.macOS).path.str), .equal("-L\(SRCROOT)/build/Debug-maccatalyst"), "-L\(core.loadSDK(.macOS).path.str)/System/iOSSupport/usr/lib", "-L\(core.developerPath.path.str)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/maccatalyst", "-L\(core.loadSDK(.macOS).path.str)/System/iOSSupport/usr/lib", "-L\(core.developerPath.path.str)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/maccatalyst", "-filelist", .equal("\(SRCROOT)/build/aProject.build/Debug-maccatalyst/AllLibraries.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AllLibraries.LinkFileList"), "-dependency_info", "\(SRCROOT)/build/aProject.build/Debug-maccatalyst/AllLibraries.build/Objects-normal/\(results.runDestinationTargetArchitecture)/AllLibraries_libtool_dependency_info.dat", "-o", .equal("\(SRCROOT)/build/Debug-maccatalyst/libAllLibraries.a")])
353+
}
354+
}
355+
356+
// There should be no other tasks.
357+
results.checkNoTask()
358+
359+
// There shouldn't be any diagnostics.
360+
results.checkNoDiagnostics()
361+
362+
// Check there are no other targets.
363+
#expect(results.otherTargets == [])
364+
}
365+
}
366+
224367
@Test(.requireSDKs(.iOS))
225368
func prelinkedObjectFileGenerationVariant_ios() async throws {
226369
let core = try await getCore()

0 commit comments

Comments
 (0)