From 4918cd643a0449c39d8f58a2e8c93965ae7759dc Mon Sep 17 00:00:00 2001 From: Evan Wilde Date: Sat, 13 Apr 2024 21:53:25 -0700 Subject: [PATCH] Remove swiftmodule from linker filelist input The swiftmodule isn't something the linker can operate on. It should be passed to the clang linker, but not to the underlying linker through the use of the linker input filelist. This exposes itself as a linker error when trying to link with a filelist and debug info. With debug info, the driver schedules an `emit-module` job and an object compile job, which are both fed into the link job. > swiftc hello.swift -g -emit-executable -driver-filelist-threshold=0 0: input, "hello.swift", swift 1: emit-module, {0}, swiftmodule 2: compile, {0}, object 3: link, {1, 2}, image 4: generate-dSYM, {3}, dSYM Without generating debug info, the driver does not schedule an emit-module job, so the swiftmodule is never generated in the first place and not included in the filelist where it can cause trouble. > swiftc hello.swift -emit-executable -driver-filelist-threshold=0 0: input, "hello.swift", swift 1: compile, {0}, object 2: link, {1}, image I've removed the module from the linker filelist, but kept it in the module input list. This lines up more cleanly with the non-filelist path, which passes the swiftmodule to the clang-linker via a direct `-Wl,-add_ast_path`. Fixes: rdar://125936639 --- .../Jobs/DarwinToolchain+LinkerSupport.swift | 1 - Tests/SwiftDriverTests/SwiftDriverTests.swift | 29 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Sources/SwiftDriver/Jobs/DarwinToolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/DarwinToolchain+LinkerSupport.swift index cdc79e1f8..fd831b0ce 100644 --- a/Sources/SwiftDriver/Jobs/DarwinToolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/DarwinToolchain+LinkerSupport.swift @@ -119,7 +119,6 @@ extension DarwinToolchain { var inputModules = [VirtualPath]() for input in inputs { if input.type == .swiftModule && linkerOutputType != .staticLibrary { - inputPaths.append(input.file) inputModules.append(input.file) } else if input.type == .object { inputPaths.append(input.file) diff --git a/Tests/SwiftDriverTests/SwiftDriverTests.swift b/Tests/SwiftDriverTests/SwiftDriverTests.swift index 46ac1d115..388f26bc1 100644 --- a/Tests/SwiftDriverTests/SwiftDriverTests.swift +++ b/Tests/SwiftDriverTests/SwiftDriverTests.swift @@ -3097,6 +3097,35 @@ final class SwiftDriverTests: XCTestCase { XCTAssertTrue(firstKeyOutputs.keys.contains(where: { $0 == .swiftModule })) } + func testLinkFilelistWithDebugInfo() throws { + func getFileListElements(for filelistOpt: String, job: Job) -> [VirtualPath] { + guard let optIdx = job.commandLine.firstIndex(of: .flag(filelistOpt)) else { + XCTFail("Argument '\(filelistOpt)' not in job command line") + return [] + } + let value = job.commandLine[job.commandLine.index(after: optIdx)] + guard case let .path(.fileList(_, valueFileList)) = value else { + XCTFail("Argument wasn't a filelist") + return [] + } + guard case let .list(inputs) = valueFileList else { + XCTFail("FileList wasn't a List") + return [] + } + return inputs + } + + var driver = try Driver(args: [ + "swiftc", "-g", "/tmp/hello.swift", "-module-name", "Hello", + "-emit-library", "-driver-filelist-threshold=0" + ]) + + var jobs = try driver.planBuild() + XCTAssertEqual(jobs.count, 4) + XCTAssertEqual(getFileListElements(for: "-filelist", job: jobs[2]), + [.temporary(try .init(validating: "hello-1.o"))]) + } + func testDashDashPassingDownInput() throws { do { var driver = try Driver(args: ["swiftc", "-module-name=ThisModule", "-wmo", "-num-threads", "4", "-emit-module", "-o", "test.swiftmodule", "--", "main.swift", "multi-threaded.swift"])