Skip to content

Commit c4bf245

Browse files
author
Harlan Haskins
committed
Add autolink-extract for Linux
1 parent 23742cc commit c4bf245

File tree

8 files changed

+107
-20
lines changed

8 files changed

+107
-20
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import TSCBasic
2+
import TSCUtility
3+
4+
extension Driver {
5+
mutating func autolinkExtractJob(inputs: [TypedVirtualPath]) throws -> Job? {
6+
// On ELF platforms there's no built in autolinking mechanism, so we
7+
// pull the info we need from the .o files directly and pass them as an
8+
// argument input file to the linker.
9+
// FIXME: Also handle Cygwin and MinGW
10+
guard inputs.count > 0 && targetTriple.objectFormat == .elf else {
11+
return nil
12+
}
13+
14+
var commandLine = [Job.ArgTemplate]()
15+
let output = VirtualPath.temporary("\(moduleName).autolink")
16+
17+
commandLine.append(contentsOf: inputs.map { .path($0.file) })
18+
commandLine.appendFlag(.o)
19+
commandLine.appendPath(output)
20+
21+
return Job(
22+
kind: .autolinkExtract,
23+
tool: .absolute(try toolchain.getToolPath(.swiftAutolinkExtract)),
24+
commandLine: commandLine,
25+
inputs: inputs,
26+
outputs: [.init(file: output, type: .autolink)]
27+
)
28+
}
29+
}

Sources/SwiftDriver/Jobs/GenericUnixToolchain+LinkerSupport.swift

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,14 @@ extension GenericUnixToolchain {
145145
)
146146
commandLine.appendPath(swiftrtPath)
147147

148-
commandLine.append(contentsOf: inputs.map { .path($0.file) })
148+
let inputFiles: [Job.ArgTemplate] = inputs.map { input in
149+
// Autolink inputs are handled specially
150+
if input.type == .autolink {
151+
return .flag("@\(input.file.name)")
152+
}
153+
return .path(input.file)
154+
}
155+
commandLine.append(contentsOf: inputFiles)
149156

150157
let fSystemArgs = parsedOptions.filter {
151158
$0.option == .F || $0.option == .Fsystem
@@ -164,14 +171,6 @@ extension GenericUnixToolchain {
164171
commandLine.appendFlag(path)
165172
}
166173

167-
// FIXME: Add any autolinking scripts to the arguments
168-
// for (const Job *Cmd : context.Inputs) {
169-
// auto &OutputInfo = Cmd->getOutput()
170-
// if (OutputInfo.getPrimaryOutputType() == file_types::TY_AutolinkFile)
171-
// Arguments.push_back(context.Args.MakeArgString(
172-
// Twine("@") + OutputInfo.getPrimaryOutputFilename()))
173-
// }
174-
175174
// Add the runtime library link paths.
176175
for path in runtimePaths {
177176
commandLine.appendFlag(.L)

Sources/SwiftDriver/Jobs/Job.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public struct Job: Codable, Equatable {
77
case mergeModule = "merge-module"
88
case link
99
case generateDSYM = "generate-dsym"
10+
case autolinkExtract = "autolink-extract"
1011
}
1112

1213
public enum ArgTemplate: Equatable {

Sources/SwiftDriver/Jobs/Planning.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,19 @@ extension Driver {
6262
jobs.append(try mergeModuleJob(inputs: moduleInputs))
6363
}
6464

65+
// If we need to autolink-extract, do so.
66+
let autolinkInputs = linkerInputs.filter { $0.type == .object }
67+
if let autolinkExtractJob = try autolinkExtractJob(inputs: autolinkInputs) {
68+
linkerInputs.append(contentsOf: autolinkExtractJob.outputs)
69+
jobs.append(autolinkExtractJob)
70+
}
6571

6672
// If we should link, do so.
6773
if linkerOutputType != nil && !linkerInputs.isEmpty {
6874
jobs.append(try linkJob(inputs: linkerInputs))
6975
}
7076

77+
7178
// FIXME: Lots of follow-up actions for merging modules, etc.
7279

7380
return jobs

Sources/SwiftDriver/Toolchains/DarwinToolchain.swift

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
import TSCBasic
22

3+
/// Utility function to lookup an executable using xcrun.
4+
func xcrunFind(exec: String) throws -> AbsolutePath {
5+
let path = try Process.checkNonZeroExit(
6+
arguments: ["xcrun", "-sdk", "macosx", "--find", exec]).spm_chomp()
7+
return AbsolutePath(path)
8+
}
9+
310
/// Toolchain for Darwin-based platforms, such as macOS and iOS.
411
///
512
/// FIXME: This class is not thread-safe.
@@ -21,6 +28,8 @@ public final class DarwinToolchain: Toolchain {
2128
arguments: ["xcrun", "-toolchain", "default", "-f", "clang"]
2229
).spm_chomp()
2330
return AbsolutePath(result)
31+
case .swiftAutolinkExtract:
32+
return try xcrunFind(exec: "swift-autolink-extract")
2433
}
2534
}
2635

@@ -57,13 +66,6 @@ public final class DarwinToolchain: Toolchain {
5766
}
5867
}
5968

60-
/// Utility function to lookup an executable using xcrun.
61-
private func xcrunFind(exec: String) throws -> AbsolutePath {
62-
let path = try Process.checkNonZeroExit(
63-
arguments: ["xcrun", "-sdk", "macosx", "--find", exec]).spm_chomp()
64-
return AbsolutePath(path)
65-
}
66-
6769
public var compatibility50: Result<AbsolutePath, Error> {
6870
resourcesDirectory.map{ $0.appending(component: "libswiftCompatibility50.a") }
6971
}

Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,14 @@ public final class GenericUnixToolchain: Toolchain {
1717
return path
1818
}
1919

20+
// If we happen to be on a macOS host, some tools might not be in our
21+
// PATH, so we'll just use xcrun to find them too.
22+
#if os(macOS)
23+
return try xcrunFind(exec: exec)
24+
#else
2025
throw Error.unableToFind(tool: exec)
26+
#endif
27+
2128
}
2229

2330
public func makeLinkerOutputFilename(moduleName: String, type: LinkOutputType) -> String {
@@ -39,6 +46,8 @@ public final class GenericUnixToolchain: Toolchain {
3946
return try lookup(exec: "clang")
4047
case .clang:
4148
return try lookup(exec: "clang")
49+
case .swiftAutolinkExtract:
50+
return try lookup(exec: "swift-autolink-extract")
4251
}
4352
}
4453

Sources/SwiftDriver/Toolchains/Toolchain.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ public enum Tool {
55
case staticLinker
66
case dynamicLinker
77
case clang
8+
case swiftAutolinkExtract
89
}
910

1011
/// Describes a toolchain, which includes information about compilers, linkers

Tests/SwiftDriverTests/SwiftDriverTests.swift

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,11 @@ final class SwiftDriverTests: XCTestCase {
238238
let plannedJobs = try driver.planBuild()
239239

240240
XCTAssertEqual(3, plannedJobs.count)
241+
XCTAssertFalse(plannedJobs.contains { $0.kind == .autolinkExtract })
242+
241243
let linkJob = plannedJobs[2]
244+
XCTAssertEqual(linkJob.kind, .link)
245+
242246
let cmd = linkJob.commandLine
243247
XCTAssertTrue(cmd.contains(.flag("-dylib")))
244248
XCTAssertTrue(cmd.contains(.flag("-arch")))
@@ -257,7 +261,11 @@ final class SwiftDriverTests: XCTestCase {
257261
let plannedJobs = try driver.planBuild()
258262

259263
XCTAssertEqual(3, plannedJobs.count)
264+
XCTAssertFalse(plannedJobs.contains { $0.kind == .autolinkExtract })
265+
260266
let linkJob = plannedJobs[2]
267+
XCTAssertEqual(linkJob.kind, .link)
268+
261269
let cmd = linkJob.commandLine
262270
XCTAssertTrue(cmd.contains(.flag("-dylib")))
263271
XCTAssertTrue(cmd.contains(.flag("-arch")))
@@ -276,7 +284,11 @@ final class SwiftDriverTests: XCTestCase {
276284
let plannedJobs = try driver.planBuild()
277285

278286
XCTAssertEqual(3, plannedJobs.count)
287+
XCTAssertFalse(plannedJobs.contains { $0.kind == .autolinkExtract })
288+
279289
let linkJob = plannedJobs[2]
290+
XCTAssertEqual(linkJob.kind, .link)
291+
280292
let cmd = linkJob.commandLine
281293
XCTAssertTrue(cmd.contains(.flag("-dylib")))
282294
XCTAssertTrue(cmd.contains(.flag("-w")))
@@ -294,7 +306,11 @@ final class SwiftDriverTests: XCTestCase {
294306
let plannedJobs = try driver.planBuild()
295307

296308
XCTAssertEqual(plannedJobs.count, 3)
309+
XCTAssertFalse(plannedJobs.contains { $0.kind == .autolinkExtract })
310+
297311
let linkJob = plannedJobs[2]
312+
XCTAssertEqual(linkJob.kind, .link)
313+
298314
let cmd = linkJob.commandLine
299315
XCTAssertTrue(cmd.contains(.flag("-static")))
300316
XCTAssertTrue(cmd.contains(.flag("-o")))
@@ -317,7 +333,11 @@ final class SwiftDriverTests: XCTestCase {
317333
var driver = try Driver(args: commonArgs + ["-emit-executable"])
318334
let plannedJobs = try driver.planBuild()
319335
XCTAssertEqual(3, plannedJobs.count)
336+
XCTAssertFalse(plannedJobs.contains { $0.kind == .autolinkExtract })
337+
320338
let linkJob = plannedJobs[2]
339+
XCTAssertEqual(linkJob.kind, .link)
340+
321341
let cmd = linkJob.commandLine
322342
XCTAssertTrue(cmd.contains(.flag("-o")))
323343
XCTAssertTrue(cmd.contains(.path(.temporary("foo.o"))))
@@ -334,8 +354,18 @@ final class SwiftDriverTests: XCTestCase {
334354
var driver = try Driver(args: commonArgs + ["-emit-library", "-target", "x86_64-unknown-linux"])
335355
let plannedJobs = try driver.planBuild()
336356

337-
XCTAssertEqual(plannedJobs.count, 3)
338-
let linkJob = plannedJobs[2]
357+
XCTAssertEqual(plannedJobs.count, 4)
358+
359+
let autolinkExtractJob = plannedJobs[2]
360+
XCTAssertEqual(autolinkExtractJob.kind, .autolinkExtract)
361+
362+
let autolinkCmd = autolinkExtractJob.commandLine
363+
XCTAssertTrue(autolinkCmd.contains(.path(.temporary("foo.o"))))
364+
XCTAssertTrue(autolinkCmd.contains(.path(.temporary("bar.o"))))
365+
XCTAssertTrue(autolinkCmd.contains(.path(.temporary("Test.autolink"))))
366+
367+
let linkJob = plannedJobs[3]
368+
XCTAssertEqual(linkJob.kind, .link)
339369
let cmd = linkJob.commandLine
340370
XCTAssertTrue(cmd.contains(.flag("-o")))
341371
XCTAssertTrue(cmd.contains(.flag("-shared")))
@@ -352,8 +382,17 @@ final class SwiftDriverTests: XCTestCase {
352382
var driver = try Driver(args: commonArgs + ["-emit-library", "-static", "-target", "x86_64-unknown-linux"])
353383
let plannedJobs = try driver.planBuild()
354384

355-
XCTAssertEqual(plannedJobs.count, 3)
356-
let linkJob = plannedJobs[2]
385+
XCTAssertEqual(plannedJobs.count, 4)
386+
387+
let autolinkExtractJob = plannedJobs[2]
388+
XCTAssertEqual(autolinkExtractJob.kind, .autolinkExtract)
389+
390+
let autolinkCmd = autolinkExtractJob.commandLine
391+
XCTAssertTrue(autolinkCmd.contains(.path(.temporary("foo.o"))))
392+
XCTAssertTrue(autolinkCmd.contains(.path(.temporary("bar.o"))))
393+
XCTAssertTrue(autolinkCmd.contains(.path(.temporary("Test.autolink"))))
394+
395+
let linkJob = plannedJobs[3]
357396
let cmd = linkJob.commandLine
358397
// we'd expect "ar crs libTest.a foo.o bar.o"
359398
XCTAssertTrue(cmd.contains(.flag("crs")))

0 commit comments

Comments
 (0)