diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 19082c99d4e38..6de7a1eb6c376 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -133,6 +133,10 @@ def j : JoinedOrSeparate<["-"], "j">, Flags<[DoesNotAffectIncrementalBuild]>, def sdk : Separate<["-"], "sdk">, Flags<[FrontendOption]>, HelpText<"Compile against ">, MetaVarName<"">; +def tools_directory : Separate<["-"], "tools-directory">, + Flags<[FrontendOption, NoInteractiveOption, DoesNotAffectIncrementalBuild]>, + HelpText<"Look for external executables (ld, clang, binutils) in ">, MetaVarName<"">; + def D : JoinedOrSeparate<["-"], "D">, Flags<[FrontendOption]>, HelpText<"Marks a conditional compilation flag as true">; diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 1539a7819d743..2f76de1ab1660 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -951,7 +951,19 @@ toolchains::Darwin::constructInvocation(const LinkJobAction &job, const Driver &D = getDriver(); const llvm::Triple &Triple = getTriple(); - InvocationInfo II{"ld"}; + // Configure the toolchain. + // By default, use the system `ld` to link. + const char *LD = "ld"; + if (const Arg *A = context.Args.getLastArg(options::OPT_tools_directory)) { + StringRef toolchainPath(A->getValue()); + + // If there is a 'ld' in the toolchain folder, use that instead. + if (auto toolchainLD = llvm::sys::findProgramByName("ld", {toolchainPath})) { + LD = context.Args.MakeArgString(toolchainLD.get()); + } + } + + InvocationInfo II = {LD}; ArgStringList &Arguments = II.Arguments; if (context.Args.hasArg(options::OPT_driver_use_filelists) || @@ -1269,14 +1281,14 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, case LinkKind::None: llvm_unreachable("invalid link kind"); case LinkKind::Executable: - // Default case, nothing extra needed + // Default case, nothing extra needed. break; case LinkKind::DynamicLibrary: Arguments.push_back("-shared"); break; } - // Select the linker to use + // Select the linker to use. std::string Linker; if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) { Linker = A->getValue(); @@ -1287,6 +1299,22 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker)); } + // Configure the toolchain. + // By default, use the system clang++ to link. + const char * Clang = "clang++"; + if (const Arg *A = context.Args.getLastArg(options::OPT_tools_directory)) { + StringRef toolchainPath(A->getValue()); + + // If there is a clang in the toolchain folder, use that instead. + if (auto toolchainClang = llvm::sys::findProgramByName("clang++", {toolchainPath})) { + Clang = context.Args.MakeArgString(toolchainClang.get()); + } + + // Look for binutils in the toolchain folder. + Arguments.push_back("-B"); + Arguments.push_back(context.Args.MakeArgString(A->getValue())); + } + std::string Target = getTargetForLinker(); if (!Target.empty()) { Arguments.push_back("-target"); @@ -1393,7 +1421,7 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, Arguments.push_back("-o"); Arguments.push_back(context.Output.getPrimaryOutputFilename().c_str()); - return {"clang++", Arguments}; + return {Clang, Arguments}; } std::string diff --git a/test/Driver/Inputs/fake-toolchain/clang++ b/test/Driver/Inputs/fake-toolchain/clang++ new file mode 100755 index 0000000000000..4eb768a1745b8 --- /dev/null +++ b/test/Driver/Inputs/fake-toolchain/clang++ @@ -0,0 +1,16 @@ +#!/usr/bin/env python +# clang++ - Fake Clang to test finding clang++ in the toolchain path +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +from __future__ import print_function + +print("Sorry, I'm lazy-clang") diff --git a/test/Driver/Inputs/fake-toolchain/ld b/test/Driver/Inputs/fake-toolchain/ld new file mode 100755 index 0000000000000..09c937f59d2af --- /dev/null +++ b/test/Driver/Inputs/fake-toolchain/ld @@ -0,0 +1,16 @@ +#!/usr/bin/env python +# ld - Fake ld to test finding the Darwin linker in the toolchain path +# +# This source file is part of the Swift.org open source project +# +# Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors +# Licensed under Apache License v2.0 with Runtime Library Exception +# +# See http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +# +# ---------------------------------------------------------------------------- + +from __future__ import print_function + +print("Sorry, wrong number!") diff --git a/test/Driver/tools_directory.swift b/test/Driver/tools_directory.swift new file mode 100644 index 0000000000000..61b3e81d7c840 --- /dev/null +++ b/test/Driver/tools_directory.swift @@ -0,0 +1,36 @@ +//================================================= +// ** GENERIC UNIX TARGETS - linking via clang++ ** +//================================================= + +// RUN: %swiftc_driver -### -target x86_64-linux-unknown -tools-directory %S/Inputs/fake-toolchain %s 2>&1 | %FileCheck -check-prefix CLANGSUB %s +// RUN: %swiftc_driver -### -target x86_64-linux-unknown -tools-directory /Something/obviously/fake %s 2>&1 | %FileCheck -check-prefix BINUTILS %s + +// CLANGSUB: swift +// CLANGSUB-SAME: -o [[OBJECTFILE:.*]] +// CLANGSUB: swift-autolink-extract [[OBJECTFILE]] +// CLANGSUB-SAME: -o [[AUTOLINKFILE:.*]] +// CLANGSUB: {{[^ ]+}}/Inputs/fake-toolchain/clang++ +// CLANGSUB-DAG: [[OBJECTFILE]] +// CLANGSUB-DAG: @[[AUTOLINKFILE]] +// CLANGSUB: -o tools_directory + +// BINUTILS: swift +// BINUTILS-SAME: -o [[OBJECTFILE:.*]] +// BINUTILS: swift-autolink-extract [[OBJECTFILE]] +// BINUTILS-SAME: -o [[AUTOLINKFILE:.*]] +// BINUTILS: clang++ +// BINUTILS-DAG: [[OBJECTFILE]] +// BINUTILS-DAG: @[[AUTOLINKFILE]] +// BINUTILS-DAG: -B /Something/obviously/fake +// BINUTILS: -o tools_directory + +//====================================== +// ** DARWIN TARGETS - linking via ld ** +//====================================== + +// RUN: %swiftc_driver -### -target x86_64-apple-macosx10.9 -tools-directory %S/Inputs/fake-toolchain %s 2>&1 | %FileCheck -check-prefix LDSUB %s + +// LDSUB: swift +// LDSUB-SAME: -o [[OBJECTFILE:.*]] +// LDSUB: {{[^ ]+}}/Inputs/fake-toolchain/ld [[OBJECTFILE]] +// LDSUB: -o tools_directory