Skip to content

Commit 69e5636

Browse files
authored
Merge pull request #631 from owenv/owenv/object-library
Add initial support for object library product type
2 parents 5c1f405 + 1ed79ab commit 69e5636

28 files changed

+888
-25
lines changed

Sources/SWBCore/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ add_library(SWBCore
139139
SpecImplementations/Tools/MergeInfoPlist.swift
140140
SpecImplementations/Tools/MkdirTool.swift
141141
SpecImplementations/Tools/ModulesVerifierTool.swift
142+
SpecImplementations/Tools/ObjectLibraryAssembler.swift
142143
SpecImplementations/Tools/PLUtilTool.swift
143144
SpecImplementations/Tools/PrelinkedObjectLink.swift
144145
SpecImplementations/Tools/ProcessSDKImports.swift

Sources/SWBCore/PlannedTaskAction.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,8 @@ public protocol TaskActionCreationDelegate
347347
func createClangModuleVerifierInputGeneratorTaskAction() -> any PlannedTaskAction
348348
func createProcessSDKImportsTaskAction() -> any PlannedTaskAction
349349
func createValidateDependenciesTaskAction() -> any PlannedTaskAction
350+
func createObjectLibraryAssemblerTaskAction() -> any PlannedTaskAction
351+
func createLinkerTaskAction(expandResponseFiles: Bool) -> any PlannedTaskAction
350352
}
351353

352354
extension TaskActionCreationDelegate {

Sources/SWBCore/SpecImplementations/LinkerSpec.swift

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,16 @@ open class LinkerSpec : CommandLineToolSpec, @unchecked Sendable {
2424
case textBased
2525
case framework
2626
case object
27+
case objectLibrary
2728

2829
public var description: String {
2930
switch self {
30-
case .static: return "static library"
31-
case .dynamic: return "dynamic library"
32-
case .textBased: return "text-based stub"
33-
case .framework: return "framework"
34-
case .object: return "object file"
31+
case .static: return "static library"
32+
case .dynamic: return "dynamic library"
33+
case .textBased: return "text-based stub"
34+
case .framework: return "framework"
35+
case .object: return "object file"
36+
case .objectLibrary: return "object library"
3537
}
3638
}
3739
}
@@ -144,7 +146,7 @@ open class LinkerSpec : CommandLineToolSpec, @unchecked Sendable {
144146
/// Custom entry point for constructing linker tasks.
145147
public func constructLinkerTasks(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate, libraries: [LibrarySpecifier], usedTools: [CommandLineToolSpec: Set<FileTypeSpec>]) async {
146148
/// Delegate to the generic machinery.
147-
await delegate.createTask(type: self, ruleInfo: defaultRuleInfo(cbc, delegate), commandLine: commandLineFromTemplate(cbc, delegate, optionContext: discoveredCommandLineToolSpecInfo(cbc.producer, cbc.scope, delegate)).map(\.asString), environment: environmentFromSpec(cbc, delegate), workingDirectory: cbc.producer.defaultWorkingDirectory, inputs: cbc.inputs.map({ $0.absolutePath }), outputs: [cbc.output], action: nil, execDescription: resolveExecutionDescription(cbc, delegate), enableSandboxing: enableSandboxing)
149+
await delegate.createTask(type: self, ruleInfo: defaultRuleInfo(cbc, delegate), commandLine: commandLineFromTemplate(cbc, delegate, optionContext: discoveredCommandLineToolSpecInfo(cbc.producer, cbc.scope, delegate)).map(\.asString), environment: environmentFromSpec(cbc, delegate), workingDirectory: cbc.producer.defaultWorkingDirectory, inputs: cbc.inputs.map({ $0.absolutePath }), outputs: [cbc.output], action: createTaskAction(cbc, delegate), execDescription: resolveExecutionDescription(cbc, delegate), enableSandboxing: enableSandboxing)
148150
}
149151
}
150152

Sources/SWBCore/SpecImplementations/RegisterSpecs.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public struct BuiltinSpecsExtension: SpecificationsExtension {
5959
LibtoolLinkerSpec.self,
6060
LipoToolSpec.self,
6161
MkdirToolSpec.self,
62+
ObjectLibraryAssemblerSpec.self,
6263
PLUtilToolSpec.self,
6364
ProductPackagingToolSpec.self,
6465
ShellScriptToolSpec.self,

Sources/SWBCore/SpecImplementations/Tools/LinkerTools.swift

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,7 @@ public final class LdLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @unchec
918918
)
919919

920920
// Create the task.
921-
delegate.createTask(type: self, payload: payload, ruleInfo: defaultRuleInfo(cbc, delegate), commandLine: commandLine, environment: environmentFromSpec(cbc, delegate), workingDirectory: cbc.producer.defaultWorkingDirectory, inputs: inputs, outputs: outputs, action: nil, execDescription: resolveExecutionDescription(cbc, delegate), enableSandboxing: enableSandboxing)
921+
delegate.createTask(type: self, payload: payload, ruleInfo: defaultRuleInfo(cbc, delegate), commandLine: commandLine, environment: environmentFromSpec(cbc, delegate), workingDirectory: cbc.producer.defaultWorkingDirectory, inputs: inputs, outputs: outputs, action: createTaskAction(cbc, delegate), execDescription: resolveExecutionDescription(cbc, delegate), enableSandboxing: enableSandboxing)
922922
}
923923

924924
public func constructPreviewsBlankInjectionDylibTask(
@@ -992,7 +992,7 @@ public final class LdLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @unchec
992992
workingDirectory: cbc.producer.defaultWorkingDirectory,
993993
inputs: [],
994994
outputs: outputs,
995-
action: nil,
995+
action: createTaskAction(cbc, delegate),
996996
execDescription: resolveExecutionDescription(cbc, delegate),
997997
enableSandboxing: enableSandboxing
998998
)
@@ -1246,6 +1246,9 @@ public final class LdLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @unchec
12461246
case .object:
12471247
// Object files are added to linker inputs in the sources task producer.
12481248
return ([], [])
1249+
case .objectLibrary:
1250+
let pathFlags = specifier.absolutePathFlagsForLd()
1251+
return (pathFlags, [specifier.path])
12491252
}
12501253
}.reduce(([], [])) { (lhs, rhs) in (lhs.args + rhs.args, lhs.inputs + rhs.inputs) }
12511254
}
@@ -1367,6 +1370,11 @@ public final class LdLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @unchec
13671370
return LdLinkerOutputParser.self
13681371
}
13691372

1373+
override public func createTaskAction(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate) -> (any PlannedTaskAction)? {
1374+
let useResponseFile = cbc.scope.evaluate(BuiltinMacros.CLANG_USE_RESPONSE_FILE)
1375+
return delegate.taskActionCreationDelegate.createLinkerTaskAction(expandResponseFiles: !useResponseFile)
1376+
}
1377+
13701378
override public func discoveredCommandLineToolSpecInfo(_ producer: any CommandProducer, _ scope: MacroEvaluationScope, _ delegate: any CoreClientTargetDiagnosticProducingDelegate) async -> (any DiscoveredCommandLineToolSpecInfo)? {
13711379
// The ALTERNATE_LINKER is the 'name' of the linker not the executable name, clang will find the linker binary based on name passed via -fuse-ld, but we need to discover
13721380
// its properties by executing the actual binary. There is a common filename when the linker is not "ld" across all platforms using "ld.<ALTERNAME_LINKER>(.exe)"
@@ -1482,6 +1490,9 @@ fileprivate extension LinkerSpec.LibrarySpecifier {
14821490
case (.object, _):
14831491
// Object files are added to linker inputs in the sources task producer.
14841492
return []
1493+
case (.objectLibrary, _):
1494+
// Object libraries can't be found via search paths.
1495+
return []
14851496
}
14861497
}
14871498

@@ -1518,6 +1529,8 @@ fileprivate extension LinkerSpec.LibrarySpecifier {
15181529
case (.object, _):
15191530
// Object files are added to linker inputs in the sources task producer.
15201531
return []
1532+
case (.objectLibrary, _):
1533+
return ["@\(path.join("args.resp").str)"]
15211534
}
15221535
}
15231536
}
@@ -1574,6 +1587,11 @@ public final class LibtoolLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @u
15741587
}
15751588
}
15761589

1590+
override public func createTaskAction(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate) -> (any PlannedTaskAction)? {
1591+
let useResponseFile = cbc.scope.evaluate(BuiltinMacros.LIBTOOL_USE_RESPONSE_FILE)
1592+
return delegate.taskActionCreationDelegate.createLinkerTaskAction(expandResponseFiles: !useResponseFile)
1593+
}
1594+
15771595
override public func constructLinkerTasks(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate, libraries: [LibrarySpecifier], usedTools: [CommandLineToolSpec: Set<FileTypeSpec>]) async {
15781596
var inputPaths = cbc.inputs.map({ $0.absolutePath })
15791597
var specialArgs = [String]()
@@ -1619,6 +1637,10 @@ public final class LibtoolLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @u
16191637
// Object files are added to linker inputs in the sources task producer and so end up in the link-file-list.
16201638
return []
16211639

1640+
case .objectLibrary:
1641+
inputPaths.append(specifier.path)
1642+
return ["@\(specifier.path.join("args.resp").str)"]
1643+
16221644
case .framework:
16231645
// A static library can build against a framework, since the library in the framework could be a static library, which is valid, and we can't tell here whether it is or not. So we leave it to libtool to do the right thing here.
16241646
// Also, we wouldn't want to emit an error here even if we could determine that it contained a dylib, since the target might be only using the framework to find headers.
@@ -1710,7 +1732,7 @@ public final class LibtoolLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @u
17101732
workingDirectory: cbc.producer.defaultWorkingDirectory,
17111733
inputs: inputs,
17121734
outputs: outputs,
1713-
action: nil,
1735+
action: createTaskAction(cbc, delegate),
17141736
execDescription: resolveExecutionDescription(cbc, delegate),
17151737
enableSandboxing: enableSandboxing
17161738
)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
public final class ObjectLibraryAssemblerSpec : GenericLinkerSpec, SpecIdentifierType, @unchecked Sendable {
14+
public static let identifier: String = "org.swift.linkers.object-library-assembler"
15+
16+
public override func createTaskAction(_ cbc: CommandBuildContext, _ delegate: any TaskGenerationDelegate) -> (any PlannedTaskAction)? {
17+
return delegate.taskActionCreationDelegate.createObjectLibraryAssemblerTaskAction()
18+
}
19+
}

Sources/SWBCore/Specs/CoreBuildSystem.xcspec

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@
304304
"mh_bundle",
305305
staticlib,
306306
"mh_object",
307+
"objectlib",
307308
);
308309
DefaultValue = "";
309310
},
@@ -1351,6 +1352,9 @@ When `GENERATE_INFOPLIST_FILE` is enabled, sets the value of the [CFBundleIdenti
13511352
{
13521353
Value = "mh_object";
13531354
},
1355+
{
1356+
Value = "objectlib";
1357+
},
13541358
);
13551359
DefaultValue = "";
13561360
ConditionFlavors = (

Sources/SWBTaskConstruction/TaskProducers/BuildPhaseTaskProducers/SourcesTaskProducer.swift

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ package final class SourcesTaskProducer: FilesBasedBuildPhaseTaskProducerBase, F
356356
// When emitting remarks, for now, a dSYM is required (<rdar://problem/45458590>)
357357
let dSYMForRemarks = scope.evaluate(BuiltinMacros.CLANG_GENERATE_OPTIMIZATION_REMARKS)
358358
let dSYM = dSYMForDebugInfo || dSYMForRemarks
359-
return dSYM && scope.evaluate(BuiltinMacros.MACH_O_TYPE) != "staticlib" && scope.evaluate(BuiltinMacros.MACH_O_TYPE) != "mh_object"
359+
return dSYM && !["staticlib", "mh_object", "objectlib"].contains(scope.evaluate(BuiltinMacros.MACH_O_TYPE))
360360
}
361361

362362
/// Computes and returns a list of libraries to include when linking.
@@ -687,6 +687,15 @@ package final class SourcesTaskProducer: FilesBasedBuildPhaseTaskProducerBase, F
687687
xcframeworkSourcePath: xcframeworkPath,
688688
privacyFile: nil
689689
)
690+
} else if fileType.conformsTo(identifier: "compiled.object-library") {
691+
return LinkerSpec.LibrarySpecifier(
692+
kind: .objectLibrary,
693+
path: absolutePath,
694+
mode: .normal,
695+
useSearchPaths: false,
696+
swiftModulePaths: swiftModulePaths,
697+
swiftModuleAdditionalLinkerArgResponseFilePaths: swiftModuleAdditionalLinkerArgResponseFilePaths,
698+
)
690699
} else {
691700
// FIXME: Error handling.
692701
return nil
@@ -1640,21 +1649,33 @@ package final class SourcesTaskProducer: FilesBasedBuildPhaseTaskProducerBase, F
16401649

16411650
/// Compute the linker to use in the given scope.
16421651
private func getLinkerToUse(_ scope: MacroEvaluationScope) -> LinkerSpec {
1643-
let isStaticLib = scope.evaluate(BuiltinMacros.MACH_O_TYPE) == "staticlib"
1644-
1645-
// Return the custom linker, if specified.
1646-
var identifier = scope.evaluate(isStaticLib ? BuiltinMacros.LIBRARIAN : BuiltinMacros.LINKER)
1647-
if !identifier.isEmpty {
1648-
let spec = context.getSpec(identifier)
1649-
if let linker = spec as? LinkerSpec {
1650-
return linker
1652+
let identifier: String
1653+
switch scope.evaluate(BuiltinMacros.MACH_O_TYPE) {
1654+
case "objectlib":
1655+
identifier = ObjectLibraryAssemblerSpec.identifier
1656+
case "staticlib":
1657+
let override = scope.evaluate(BuiltinMacros.LIBRARIAN)
1658+
if !override.isEmpty {
1659+
let spec = context.getSpec(override)
1660+
if let linker = spec as? LinkerSpec {
1661+
return linker
1662+
}
1663+
1664+
// FIXME: Emit a warning here.
16511665
}
1666+
identifier = LibtoolLinkerSpec.identifier
1667+
default:
1668+
let override = scope.evaluate(BuiltinMacros.LINKER)
1669+
if !override.isEmpty {
1670+
let spec = context.getSpec(override)
1671+
if let linker = spec as? LinkerSpec {
1672+
return linker
1673+
}
16521674

1653-
// FIXME: Emit a warning here.
1675+
// FIXME: Emit a warning here.
1676+
}
1677+
identifier = LdLinkerSpec.identifier
16541678
}
1655-
1656-
// Return the default linker.
1657-
identifier = isStaticLib ? LibtoolLinkerSpec.identifier : LdLinkerSpec.identifier
16581679
return context.getSpec(identifier) as! LinkerSpec
16591680
}
16601681

Sources/SWBTaskExecution/BuildDescriptionManager.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,14 @@ extension BuildSystemTaskPlanningDelegate: TaskActionCreationDelegate {
895895
func createValidateDependenciesTaskAction() -> any PlannedTaskAction {
896896
return ValidateDependenciesTaskAction()
897897
}
898+
899+
func createObjectLibraryAssemblerTaskAction() -> any PlannedTaskAction {
900+
return ObjectLibraryAssemblerTaskAction()
901+
}
902+
903+
func createLinkerTaskAction(expandResponseFiles: Bool) -> any PlannedTaskAction {
904+
return LinkerTaskAction(expandResponseFiles: expandResponseFiles)
905+
}
898906
}
899907

900908
fileprivate extension BuildDescription {

Sources/SWBTaskExecution/BuiltinTaskActionsExtension.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ public struct BuiltinTaskActionsExtension: TaskActionExtension {
5353
38: GenericCachingTaskAction.self,
5454
39: ProcessSDKImportsTaskAction.self,
5555
40: ValidateDependenciesTaskAction.self,
56+
42: ObjectLibraryAssemblerTaskAction.self,
57+
43: LinkerTaskAction.self,
5658
]
5759
}
5860
}

0 commit comments

Comments
 (0)