diff --git a/Sources/SwiftDriver/Jobs/GenericUnixToolchain+LinkerSupport.swift b/Sources/SwiftDriver/Jobs/GenericUnixToolchain+LinkerSupport.swift index e17d8a88a..617021560 100644 --- a/Sources/SwiftDriver/Jobs/GenericUnixToolchain+LinkerSupport.swift +++ b/Sources/SwiftDriver/Jobs/GenericUnixToolchain+LinkerSupport.swift @@ -147,14 +147,24 @@ extension GenericUnixToolchain { } } + if targetInfo.sdkPath != nil { + for libpath in targetInfo.runtimeLibraryImportPaths { + commandLine.appendFlag(.L) + commandLine.appendPath(VirtualPath.lookup(libpath.path)) + } + } + if !isEmbeddedEnabled && !parsedOptions.hasArgument(.nostartfiles) { - let swiftrtPath = VirtualPath.lookup(targetInfo.runtimeResourcePath.path) - .appending( - components: targetTriple.platformName() ?? "", - String(majorArchitectureName(for: targetTriple)), - "swiftrt.o" - ) - commandLine.appendPath(swiftrtPath) + let rsrc: VirtualPath + // Prefer the swiftrt.o runtime file from the SDK if it's specified. + if let sdk = targetInfo.sdkPath { + rsrc = VirtualPath.lookup(sdk.path).appending(components: "usr", "lib", "swift") + } else { + rsrc = VirtualPath.lookup(targetInfo.runtimeResourcePath.path) + } + let platform: String = targetTriple.platformName() ?? "" + let architecture: String = majorArchitectureName(for: targetTriple) + commandLine.appendPath(rsrc.appending(components: platform, architecture, "swiftrt.o")) } // If we are linking statically, we need to add all @@ -194,7 +204,12 @@ extension GenericUnixToolchain { commandLine.appendPath(try VirtualPath(path: opt.argument.asSingle)) } - if let path = targetInfo.sdkPath?.path { + if targetTriple.environment == .android { + if let sysroot = try getAndroidNDKSysrootPath() { + commandLine.appendFlag("--sysroot") + commandLine.appendPath(sysroot) + } + } else if let path = targetInfo.sdkPath?.path { commandLine.appendFlag("--sysroot") commandLine.appendPath(VirtualPath.lookup(path)) } diff --git a/Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift b/Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift index 7abe9d771..1b2d96808 100644 --- a/Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift +++ b/Sources/SwiftDriver/Toolchains/GenericUnixToolchain.swift @@ -117,4 +117,50 @@ public final class GenericUnixToolchain: Toolchain { let environment = (targetTriple.environment == .android) ? "-android" : "" return "libclang_rt.\(sanitizer.libraryName)-\(targetTriple.archName)\(environment).a" } + + private func getAndroidNDKHostOSSuffix() -> String? { +#if os(Windows) + "windows" +#elseif os(Linux) + "linux" +#elseif os(macOS) + "darwin" +#else + // The NDK is only available on macOS, linux and windows hosts. + nil +#endif + } + + func getAndroidNDKSysrootPath() throws -> AbsolutePath? { +#if arch(x86_64) + // The NDK's sysroot should be specified in the environment. + guard let ndk = env["ANDROID_NDK_ROOT"], + let osSuffix = getAndroidNDKHostOSSuffix() else { + return nil + } + var sysroot: AbsolutePath = + try AbsolutePath(validating: ndk) + .appending(components: "toolchains", "llvm", "prebuilt") + .appending(component: "\(osSuffix)-x86_64") + .appending(component: "sysroot") + return sysroot +#else + // The NDK is only available on an x86_64 host. + return nil +#endif + } + + public func addPlatformSpecificCommonFrontendOptions( + commandLine: inout [Job.ArgTemplate], + inputs: inout [TypedVirtualPath], + frontendTargetInfo: FrontendTargetInfo, + driver: inout Driver + ) throws { + if driver.targetTriple.environment == .android { + if let sysroot = try getAndroidNDKSysrootPath() { + commandLine.appendFlag("-sysroot") + commandLine.appendFlag(sysroot.pathString) + } + } + } } diff --git a/Tests/SwiftDriverTests/SwiftDriverTests.swift b/Tests/SwiftDriverTests/SwiftDriverTests.swift index 3da3655f7..5fff40c36 100644 --- a/Tests/SwiftDriverTests/SwiftDriverTests.swift +++ b/Tests/SwiftDriverTests/SwiftDriverTests.swift @@ -7151,10 +7151,14 @@ final class SwiftDriverTests: XCTestCase { func testRelativeResourceDir() throws { do { + // Reset the environment to avoid 'SDKROOT' influencing the + // linux driver paths and taking the priority over the resource directory. + var env = ProcessEnv.vars + env["SDKROOT"] = nil var driver = try Driver(args: ["swiftc", "-target", "x86_64-unknown-linux", "-lto=llvm-thin", "foo.swift", - "-resource-dir", "resource/dir"]) + "-resource-dir", "resource/dir"], env: env) let plannedJobs = try driver.planBuild().removingAutolinkExtractJobs() let compileJob = plannedJobs[0] XCTAssertEqual(compileJob.kind, .compile) @@ -7170,6 +7174,24 @@ final class SwiftDriverTests: XCTestCase { } } + func testSDKDirLinuxPrioritizedOverRelativeResourceDirForLinkingSwiftRT() throws { + do { + let sdkRoot = try testInputsPath.appending(component: "mock-sdk.sdk") + var env = ProcessEnv.vars + env["SDKROOT"] = sdkRoot.pathString + var driver = try Driver(args: ["swiftc", + "-target", "x86_64-unknown-linux", "-lto=llvm-thin", + "foo.swift", + "-resource-dir", "resource/dir"], env: env) + let plannedJobs = try driver.planBuild().removingAutolinkExtractJobs() + let compileJob = plannedJobs[0] + XCTAssertEqual(compileJob.kind, .compile) + let linkJob = plannedJobs[1] + XCTAssertEqual(linkJob.kind, .link) + XCTAssertTrue(linkJob.commandLine.contains(try toPathOption(sdkRoot.pathString + "/usr/lib/swift/linux/x86_64/swiftrt.o"))) + } + } + func testSanitizerArgsForTargets() throws { let targets = ["x86_64-unknown-freebsd", "x86_64-unknown-linux", "x86_64-apple-macosx10.9"] try targets.forEach {