From 6c39491bf0b45b5c6b20967d60fe47a26a1b61dc Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 20 Jun 2023 10:21:38 +0100 Subject: [PATCH 1/3] Driver: allow static executables when using Musl --- Sources/SwiftDriver/Driver/Driver.swift | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index f1dab6183..548d5a608 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -660,7 +660,9 @@ public struct Driver { self.lto = Self.ltoKind(&parsedOptions, diagnosticsEngine: diagnosticsEngine) // Figure out the primary outputs from the driver. - (self.compilerOutputType, self.linkerOutputType) = Self.determinePrimaryOutputs(&parsedOptions, driverKind: driverKind, diagnosticsEngine: diagnosticEngine) + (self.compilerOutputType, self.linkerOutputType) = + Self.determinePrimaryOutputs(&parsedOptions, targetTriple: self.frontendTargetInfo.target.triple, + driverKind: driverKind, diagnosticsEngine: diagnosticEngine) // Multithreading. self.numThreads = Self.determineNumThreads(&parsedOptions, compilerMode: compilerMode, diagnosticsEngine: diagnosticEngine) @@ -1994,6 +1996,7 @@ extension Driver { /// Determine the primary compiler and linker output kinds. private static func determinePrimaryOutputs( _ parsedOptions: inout ParsedOptions, + targetTriple: Triple, driverKind: DriverKind, diagnosticsEngine: DiagnosticsEngine ) -> (FileType?, LinkOutputType?) { @@ -2005,7 +2008,7 @@ extension Driver { if let outputOption = parsedOptions.getLast(in: .modes) { switch outputOption.option { case .emitExecutable: - if parsedOptions.contains(.static) { + if parsedOptions.contains(.static) && targetTriple.environment != .musl { diagnosticsEngine.emit(.error_static_emit_executable_disallowed) } linkerOutputType = .executable From 3d6503e53e269565463d236fe29c34dd7a77803f Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Wed, 21 Jun 2023 10:30:09 +0100 Subject: [PATCH 2/3] Address PR feedback --- Sources/SwiftDriver/Driver/Driver.swift | 2 +- Sources/SwiftDriver/Utilities/Triple.swift | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Sources/SwiftDriver/Driver/Driver.swift b/Sources/SwiftDriver/Driver/Driver.swift index 548d5a608..82c3ed922 100644 --- a/Sources/SwiftDriver/Driver/Driver.swift +++ b/Sources/SwiftDriver/Driver/Driver.swift @@ -2008,7 +2008,7 @@ extension Driver { if let outputOption = parsedOptions.getLast(in: .modes) { switch outputOption.option { case .emitExecutable: - if parsedOptions.contains(.static) && targetTriple.environment != .musl { + if parsedOptions.contains(.static) && !targetTriple.supportsStaticExecutables { diagnosticsEngine.emit(.error_static_emit_executable_disallowed) } linkerOutputType = .executable diff --git a/Sources/SwiftDriver/Utilities/Triple.swift b/Sources/SwiftDriver/Utilities/Triple.swift index 430685cde..805984f16 100644 --- a/Sources/SwiftDriver/Utilities/Triple.swift +++ b/Sources/SwiftDriver/Utilities/Triple.swift @@ -1705,3 +1705,14 @@ fileprivate extension Array { } } } + +// MARK: - Linker support + +extension Triple { + /// Returns `true` if a given triple supports producing fully statically linked executables by providing `-static` + /// flag to the linker. This implies statically linking platform's libc, and of those that Swift supports currently + /// only Musl allows that reliably. + var supportsStaticExecutables: Bool { + self.environment == .musl + } +} From 56e72c736ab12b155e2a32361982c1539a91603b Mon Sep 17 00:00:00 2001 From: Max Desiatov Date: Tue, 4 Jul 2023 18:29:40 +0100 Subject: [PATCH 3/3] Add a test for static executable linking on Linux --- Tests/SwiftDriverTests/SwiftDriverTests.swift | 36 +++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/Tests/SwiftDriverTests/SwiftDriverTests.swift b/Tests/SwiftDriverTests/SwiftDriverTests.swift index 648088dba..148192d70 100644 --- a/Tests/SwiftDriverTests/SwiftDriverTests.swift +++ b/Tests/SwiftDriverTests/SwiftDriverTests.swift @@ -2100,10 +2100,42 @@ final class SwiftDriverTests: XCTestCase { XCTAssertFalse(cmd.contains(.flag("-dylib"))) XCTAssertFalse(cmd.contains(.flag("-shared"))) } + + do { + // executable linking linux static stdlib with musl + var driver = try Driver(args: commonArgs + [ + "-emit-executable", "-Osize", "-static-stdlib", "-static-executable", "-target", "x86_64-unknown-linux-musl" + ], env: env) + let plannedJobs = try driver.planBuild() + + XCTAssertEqual(plannedJobs.count, 4) + + let autolinkExtractJob = plannedJobs[2] + XCTAssertEqual(autolinkExtractJob.kind, .autolinkExtract) + + let autolinkCmd = autolinkExtractJob.commandLine + XCTAssertTrue(commandContainsTemporaryPath(autolinkCmd, "foo.o")) + XCTAssertTrue(commandContainsTemporaryPath(autolinkCmd, "bar.o")) + XCTAssertTrue(commandContainsTemporaryPath(autolinkCmd, "Test.autolink")) + + let linkJob = plannedJobs[3] + let cmd = linkJob.commandLine + XCTAssertTrue(cmd.contains(.flag("-o"))) + XCTAssertTrue(commandContainsTemporaryPath(cmd, "foo.o")) + XCTAssertTrue(commandContainsTemporaryPath(cmd, "bar.o")) + XCTAssertTrue(cmd.contains(.flag("--start-group"))) + XCTAssertTrue(cmd.contains(.flag("--end-group"))) + XCTAssertTrue(cmd.contains(.flag("-Os"))) + XCTAssertTrue(cmd.contains(.flag("-static"))) + XCTAssertEqual(linkJob.outputs[0].file, try VirtualPath(path: "Test")) + + XCTAssertFalse(cmd.contains(.flag("-dylib"))) + XCTAssertFalse(cmd.contains(.flag("-shared"))) + } #endif do { - // static WASM linking + // static Wasm linking var driver = try Driver(args: commonArgs + ["-emit-library", "-static", "-target", "wasm32-unknown-wasi"], env: env) let plannedJobs = try driver.planBuild() @@ -2135,7 +2167,7 @@ final class SwiftDriverTests: XCTestCase { try withTemporaryDirectory { path in try localFileSystem.writeFileContents( path.appending(components: "wasi", "static-executable-args.lnk")) { $0 <<< "garbage" } - // WASM executable linking + // Wasm executable linking var driver = try Driver(args: commonArgs + ["-emit-executable", "-Ounchecked", "-target", "wasm32-unknown-wasi", "-resource-dir", path.pathString,