Skip to content

Commit 8693c3a

Browse files
committed
When an object file is in the Frameworks build phase of a static library target, don't add it to both the command line and the link-file-list of the libtool task.
This matches the behavior for ld of only putting it in the link-file-list. Also modify some tests to check this behavior. rdar://136958525
1 parent ad1e06a commit 8693c3a

File tree

3 files changed

+20
-9
lines changed

3 files changed

+20
-9
lines changed

Sources/SWBCore/SpecImplementations/Tools/LinkerTools.swift

+2-3
Original file line numberDiff line numberDiff line change
@@ -1530,9 +1530,8 @@ public final class LibtoolLinkerSpec : GenericLinkerSpec, SpecIdentifierType, @u
15301530
}
15311531

15321532
case .object:
1533-
// A static library can bring in the contents of a .o file.
1534-
inputPaths.append(specifier.path)
1535-
return [specifier.path.str]
1533+
// Object files are added to linker inputs in the sources task producer and so end up in the link-file-list.
1534+
return []
15361535

15371536
case .framework:
15381537
// 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.

Tests/SWBCoreTests/CommandLineSpecTests.swift

+5-3
Original file line numberDiff line numberDiff line change
@@ -1261,11 +1261,10 @@ import SWBMacro
12611261
}
12621262
var libraries = [LinkerSpec.LibrarySpecifier]()
12631263
for kind in LinkerSpec.LibrarySpecifier.Kind.allCases {
1264-
guard kind != .object else {
1265-
continue
1266-
}
12671264
libraries.append(contentsOf: generateLibrarySpecifiers(kind: kind))
12681265
}
1266+
// This is a no-op because object files get added in the SourcesTaskProducer, but we want to confirm that this is the case.
1267+
libraries.append(LinkerSpec.LibrarySpecifier(kind: .object, path: Path.root.join("tmp/Bar.o"), mode: .normal, useSearchPaths: false, swiftModulePaths: [:], swiftModuleAdditionalLinkerArgResponseFilePaths: [:]))
12691268

12701269
await linkerSpec.constructLinkerTasks(cbc, delegate, libraries: libraries, usedTools: [:])
12711270

@@ -1501,6 +1500,9 @@ import SWBMacro
15011500
LinkerSpec.LibrarySpecifier(kind: .framework, path: Path.root.join("tmp/Foo2.framework"), mode: .weak, useSearchPaths: true, swiftModulePaths: [:], swiftModuleAdditionalLinkerArgResponseFilePaths: [:]),
15021501
LinkerSpec.LibrarySpecifier(kind: .framework, path: Path.root.join("tmp/Foo3.framework"), mode: .normal, useSearchPaths: false, swiftModulePaths: [:], swiftModuleAdditionalLinkerArgResponseFilePaths: [:]),
15031502
LinkerSpec.LibrarySpecifier(kind: .framework, path: Path.root.join("tmp/Foo4.framework"), mode: .weak, useSearchPaths: false, swiftModulePaths: [:], swiftModuleAdditionalLinkerArgResponseFilePaths: [:]),
1503+
1504+
// This is a no-op because object files get added in the SourcesTaskProducer, but we want to confirm that this is the case.
1505+
LinkerSpec.LibrarySpecifier(kind: .object, path: Path.root.join("tmp/Bar.o"), mode: .normal, useSearchPaths: false, swiftModulePaths: [:], swiftModuleAdditionalLinkerArgResponseFilePaths: [:]),
15041506
]
15051507
await librarianSpec.constructLinkerTasks(cbc, delegate, libraries: libraries, usedTools: [:])
15061508

Tests/SWBTaskConstructionTests/TaskConstructionTests.swift

+13-3
Original file line numberDiff line numberDiff line change
@@ -4966,7 +4966,7 @@ fileprivate struct TaskConstructionTests: CoreBasedTests {
49664966
TestBuildConfiguration("Debug", buildSettings: [
49674967
"PRODUCT_NAME": "$(TARGET_NAME)",
49684968
"CODE_SIGN_IDENTITY": "-",
4969-
"ARCH": "x86_64",
4969+
"ARCHS": "arm64",
49704970
"LIBTOOL": libtoolPath.str,
49714971
]),
49724972
],
@@ -5049,8 +5049,8 @@ fileprivate struct TaskConstructionTests: CoreBasedTests {
50495049
task.checkNoInputs(contain: [.pathPattern(.suffix("libAnotherStatic.a"))])
50505050
// Check that the task does *not* declare libStaticLib2.a as an input, since it is located via search paths. Some projects may have a file reference whose path does not refer to a file, but which relies on finding the library via search paths anyway.
50515051
task.checkNoInputs(contain: [.pathPattern(.suffix("libStaticLib2.a"))])
5052-
// Check that the task contains a command line option to link Object.o, and declares it as an input.
5053-
task.checkCommandLineContains(["\(SRCROOT)/Object.o"])
5052+
// Check that the task does *not* contain a command line option to link Object.o (it will be in the LinkFileList instead, checked below), but that it *does* declare it as an input.
5053+
task.checkCommandLineDoesNotContain("\(SRCROOT)/Object.o")
50545054
task.checkInputs(contain: [.path("\(SRCROOT)/Object.o")])
50555055

50565056
// Check that the task does *not* have a command line option to find libDynamicLib1.dylib, nor does it declare it as an input, because static libraries can't link against dynamic libraries. We presently don't emit a diagnostic for this - see LibtoolLinkerSpec.constructLinkerTasks() and <rdar://problem/34314195> for more.
@@ -5059,6 +5059,16 @@ fileprivate struct TaskConstructionTests: CoreBasedTests {
50595059

50605060
task.checkOutputs(contain: [.path("\(SRCROOT)/build/Debug/libStaticLib1.a")])
50615061
}
5062+
5063+
// Check the contents of the LinkFileList.
5064+
results.checkWriteAuxiliaryFileTask(.matchTarget(target), .matchRuleType("WriteAuxiliaryFile"), .matchRuleItemPattern(.suffix("/StaticLib1.LinkFileList"))) { task, contents in
5065+
task.checkRuleInfo(["WriteAuxiliaryFile", "\(SRCROOT)/build/aProject.build/Debug/StaticLib1.build/Objects-normal/arm64/StaticLib1.LinkFileList"])
5066+
let contentsLines = contents.asString.dropLast().components(separatedBy: .newlines)
5067+
#expect(contentsLines == [
5068+
"\(SRCROOT)/build/aProject.build/Debug/StaticLib1.build/Objects-normal/arm64/File.o",
5069+
"\(SRCROOT)/Object.o",
5070+
])
5071+
}
50625072
}
50635073

50645074
results.checkTarget("StaticLib2") { target in

0 commit comments

Comments
 (0)