From 82e7f68e5d8998fc9398dab7dfe93c7543316c5e Mon Sep 17 00:00:00 2001 From: Thomas Roughton Date: Wed, 2 May 2018 09:51:26 +1200 Subject: [PATCH] Refactor ToolChains into separate files. Format the code and factor together some common functionality at the same time. --- include/swift/Basic/TaskQueue.h | 2 +- include/swift/Driver/ToolChain.h | 129 ++-- lib/Driver/CMakeLists.txt | 3 + lib/Driver/DarwinToolChains.cpp | 452 +++++++++++++ lib/Driver/ToolChain.cpp | 97 ++- lib/Driver/ToolChains.cpp | 1061 ++---------------------------- lib/Driver/ToolChains.h | 29 +- lib/Driver/UnixToolChains.cpp | 348 ++++++++++ lib/Driver/WindowsToolChains.cpp | 172 +++++ 9 files changed, 1180 insertions(+), 1113 deletions(-) create mode 100644 lib/Driver/DarwinToolChains.cpp create mode 100644 lib/Driver/UnixToolChains.cpp create mode 100644 lib/Driver/WindowsToolChains.cpp diff --git a/include/swift/Basic/TaskQueue.h b/include/swift/Basic/TaskQueue.h index 000a59e259d7d..4f6ef8ab68d89 100644 --- a/include/swift/Basic/TaskQueue.h +++ b/include/swift/Basic/TaskQueue.h @@ -56,7 +56,7 @@ class TaskQueue { /// \param NumberOfParallelTasks indicates the number of tasks which should /// be run in parallel. If 0, the TaskQueue will choose the most appropriate /// number of parallel tasks for the current system. - /// \param Optional stats reporter to count I/O and subprocess events. + /// \param USR Optional stats reporter to count I/O and subprocess events. TaskQueue(unsigned NumberOfParallelTasks = 0, UnifiedStatsReporter *USR = nullptr); virtual ~TaskQueue(); diff --git a/include/swift/Driver/ToolChain.h b/include/swift/Driver/ToolChain.h index f042e5f09ee8c..ff1b009533d4c 100644 --- a/include/swift/Driver/ToolChain.h +++ b/include/swift/Driver/ToolChain.h @@ -15,7 +15,9 @@ #include "swift/Basic/LLVM.h" #include "swift/Driver/Action.h" +#include "swift/Driver/Job.h" #include "swift/Frontend/FileTypes.h" +#include "swift/Option/Options.h" #include "llvm/ADT/Triple.h" #include "llvm/Option/Option.h" @@ -23,11 +25,11 @@ namespace swift { namespace driver { - class CommandOutput; - class Compilation; - class Driver; - class Job; - class OutputInfo; +class CommandOutput; +class Compilation; +class Driver; +class Job; +class OutputInfo; /// A ToolChain is responsible for turning abstract Actions into concrete, /// runnable Jobs. @@ -47,7 +49,7 @@ class ToolChain { ToolChain(const Driver &D, const llvm::Triple &T) : D(D), Triple(T) {} /// A special name used to identify the Swift executable itself. - constexpr static const char * const SWIFT_EXECUTABLE_NAME = "swift"; + constexpr static const char *const SWIFT_EXECUTABLE_NAME = "swift"; /// Packs together the supplementary information about the job being created. class JobContext { @@ -122,45 +124,36 @@ class ToolChain { InvocationInfo(const char *name, llvm::opt::ArgStringList args = {}, decltype(ExtraEnvironment) extraEnv = {}) - : ExecutableName(name), Arguments(std::move(args)), - ExtraEnvironment(std::move(extraEnv)) {} + : ExecutableName(name), Arguments(std::move(args)), + ExtraEnvironment(std::move(extraEnv)) {} }; - virtual InvocationInfo - constructInvocation(const CompileJobAction &job, - const JobContext &context) const; - virtual InvocationInfo - constructInvocation(const InterpretJobAction &job, - const JobContext &context) const; - virtual InvocationInfo - constructInvocation(const BackendJobAction &job, - const JobContext &context) const; - virtual InvocationInfo - constructInvocation(const MergeModuleJobAction &job, - const JobContext &context) const; - virtual InvocationInfo - constructInvocation(const ModuleWrapJobAction &job, - const JobContext &context) const; - - virtual InvocationInfo - constructInvocation(const REPLJobAction &job, - const JobContext &context) const; - - virtual InvocationInfo - constructInvocation(const GenerateDSYMJobAction &job, - const JobContext &context) const; + virtual InvocationInfo constructInvocation(const CompileJobAction &job, + const JobContext &context) const; + virtual InvocationInfo constructInvocation(const InterpretJobAction &job, + const JobContext &context) const; + virtual InvocationInfo constructInvocation(const BackendJobAction &job, + const JobContext &context) const; + virtual InvocationInfo constructInvocation(const MergeModuleJobAction &job, + const JobContext &context) const; + virtual InvocationInfo constructInvocation(const ModuleWrapJobAction &job, + const JobContext &context) const; + + virtual InvocationInfo constructInvocation(const REPLJobAction &job, + const JobContext &context) const; + + virtual InvocationInfo constructInvocation(const GenerateDSYMJobAction &job, + const JobContext &context) const; virtual InvocationInfo constructInvocation(const VerifyDebugInfoJobAction &job, const JobContext &context) const; - virtual InvocationInfo - constructInvocation(const GeneratePCHJobAction &job, - const JobContext &context) const; + virtual InvocationInfo constructInvocation(const GeneratePCHJobAction &job, + const JobContext &context) const; virtual InvocationInfo constructInvocation(const AutolinkExtractJobAction &job, const JobContext &context) const; - virtual InvocationInfo - constructInvocation(const LinkJobAction &job, - const JobContext &context) const; + virtual InvocationInfo constructInvocation(const LinkJobAction &job, + const JobContext &context) const; /// Searches for the given executable in appropriate paths relative to the /// Swift binary. @@ -176,6 +169,34 @@ class ToolChain { /// This method is invoked by findProgramRelativeToSwift(). virtual std::string findProgramRelativeToSwiftImpl(StringRef name) const; + void addInputsOfType(llvm::opt::ArgStringList &Arguments, + ArrayRef Inputs, + file_types::ID InputType, + const char *PrefixArgument = nullptr) const; + + void addInputsOfType(llvm::opt::ArgStringList &Arguments, + ArrayRef Jobs, + const llvm::opt::ArgList &Args, file_types::ID InputType, + const char *PrefixArgument = nullptr) const; + + void addPrimaryInputsOfType(llvm::opt::ArgStringList &Arguments, + ArrayRef Jobs, + const llvm::opt::ArgList &Args, + file_types::ID InputType, + const char *PrefixArgument = nullptr) const; + + /// Get the runtime library link path, which is platform-specific and found + /// relative to the compiler. + void getRuntimeLibraryPath(SmallVectorImpl &runtimeLibPath, + const llvm::opt::ArgList &args, bool shared) const; + + void addPathEnvironmentVariableIfNeeded(Job::EnvironmentVector &env, + const char *name, + const char *separator, + options::ID optionID, + const llvm::opt::ArgList &args, + StringRef extraEntry = "") const; + public: virtual ~ToolChain() = default; @@ -187,8 +208,7 @@ class ToolChain { /// /// This method dispatches to the various \c constructInvocation methods, /// which may be overridden by platform-specific subclasses. - std::unique_ptr constructJob(const JobAction &JA, - Compilation &C, + std::unique_ptr constructJob(const JobAction &JA, Compilation &C, SmallVectorImpl &&inputs, ArrayRef inputActions, std::unique_ptr output, @@ -221,16 +241,35 @@ class ToolChain { /// Return the default language type to use for the given extension. /// If the extension is empty or is otherwise not recognized, return /// the invalid type \c TY_INVALID. - virtual file_types::ID lookupTypeForExtension(StringRef Ext) const; + file_types::ID lookupTypeForExtension(StringRef Ext) const; - /// Check whether a clang library with a given name exists. + /// Copies the path for the directory clang libraries would be stored in on + /// the current toolchain. + void getClangLibraryPath(const llvm::opt::ArgList &Args, + SmallString<128> &LibPath) const; + + /// Returns the name the clang library for a given sanitizer would have on + /// the current toolchain. + /// + /// \param Sanitizer Sanitizer name. + /// \param shared Whether the library is shared + virtual std::string sanitizerRuntimeLibName(StringRef Sanitizer, + bool shared = true) const = 0; + + /// Returns whether a given sanitizer exists for the current toolchain. /// - /// \param args Invocation arguments. /// \param sanitizer Sanitizer name. /// \param shared Whether the library is shared - virtual bool sanitizerRuntimeLibExists(const llvm::opt::ArgList &args, - StringRef sanitizer, - bool shared=true) const; + bool sanitizerRuntimeLibExists(const llvm::opt::ArgList &args, + StringRef sanitizer, bool shared = true) const; + + /// Adds a runtime library to the arguments list for linking. + /// + /// \param LibName The library name + /// \param Arguments The arguments list to append to + void addLinkRuntimeLib(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &Arguments, + StringRef LibName) const; }; } // end namespace driver } // end namespace swift diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index b0419e4bb369b..cf531112cc4b5 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -1,6 +1,7 @@ set(swiftDriver_sources Action.cpp Compilation.cpp + DarwinToolChains.cpp DependencyGraph.cpp Driver.cpp FrontendUtil.cpp @@ -9,6 +10,8 @@ set(swiftDriver_sources PrettyStackTrace.cpp ToolChain.cpp ToolChains.cpp + UnixToolChains.cpp + WindowsToolChains.cpp ) set(swiftDriver_targetDefines) diff --git a/lib/Driver/DarwinToolChains.cpp b/lib/Driver/DarwinToolChains.cpp new file mode 100644 index 0000000000000..5f156b025eaf3 --- /dev/null +++ b/lib/Driver/DarwinToolChains.cpp @@ -0,0 +1,452 @@ +//===------ DarwinToolChains.cpp - Job invocations (Darwin-specific) ------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "ToolChains.h" + +#include "swift/Basic/Dwarf.h" +#include "swift/Basic/LLVM.h" +#include "swift/Basic/Platform.h" +#include "swift/Basic/Range.h" +#include "swift/Basic/TaskQueue.h" +#include "swift/Config.h" +#include "swift/Driver/Compilation.h" +#include "swift/Driver/Driver.h" +#include "swift/Driver/Job.h" +#include "swift/Frontend/Frontend.h" +#include "swift/Option/Options.h" +#include "clang/Basic/Version.h" +#include "clang/Driver/Util.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" + +using namespace swift; +using namespace swift::driver; +using namespace llvm::opt; + +std::string +toolchains::Darwin::findProgramRelativeToSwiftImpl(StringRef name) const { + StringRef swiftPath = getDriver().getSwiftProgramPath(); + StringRef swiftBinDir = llvm::sys::path::parent_path(swiftPath); + + // See if we're in an Xcode toolchain. + bool hasToolchain = false; + llvm::SmallString<128> path{swiftBinDir}; + llvm::sys::path::remove_filename(path); // bin + llvm::sys::path::remove_filename(path); // usr + if (llvm::sys::path::extension(path) == ".xctoolchain") { + hasToolchain = true; + llvm::sys::path::remove_filename(path); // *.xctoolchain + llvm::sys::path::remove_filename(path); // Toolchains + llvm::sys::path::append(path, "usr", "bin"); + } + + StringRef paths[] = {swiftBinDir, path}; + auto pathsRef = llvm::makeArrayRef(paths); + if (!hasToolchain) + pathsRef = pathsRef.drop_back(); + + auto result = llvm::sys::findProgramByName(name, pathsRef); + if (result) + return result.get(); + return {}; +} + +ToolChain::InvocationInfo +toolchains::Darwin::constructInvocation(const InterpretJobAction &job, + const JobContext &context) const { + InvocationInfo II = ToolChain::constructInvocation(job, context); + + SmallString<128> runtimeLibraryPath; + getRuntimeLibraryPath(runtimeLibraryPath, context.Args, /*Shared=*/true); + + addPathEnvironmentVariableIfNeeded(II.ExtraEnvironment, "DYLD_LIBRARY_PATH", + ":", options::OPT_L, context.Args, + runtimeLibraryPath); + addPathEnvironmentVariableIfNeeded(II.ExtraEnvironment, "DYLD_FRAMEWORK_PATH", + ":", options::OPT_F, context.Args); + // FIXME: Add options::OPT_Fsystem paths to DYLD_FRAMEWORK_PATH as well. + return II; +} + +static StringRef +getDarwinLibraryNameSuffixForTriple(const llvm::Triple &triple) { + switch (getDarwinPlatformKind(triple)) { + case DarwinPlatformKind::MacOS: + return "osx"; + case DarwinPlatformKind::IPhoneOS: + return "ios"; + case DarwinPlatformKind::IPhoneOSSimulator: + return "iossim"; + case DarwinPlatformKind::TvOS: + return "tvos"; + case DarwinPlatformKind::TvOSSimulator: + return "tvossim"; + case DarwinPlatformKind::WatchOS: + return "watchos"; + case DarwinPlatformKind::WatchOSSimulator: + return "watchossim"; + } + llvm_unreachable("Unsupported Darwin platform"); +} + +std::string toolchains::Darwin::sanitizerRuntimeLibName(StringRef Sanitizer, + bool shared) const { + return (Twine("libclang_rt.") + Sanitizer + "_" + + getDarwinLibraryNameSuffixForTriple(this->getTriple()) + + (shared ? "_dynamic.dylib" : ".a")) + .str(); +} + +static void addLinkRuntimeLibRPath(const ArgList &Args, + ArgStringList &Arguments, + StringRef DarwinLibName, + const ToolChain &TC) { + // Adding the rpaths might negatively interact when other rpaths are involved, + // so we should make sure we add the rpaths last, after all user-specified + // rpaths. This is currently true from this place, but we need to be + // careful if this function is ever called before user's rpaths are emitted. + assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library"); + + // Add @executable_path to rpath to support having the dylib copied with + // the executable. + Arguments.push_back("-rpath"); + Arguments.push_back("@executable_path"); + + // Add the path to the resource dir to rpath to support using the dylib + // from the default location without copying. + + SmallString<128> ClangLibraryPath; + TC.getClangLibraryPath(Args, ClangLibraryPath); + + Arguments.push_back("-rpath"); + Arguments.push_back(Args.MakeArgString(ClangLibraryPath)); +} + +static void addLinkSanitizerLibArgsForDarwin(const ArgList &Args, + ArgStringList &Arguments, + StringRef Sanitizer, + const ToolChain &TC, + bool shared = true) { + // Sanitizer runtime libraries requires C++. + Arguments.push_back("-lc++"); + // Add explicit dependency on -lc++abi, as -lc++ doesn't re-export + // all RTTI-related symbols that are used. + Arguments.push_back("-lc++abi"); + + auto LibName = TC.sanitizerRuntimeLibName(Sanitizer, shared); + TC.addLinkRuntimeLib(Args, Arguments, LibName); + + if (shared) + addLinkRuntimeLibRPath(Args, Arguments, LibName, TC); +} + +/// Runs xcrun -f clang in order to find the location of Clang for +/// the currently active Xcode. +/// +/// We get the "currently active" part by passing through the DEVELOPER_DIR +/// environment variable (along with the rest of the environment). +static bool findXcodeClangPath(llvm::SmallVectorImpl &path) { + assert(path.empty()); + + auto xcrunPath = llvm::sys::findProgramByName("xcrun"); + if (!xcrunPath.getError()) { + const char *args[] = {"-f", "clang", nullptr}; + sys::TaskQueue queue; + queue.addTask(xcrunPath->c_str(), args, /*Env=*/llvm::None, + /*Context=*/nullptr, + /*SeparateErrors=*/true); + queue.execute(nullptr, + [&path](sys::ProcessId PID, int returnCode, StringRef output, + StringRef errors, + void *unused) -> sys::TaskFinishedResponse { + if (returnCode == 0) { + output = output.rtrim(); + path.append(output.begin(), output.end()); + } + return sys::TaskFinishedResponse::ContinueExecution; + }); + } + + return !path.empty(); +} + +static void addVersionString(const ArgList &inputArgs, ArgStringList &arguments, + unsigned major, unsigned minor, unsigned micro) { + llvm::SmallString<8> buf; + llvm::raw_svector_ostream os{buf}; + os << major << '.' << minor << '.' << micro; + arguments.push_back(inputArgs.MakeArgString(os.str())); +} + +ToolChain::InvocationInfo +toolchains::Darwin::constructInvocation(const LinkJobAction &job, + const JobContext &context) const { + assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && + "Invalid linker output type."); + + if (context.Args.hasFlag(options::OPT_static_executable, + options::OPT_no_static_executable, false)) { + llvm::report_fatal_error("-static-executable is not supported on Darwin"); + } + + const Driver &D = getDriver(); + const llvm::Triple &Triple = getTriple(); + + // 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.shouldUseInputFileList()) { + Arguments.push_back("-filelist"); + Arguments.push_back(context.getTemporaryFilePath("inputs", "LinkFileList")); + II.FilelistInfos.push_back({Arguments.back(), file_types::TY_Object, + FilelistInfo::WhichFiles::Input}); + } else { + addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, + file_types::TY_Object); + } + + addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); + + if (context.OI.CompilerMode == OutputInfo::Mode::SingleCompile) + addInputsOfType(Arguments, context.Inputs, context.Args, + file_types::TY_SwiftModuleFile, "-add_ast_path"); + else + addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, + file_types::TY_SwiftModuleFile, "-add_ast_path"); + + // Add all .swiftmodule file inputs as arguments, preceded by the + // "-add_ast_path" linker option. + addInputsOfType(Arguments, context.InputActions, + file_types::TY_SwiftModuleFile, "-add_ast_path"); + + switch (job.getKind()) { + case LinkKind::None: + llvm_unreachable("invalid link kind"); + case LinkKind::Executable: + // The default for ld; no extra flags necessary. + break; + case LinkKind::DynamicLibrary: + Arguments.push_back("-dylib"); + break; + } + + assert(Triple.isOSDarwin()); + + // FIXME: If we used Clang as a linker instead of going straight to ld, + // we wouldn't have to replicate Clang's logic here. + bool wantsObjCRuntime = false; + if (Triple.isiOS()) + wantsObjCRuntime = Triple.isOSVersionLT(9); + else if (Triple.isMacOSX()) + wantsObjCRuntime = Triple.isMacOSXVersionLT(10, 11); + + if (context.Args.hasFlag(options::OPT_link_objc_runtime, + options::OPT_no_link_objc_runtime, + /*Default=*/wantsObjCRuntime)) { + llvm::SmallString<128> ARCLiteLib(D.getSwiftProgramPath()); + llvm::sys::path::remove_filename(ARCLiteLib); // 'swift' + llvm::sys::path::remove_filename(ARCLiteLib); // 'bin' + llvm::sys::path::append(ARCLiteLib, "lib", "arc"); + + if (!llvm::sys::fs::is_directory(ARCLiteLib)) { + // If we don't have a 'lib/arc/' directory, find the "arclite" library + // relative to the Clang in the active Xcode. + ARCLiteLib.clear(); + if (findXcodeClangPath(ARCLiteLib)) { + llvm::sys::path::remove_filename(ARCLiteLib); // 'clang' + llvm::sys::path::remove_filename(ARCLiteLib); // 'bin' + llvm::sys::path::append(ARCLiteLib, "lib", "arc"); + } + } + + if (!ARCLiteLib.empty()) { + llvm::sys::path::append(ARCLiteLib, "libarclite_"); + ARCLiteLib += getPlatformNameForTriple(Triple); + ARCLiteLib += ".a"; + + Arguments.push_back("-force_load"); + Arguments.push_back(context.Args.MakeArgString(ARCLiteLib)); + + // Arclite depends on CoreFoundation. + Arguments.push_back("-framework"); + Arguments.push_back("CoreFoundation"); + } else { + // FIXME: We should probably diagnose this, but this is not a place where + // we can emit diagnostics. Silently ignore it for now. + } + } + + context.Args.AddAllArgValues(Arguments, options::OPT_Xlinker); + context.Args.AddAllArgs(Arguments, options::OPT_linker_option_Group); + for (const Arg *arg : + context.Args.filtered(options::OPT_F, options::OPT_Fsystem)) { + Arguments.push_back("-F"); + Arguments.push_back(arg->getValue()); + } + + if (context.Args.hasArg(options::OPT_enable_app_extension)) { + // Keep this string fixed in case the option used by the + // compiler itself changes. + Arguments.push_back("-application_extension"); + } + + // Linking sanitizers will add rpaths, which might negatively interact when + // other rpaths are involved, so we should make sure we add the rpaths after + // all user-specified rpaths. + if (context.OI.SelectedSanitizers & SanitizerKind::Address) + addLinkSanitizerLibArgsForDarwin(context.Args, Arguments, "asan", *this); + + if (context.OI.SelectedSanitizers & SanitizerKind::Thread) + addLinkSanitizerLibArgsForDarwin(context.Args, Arguments, "tsan", *this); + + // Only link in libFuzzer for executables. + if (job.getKind() == LinkKind::Executable && + (context.OI.SelectedSanitizers & SanitizerKind::Fuzzer)) + addLinkSanitizerLibArgsForDarwin(context.Args, Arguments, "fuzzer", *this, + /*shared=*/false); + + if (context.Args.hasArg(options::OPT_embed_bitcode, + options::OPT_embed_bitcode_marker)) { + Arguments.push_back("-bitcode_bundle"); + } + + if (!context.OI.SDKPath.empty()) { + Arguments.push_back("-syslibroot"); + Arguments.push_back(context.Args.MakeArgString(context.OI.SDKPath)); + } + + Arguments.push_back("-lobjc"); + Arguments.push_back("-lSystem"); + + Arguments.push_back("-arch"); + Arguments.push_back(context.Args.MakeArgString(getTriple().getArchName())); + + // Add the runtime library link path, which is platform-specific and found + // relative to the compiler. + SmallString<128> RuntimeLibPath; + getRuntimeLibraryPath(RuntimeLibPath, context.Args, /*Shared=*/true); + + // Link the standard library. + Arguments.push_back("-L"); + if (context.Args.hasFlag(options::OPT_static_stdlib, + options::OPT_no_static_stdlib, false)) { + SmallString<128> StaticRuntimeLibPath; + getRuntimeLibraryPath(StaticRuntimeLibPath, context.Args, /*Shared=*/false); + Arguments.push_back(context.Args.MakeArgString(StaticRuntimeLibPath)); + Arguments.push_back("-lc++"); + Arguments.push_back("-framework"); + Arguments.push_back("Foundation"); + Arguments.push_back("-force_load_swift_libs"); + } else { + Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); + // FIXME: We probably shouldn't be adding an rpath here unless we know ahead + // of time the standard library won't be copied. SR-1967 + Arguments.push_back("-rpath"); + Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); + } + + if (context.Args.hasArg(options::OPT_profile_generate)) { + SmallString<128> LibProfile(RuntimeLibPath); + llvm::sys::path::remove_filename(LibProfile); // remove platform name + llvm::sys::path::append(LibProfile, "clang", "lib", "darwin"); + + StringRef RT; + if (Triple.isiOS()) { + if (Triple.isTvOS()) + RT = "tvos"; + else + RT = "ios"; + } else if (Triple.isWatchOS()) { + RT = "watchos"; + } else { + assert(Triple.isMacOSX()); + RT = "osx"; + } + + StringRef Sim; + if (tripleIsAnySimulator(Triple)) { + Sim = "sim"; + } + + llvm::sys::path::append(LibProfile, + "libclang_rt.profile_" + RT + Sim + ".a"); + + // FIXME: Continue accepting the old path for simulator libraries for now. + if (!Sim.empty() && !llvm::sys::fs::exists(LibProfile)) { + llvm::sys::path::remove_filename(LibProfile); + llvm::sys::path::append(LibProfile, "libclang_rt.profile_" + RT + ".a"); + } + + Arguments.push_back(context.Args.MakeArgString(LibProfile)); + } + + // FIXME: Properly handle deployment targets. + assert(Triple.isiOS() || Triple.isWatchOS() || Triple.isMacOSX()); + if (Triple.isiOS()) { + bool isiOSSimulator = tripleIsiOSSimulator(Triple); + if (Triple.isTvOS()) { + if (isiOSSimulator) + Arguments.push_back("-tvos_simulator_version_min"); + else + Arguments.push_back("-tvos_version_min"); + } else { + if (isiOSSimulator) + Arguments.push_back("-ios_simulator_version_min"); + else + Arguments.push_back("-iphoneos_version_min"); + } + unsigned major, minor, micro; + Triple.getiOSVersion(major, minor, micro); + addVersionString(context.Args, Arguments, major, minor, micro); + } else if (Triple.isWatchOS()) { + if (tripleIsWatchSimulator(Triple)) + Arguments.push_back("-watchos_simulator_version_min"); + else + Arguments.push_back("-watchos_version_min"); + unsigned major, minor, micro; + Triple.getOSVersion(major, minor, micro); + addVersionString(context.Args, Arguments, major, minor, micro); + } else { + Arguments.push_back("-macosx_version_min"); + unsigned major, minor, micro; + Triple.getMacOSXVersion(major, minor, micro); + addVersionString(context.Args, Arguments, major, minor, micro); + } + + Arguments.push_back("-no_objc_category_merging"); + + // This should be the last option, for convenience in checking output. + Arguments.push_back("-o"); + Arguments.push_back( + context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); + + return II; +} diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index caf9044764def..cb7340001297a 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -50,8 +50,7 @@ const char * ToolChain::JobContext::getTemporaryFilePath(const llvm::Twine &name, StringRef suffix) const { SmallString<128> buffer; - std::error_code EC = - llvm::sys::fs::createTemporaryFile(name, suffix, buffer); + std::error_code EC = llvm::sys::fs::createTemporaryFile(name, suffix, buffer); if (EC) { // FIXME: This should not take down the entire process. llvm::report_fatal_error("unable to create temporary file for filelist"); @@ -63,13 +62,10 @@ ToolChain::JobContext::getTemporaryFilePath(const llvm::Twine &name, return C.getArgs().MakeArgString(buffer.str()); } -std::unique_ptr -ToolChain::constructJob(const JobAction &JA, - Compilation &C, - SmallVectorImpl &&inputs, - ArrayRef inputActions, - std::unique_ptr output, - const OutputInfo &OI) const { +std::unique_ptr ToolChain::constructJob( + const JobAction &JA, Compilation &C, SmallVectorImpl &&inputs, + ArrayRef inputActions, + std::unique_ptr output, const OutputInfo &OI) const { JobContext context{C, inputs, inputActions, *output, OI}; auto invocationInfo = [&]() -> InvocationInfo { @@ -77,17 +73,17 @@ ToolChain::constructJob(const JobAction &JA, #define CASE(K) \ case Action::Kind::K: \ return constructInvocation(cast(JA), context); - CASE(CompileJob) - CASE(InterpretJob) - CASE(BackendJob) - CASE(MergeModuleJob) - CASE(ModuleWrapJob) - CASE(LinkJob) - CASE(GenerateDSYMJob) - CASE(VerifyDebugInfoJob) - CASE(GeneratePCHJob) - CASE(AutolinkExtractJob) - CASE(REPLJob) + CASE(CompileJob) + CASE(InterpretJob) + CASE(BackendJob) + CASE(MergeModuleJob) + CASE(ModuleWrapJob) + CASE(LinkJob) + CASE(GenerateDSYMJob) + CASE(VerifyDebugInfoJob) + CASE(GeneratePCHJob) + CASE(AutolinkExtractJob) + CASE(REPLJob) #undef CASE case Action::Kind::Input: llvm_unreachable("not a JobAction"); @@ -153,8 +149,7 @@ file_types::ID ToolChain::lookupTypeForExtension(StringRef Ext) const { /// Return a _single_ TY_Swift InputAction, if one exists; /// if 0 or >1 such inputs exist, return nullptr. -static const InputAction* -findSingleSwiftInput(const CompileJobAction *CJA) { +static const InputAction *findSingleSwiftInput(const CompileJobAction *CJA) { auto Inputs = CJA->getInputs(); const InputAction *IA = nullptr; for (auto const *I : Inputs) { @@ -172,8 +167,7 @@ findSingleSwiftInput(const CompileJobAction *CJA) { return IA; } -static bool -jobsHaveSameExecutableNames(const Job *A, const Job *B) { +static bool jobsHaveSameExecutableNames(const Job *A, const Job *B) { // Jobs that get here (that are derived from CompileJobActions) should always // have the same executable name -- it should always be SWIFT_EXECUTABLE_NAME // -- but we check here just to be sure / fail gracefully in non-assert @@ -185,16 +179,14 @@ jobsHaveSameExecutableNames(const Job *A, const Job *B) { return true; } -static bool -jobsHaveSameOutputTypes(const Job *A, const Job *B) { +static bool jobsHaveSameOutputTypes(const Job *A, const Job *B) { if (A->getOutput().getPrimaryOutputType() != B->getOutput().getPrimaryOutputType()) return false; return A->getOutput().hasSameAdditionalOutputTypes(B->getOutput()); } -static bool -jobsHaveSameEnvironment(const Job *A, const Job *B) { +static bool jobsHaveSameEnvironment(const Job *A, const Job *B) { auto AEnv = A->getExtraEnvironment(); auto BEnv = B->getExtraEnvironment(); if (AEnv.size() != BEnv.size()) @@ -208,8 +200,7 @@ jobsHaveSameEnvironment(const Job *A, const Job *B) { return true; } -bool -ToolChain::jobIsBatchable(const Compilation &C, const Job *A) const { +bool ToolChain::jobIsBatchable(const Compilation &C, const Job *A) const { // FIXME: There might be a tighter criterion to use here? if (C.getOutputInfo().CompilerMode != OutputInfo::Mode::StandardCompile) return false; @@ -219,13 +210,11 @@ ToolChain::jobIsBatchable(const Compilation &C, const Job *A) const { return findSingleSwiftInput(CJActA) != nullptr; } -bool -ToolChain::jobsAreBatchCombinable(const Compilation &C, - const Job *A, const Job *B) const { +bool ToolChain::jobsAreBatchCombinable(const Compilation &C, const Job *A, + const Job *B) const { assert(jobIsBatchable(C, A)); assert(jobIsBatchable(C, B)); - return (jobsHaveSameExecutableNames(A, B) && - jobsHaveSameOutputTypes(A, B) && + return (jobsHaveSameExecutableNames(A, B) && jobsHaveSameOutputTypes(A, B) && jobsHaveSameEnvironment(A, B)); } @@ -286,15 +275,16 @@ mergeBatchInputs(ArrayRef jobs, /// discovered yet). So long as this is true, we need to make sure any batch job /// we build names its inputs in an order that's a subsequence of the sequence /// of inputs the driver was initially invoked with. -static void sortJobsToMatchCompilationInputs(ArrayRef unsortedJobs, - SmallVectorImpl &sortedJobs, - Compilation &C) { +static void +sortJobsToMatchCompilationInputs(ArrayRef unsortedJobs, + SmallVectorImpl &sortedJobs, + Compilation &C) { llvm::StringMap jobsByInput; for (const Job *J : unsortedJobs) { const CompileJobAction *CJA = cast(&J->getSource()); - const InputAction* IA = findSingleSwiftInput(CJA); - auto R = jobsByInput.insert(std::make_pair(IA->getInputArg().getValue(), - J)); + const InputAction *IA = findSingleSwiftInput(CJA); + auto R = + jobsByInput.insert(std::make_pair(IA->getInputArg().getValue(), J)); assert(R.second); } for (const InputPair &P : C.getInputFiles()) { @@ -310,8 +300,7 @@ static void sortJobsToMatchCompilationInputs(ArrayRef unsortedJobs, /// on \p BatchJob, to build the \c InvocationInfo. std::unique_ptr ToolChain::constructBatchJob(ArrayRef unsortedJobs, - Compilation &C) const -{ + Compilation &C) const { if (unsortedJobs.empty()) return nullptr; @@ -336,21 +325,9 @@ ToolChain::constructBatchJob(ArrayRef unsortedJobs, JobContext context{C, inputJobs.getArrayRef(), inputActions.getArrayRef(), *output, OI}; auto invocationInfo = constructInvocation(*batchCJA, context); - return llvm::make_unique(*batchCJA, - inputJobs.takeVector(), - std::move(output), - executablePath, - std::move(invocationInfo.Arguments), - std::move(invocationInfo.ExtraEnvironment), - std::move(invocationInfo.FilelistInfos), - sortedJobs); -} - -bool -ToolChain::sanitizerRuntimeLibExists(const ArgList &args, - StringRef sanitizerName, - bool shared) const { - // Assume no sanitizers are supported by default. - // This method should be overriden by a platform-specific subclass. - return false; + return llvm::make_unique( + *batchCJA, inputJobs.takeVector(), std::move(output), executablePath, + std::move(invocationInfo.Arguments), + std::move(invocationInfo.ExtraEnvironment), + std::move(invocationInfo.FilelistInfos), sortedJobs); } diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 44221595f696b..d7adb879e3e67 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -17,12 +17,12 @@ #include "swift/Basic/Platform.h" #include "swift/Basic/Range.h" #include "swift/Basic/TaskQueue.h" +#include "swift/Config.h" #include "swift/Driver/Compilation.h" #include "swift/Driver/Driver.h" #include "swift/Driver/Job.h" #include "swift/Frontend/Frontend.h" #include "swift/Option/Options.h" -#include "swift/Config.h" #include "clang/Basic/Version.h" #include "clang/Driver/Util.h" #include "llvm/ADT/StringSwitch.h" @@ -66,10 +66,10 @@ bool ToolChain::JobContext::shouldFilterFrontendInputsByType() const { return OI.CompilerMode != OutputInfo::Mode::SingleCompile; } -static void addInputsOfType(ArgStringList &Arguments, - ArrayRef Inputs, - file_types::ID InputType, - const char *PrefixArgument = nullptr) { +void ToolChain::addInputsOfType(ArgStringList &Arguments, + ArrayRef Inputs, + file_types::ID InputType, + const char *PrefixArgument) const { for (auto &Input : Inputs) { if (Input->getType() != InputType) continue; @@ -79,11 +79,11 @@ static void addInputsOfType(ArgStringList &Arguments, } } -static void addInputsOfType(ArgStringList &Arguments, - ArrayRef Jobs, - const llvm::opt::ArgList &Args, - file_types::ID InputType, - const char *PrefixArgument = nullptr) { +void ToolChain::addInputsOfType(ArgStringList &Arguments, + ArrayRef Jobs, + const llvm::opt::ArgList &Args, + file_types::ID InputType, + const char *PrefixArgument) const { for (const Job *Cmd : Jobs) { auto output = Cmd->getOutput().getAnyOutputForType(InputType); if (!output.empty()) { @@ -94,11 +94,11 @@ static void addInputsOfType(ArgStringList &Arguments, } } -static void addPrimaryInputsOfType(ArgStringList &Arguments, - ArrayRef Jobs, - const llvm::opt::ArgList &Args, - file_types::ID InputType, - const char *PrefixArgument = nullptr) { +void ToolChain::addPrimaryInputsOfType(ArgStringList &Arguments, + ArrayRef Jobs, + const llvm::opt::ArgList &Args, + file_types::ID InputType, + const char *PrefixArgument) const { for (const Job *Cmd : Jobs) { auto &outputInfo = Cmd->getOutput(); if (outputInfo.getPrimaryOutputType() == InputType) { @@ -129,8 +129,7 @@ static bool addOutputsOfType(ArgStringList &Arguments, /// Handle arguments common to all invocations of the frontend (compilation, /// module-merging, LLDB's REPL, etc). -static void addCommonFrontendArgs(const ToolChain &TC, - const OutputInfo &OI, +static void addCommonFrontendArgs(const ToolChain &TC, const OutputInfo &OI, const CommandOutput &output, const ArgList &inputArgs, ArgStringList &arguments) { @@ -262,8 +261,8 @@ ToolChain::constructInvocation(const CompileJobAction &job, context.addFrontendInputAndOutputArguments(Arguments, II.FilelistInfos); // Forward migrator flags. - if (auto DataPath = context.Args.getLastArg(options:: - OPT_api_diff_data_file)) { + if (auto DataPath = + context.Args.getLastArg(options::OPT_api_diff_data_file)) { Arguments.push_back("-api-diff-data-file"); Arguments.push_back(DataPath->getValue()); } @@ -283,10 +282,9 @@ ToolChain::constructInvocation(const CompileJobAction &job, bool ForwardAsIs = true; bool bridgingPCHIsEnabled = context.Args.hasFlag(options::OPT_enable_bridging_pch, - options::OPT_disable_bridging_pch, - true); + options::OPT_disable_bridging_pch, true); bool usePersistentPCH = bridgingPCHIsEnabled && - context.Args.hasArg(options::OPT_pch_output_dir); + context.Args.hasArg(options::OPT_pch_output_dir); if (!usePersistentPCH) { for (auto *IJ : context.Inputs) { if (!IJ->getOutput().getAnyOutputForType(file_types::TY_PCH).empty()) { @@ -456,7 +454,7 @@ void ToolChain::JobContext::addFrontendInputAndOutputArguments( assert((C.getFilelistThreshold() != Compilation::NEVER_USE_FILELIST || !UseFileList && !UsePrimaryFileList && - !UseSupplementaryOutputFileList) && + !UseSupplementaryOutputFileList) && "No filelists are used if FilelistThreshold=NEVER_USE_FILELIST"); if (UseFileList) { @@ -614,7 +612,8 @@ ToolChain::constructInvocation(const BackendJobAction &job, FrontendModeOption = "-S"; break; case file_types::TY_Nothing: - // We were told to output nothing, so get the last mode option and use that. + // We were told to output nothing, so get the last mode option and use + // that. if (const Arg *A = context.Args.getLastArg(options::OPT_modes_Group)) FrontendModeOption = A->getSpelling().data(); else @@ -658,7 +657,7 @@ ToolChain::constructInvocation(const BackendJobAction &job, } assert(FrontendModeOption != nullptr && "No frontend mode option specified!"); - + Arguments.push_back(FrontendModeOption); // Add input arguments. @@ -675,7 +674,7 @@ ToolChain::constructInvocation(const BackendJobAction &job, assert(context.Inputs.size() == 1 && "The backend expects one input!"); Arguments.push_back("-primary-file"); const Job *Cmd = context.Inputs.front(); - + // In multi-threaded compilation, the backend job must select the correct // output file of the compilation job. auto OutNames = Cmd->getOutput().getPrimaryOutputFilenames(); @@ -793,8 +792,8 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job, "The MergeModule tool only produces swiftmodule files!"); Arguments.push_back("-o"); - Arguments.push_back(context.Args.MakeArgString( - context.Output.getPrimaryOutputFilename())); + Arguments.push_back( + context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); return II; } @@ -818,10 +817,10 @@ ToolChain::constructInvocation(const ModuleWrapJobAction &job, Arguments.push_back("-target"); Arguments.push_back(context.Args.MakeArgString(getTriple().str())); - + Arguments.push_back("-o"); - Arguments.push_back(context.Args.MakeArgString( - context.Output.getPrimaryOutputFilename())); + Arguments.push_back( + context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); return {SWIFT_EXECUTABLE_NAME, Arguments}; } @@ -873,7 +872,6 @@ ToolChain::constructInvocation(const REPLJobAction &job, return {"lldb", Arguments}; } - ToolChain::InvocationInfo ToolChain::constructInvocation(const GenerateDSYMJobAction &job, const JobContext &context) const { @@ -888,8 +886,8 @@ ToolChain::constructInvocation(const GenerateDSYMJobAction &job, Arguments.push_back(context.Args.MakeArgString(inputPath)); Arguments.push_back("-o"); - Arguments.push_back(context.Args.MakeArgString( - context.Output.getPrimaryOutputFilename())); + Arguments.push_back( + context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); return {"dsymutil", Arguments}; } @@ -940,13 +938,12 @@ ToolChain::constructInvocation(const GeneratePCHJobAction &job, if (job.isPersistentPCH()) { Arguments.push_back("-emit-pch"); Arguments.push_back("-pch-output-dir"); - Arguments.push_back( - context.Args.MakeArgString(job.getPersistentPCHDir())); + Arguments.push_back(context.Args.MakeArgString(job.getPersistentPCHDir())); } else { Arguments.push_back("-emit-pch"); Arguments.push_back("-o"); - Arguments.push_back(context.Args.MakeArgString( - context.Output.getPrimaryOutputFilename())); + Arguments.push_back( + context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); } return {SWIFT_EXECUTABLE_NAME, Arguments}; @@ -964,77 +961,9 @@ ToolChain::constructInvocation(const LinkJobAction &job, llvm_unreachable("linking not implemented for this toolchain"); } -std::string -toolchains::Darwin::findProgramRelativeToSwiftImpl(StringRef name) const { - StringRef swiftPath = getDriver().getSwiftProgramPath(); - StringRef swiftBinDir = llvm::sys::path::parent_path(swiftPath); - - // See if we're in an Xcode toolchain. - bool hasToolchain = false; - llvm::SmallString<128> path{swiftBinDir}; - llvm::sys::path::remove_filename(path); // bin - llvm::sys::path::remove_filename(path); // usr - if (llvm::sys::path::extension(path) == ".xctoolchain") { - hasToolchain = true; - llvm::sys::path::remove_filename(path); // *.xctoolchain - llvm::sys::path::remove_filename(path); // Toolchains - llvm::sys::path::append(path, "usr", "bin"); - } - - StringRef paths[] = { swiftBinDir, path }; - auto pathsRef = llvm::makeArrayRef(paths); - if (!hasToolchain) - pathsRef = pathsRef.drop_back(); - - auto result = llvm::sys::findProgramByName(name, pathsRef); - if (result) - return result.get(); - return {}; -} - -static void addVersionString(const ArgList &inputArgs, ArgStringList &arguments, - unsigned major, unsigned minor, unsigned micro) { - llvm::SmallString<8> buf; - llvm::raw_svector_ostream os{buf}; - os << major << '.' << minor << '.' << micro; - arguments.push_back(inputArgs.MakeArgString(os.str())); -} - -/// Runs xcrun -f clang in order to find the location of Clang for -/// the currently active Xcode. -/// -/// We get the "currently active" part by passing through the DEVELOPER_DIR -/// environment variable (along with the rest of the environment). -static bool findXcodeClangPath(llvm::SmallVectorImpl &path) { - assert(path.empty()); - - auto xcrunPath = llvm::sys::findProgramByName("xcrun"); - if (!xcrunPath.getError()) { - const char *args[] = {"-f", "clang", nullptr}; - sys::TaskQueue queue; - queue.addTask(xcrunPath->c_str(), args, /*Env=*/llvm::None, - /*Context=*/nullptr, - /*SeparateErrors=*/true); - queue.execute(nullptr, [&path](sys::ProcessId PID, int returnCode, - StringRef output, StringRef errors, - void *unused) -> sys::TaskFinishedResponse { - if (returnCode == 0) { - output = output.rtrim(); - path.append(output.begin(), output.end()); - } - return sys::TaskFinishedResponse::ContinueExecution; - }); - } - - return !path.empty(); -} - -static void addPathEnvironmentVariableIfNeeded(Job::EnvironmentVector &env, - const char *name, - const char *separator, - options::ID optionID, - const ArgList &args, - StringRef extraEntry = "") { +void ToolChain::addPathEnvironmentVariableIfNeeded( + Job::EnvironmentVector &env, const char *name, const char *separator, + options::ID optionID, const ArgList &args, StringRef extraEntry) const { auto linkPathOptions = args.filtered(optionID); if (linkPathOptions.begin() == linkPathOptions.end() && extraEntry.empty()) return; @@ -1055,12 +984,31 @@ static void addPathEnvironmentVariableIfNeeded(Job::EnvironmentVector &env, env.emplace_back(name, args.MakeArgString(newPaths)); } +void ToolChain::addLinkRuntimeLib(const ArgList &Args, ArgStringList &Arguments, + StringRef LibName) const { + SmallString<128> P; + getClangLibraryPath(Args, P); + llvm::sys::path::append(P, LibName); + Arguments.push_back(Args.MakeArgString(P)); +} + +void ToolChain::getClangLibraryPath(const ArgList &Args, + SmallString<128> &LibPath) const { + const llvm::Triple &T = getTriple(); + + getRuntimeLibraryPath(LibPath, Args, /*Shared=*/true); + // Remove platform name. + llvm::sys::path::remove_filename(LibPath); + llvm::sys::path::append(LibPath, "clang", "lib", + T.isOSDarwin() ? "darwin" + : getPlatformNameForTriple(T)); +} + /// Get the runtime library link path, which is platform-specific and found /// relative to the compiler. -static void getRuntimeLibraryPath(SmallVectorImpl &runtimeLibPath, - const llvm::opt::ArgList &args, - const ToolChain &TC, - bool shared) { +void ToolChain::getRuntimeLibraryPath(SmallVectorImpl &runtimeLibPath, + const llvm::opt::ArgList &args, + bool shared) const { // FIXME: Duplicated from CompilerInvocation, but in theory the runtime // library link path and the standard library module import path don't // need to be the same. @@ -1068,892 +1016,23 @@ static void getRuntimeLibraryPath(SmallVectorImpl &runtimeLibPath, StringRef value = A->getValue(); runtimeLibPath.append(value.begin(), value.end()); } else { - auto programPath = TC.getDriver().getSwiftProgramPath(); + auto programPath = getDriver().getSwiftProgramPath(); runtimeLibPath.append(programPath.begin(), programPath.end()); llvm::sys::path::remove_filename(runtimeLibPath); // remove /swift llvm::sys::path::remove_filename(runtimeLibPath); // remove /bin - llvm::sys::path::append(runtimeLibPath, "lib", shared ? "swift" : "swift_static"); + llvm::sys::path::append(runtimeLibPath, "lib", + shared ? "swift" : "swift_static"); } llvm::sys::path::append(runtimeLibPath, - getPlatformNameForTriple(TC.getTriple())); -} - -static void getClangLibraryPath(const ToolChain &TC, const ArgList &Args, - SmallString<128> &LibPath) { - const llvm::Triple &T = TC.getTriple(); - - getRuntimeLibraryPath(LibPath, Args, TC, /*Shared=*/ true); - // Remove platform name. - llvm::sys::path::remove_filename(LibPath); - llvm::sys::path::append(LibPath, "clang", "lib", - T.isOSDarwin() ? "darwin" - : getPlatformNameForTriple(T)); -} - -ToolChain::InvocationInfo -toolchains::Darwin::constructInvocation(const InterpretJobAction &job, - const JobContext &context) const { - InvocationInfo II = ToolChain::constructInvocation(job, context); - - SmallString<128> runtimeLibraryPath; - getRuntimeLibraryPath(runtimeLibraryPath, context.Args, *this, /*Shared=*/ true); - - addPathEnvironmentVariableIfNeeded(II.ExtraEnvironment, "DYLD_LIBRARY_PATH", - ":", options::OPT_L, context.Args, - runtimeLibraryPath); - addPathEnvironmentVariableIfNeeded(II.ExtraEnvironment, "DYLD_FRAMEWORK_PATH", - ":", options::OPT_F, context.Args); - // FIXME: Add options::OPT_Fsystem paths to DYLD_FRAMEWORK_PATH as well. - return II; -} - -static StringRef -getDarwinLibraryNameSuffixForTriple(const llvm::Triple &triple) { - switch (getDarwinPlatformKind(triple)) { - case DarwinPlatformKind::MacOS: - return "osx"; - case DarwinPlatformKind::IPhoneOS: - return "ios"; - case DarwinPlatformKind::IPhoneOSSimulator: - return "iossim"; - case DarwinPlatformKind::TvOS: - return "tvos"; - case DarwinPlatformKind::TvOSSimulator: - return "tvossim"; - case DarwinPlatformKind::WatchOS: - return "watchos"; - case DarwinPlatformKind::WatchOSSimulator: - return "watchossim"; - } - llvm_unreachable("Unsupported Darwin platform"); -} - -static std::string -getSanitizerRuntimeLibNameForDarwin(StringRef Sanitizer, - const llvm::Triple &Triple, - bool shared = true) { - return (Twine("libclang_rt.") - + Sanitizer + "_" - + getDarwinLibraryNameSuffixForTriple(Triple) - + (shared ? "_dynamic.dylib" : ".a")).str(); -} - -static std::string -getSanitizerRuntimeLibNameForWindows(StringRef Sanitizer, - const llvm::Triple &Triple) { - return (Twine("clang_rt.") + Sanitizer + "-" + Triple.getArchName() + ".lib") - .str(); -} - -static std::string -getSanitizerRuntimeLibNameForLinux(StringRef Sanitizer, const llvm::Triple &Triple) { - return (Twine("libclang_rt.") + Sanitizer + "-" + - Triple.getArchName() + ".a").str(); -} - -bool toolchains::Darwin::sanitizerRuntimeLibExists( - const ArgList &args, StringRef sanitizer, bool shared) const { - SmallString<128> sanitizerLibPath; - getClangLibraryPath(*this, args, sanitizerLibPath); - llvm::sys::path::append(sanitizerLibPath, - getSanitizerRuntimeLibNameForDarwin( - sanitizer, this->getTriple(), shared)); - return llvm::sys::fs::exists(sanitizerLibPath.str()); -} - -bool toolchains::Windows::sanitizerRuntimeLibExists(const ArgList &args, - StringRef sanitizer, - bool shared) const { - SmallString<128> sanitizerLibPath; - getClangLibraryPath(*this, args, sanitizerLibPath); - llvm::sys::path::append( - sanitizerLibPath, - getSanitizerRuntimeLibNameForWindows(sanitizer, this->getTriple())); - return llvm::sys::fs::exists(sanitizerLibPath.str()); + getPlatformNameForTriple(getTriple())); } -bool toolchains::GenericUnix::sanitizerRuntimeLibExists( - const ArgList &args, StringRef sanitizer, bool shared) const { +bool ToolChain::sanitizerRuntimeLibExists(const ArgList &args, + StringRef sanitizerName, + bool shared) const { SmallString<128> sanitizerLibPath; - getClangLibraryPath(*this, args, sanitizerLibPath); - - // All libraries are static for linux. + getClangLibraryPath(args, sanitizerLibPath); llvm::sys::path::append(sanitizerLibPath, - getSanitizerRuntimeLibNameForLinux(sanitizer, this->getTriple())); + sanitizerRuntimeLibName(sanitizerName, shared)); return llvm::sys::fs::exists(sanitizerLibPath.str()); } - - -static void -addLinkRuntimeLibForDarwin(const ArgList &Args, ArgStringList &Arguments, - StringRef DarwinLibName, bool AddRPath, - const ToolChain &TC) { - SmallString<128> ClangLibraryPath; - getClangLibraryPath(TC, Args, ClangLibraryPath); - - SmallString<128> P(ClangLibraryPath); - llvm::sys::path::append(P, DarwinLibName); - Arguments.push_back(Args.MakeArgString(P)); - - // Adding the rpaths might negatively interact when other rpaths are involved, - // so we should make sure we add the rpaths last, after all user-specified - // rpaths. This is currently true from this place, but we need to be - // careful if this function is ever called before user's rpaths are emitted. - if (AddRPath) { - assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library"); - - // Add @executable_path to rpath to support having the dylib copied with - // the executable. - Arguments.push_back("-rpath"); - Arguments.push_back("@executable_path"); - - // Add the path to the resource dir to rpath to support using the dylib - // from the default location without copying. - Arguments.push_back("-rpath"); - Arguments.push_back(Args.MakeArgString(ClangLibraryPath)); - } -} - -static void addLinkRuntimeLibForWindows(const ArgList &Args, - ArgStringList &Arguments, - StringRef WindowsLibName, - const ToolChain &TC) { - SmallString<128> P; - getClangLibraryPath(TC, Args, P); - llvm::sys::path::append(P, WindowsLibName); - Arguments.push_back(Args.MakeArgString(P)); -} - -static void -addLinkRuntimeLibForLinux(const ArgList &Args, ArgStringList &Arguments, - StringRef LinuxLibName, - const ToolChain &TC) { - SmallString<128> P; - getClangLibraryPath(TC, Args, P); - llvm::sys::path::append(P, LinuxLibName); - Arguments.push_back(Args.MakeArgString(P)); -} - -static void -addLinkSanitizerLibArgsForDarwin(const ArgList &Args, - ArgStringList &Arguments, - StringRef Sanitizer, - const ToolChain &TC, - bool shared = true - ) { - // Sanitizer runtime libraries requires C++. - Arguments.push_back("-lc++"); - // Add explicit dependency on -lc++abi, as -lc++ doesn't re-export - // all RTTI-related symbols that are used. - Arguments.push_back("-lc++abi"); - - addLinkRuntimeLibForDarwin(Args, Arguments, - getSanitizerRuntimeLibNameForDarwin(Sanitizer, TC.getTriple(), shared), - /*AddRPath=*/ shared, TC); -} - -static void addLinkSanitizerLibArgsForWindows(const ArgList &Args, - ArgStringList &Arguments, - StringRef Sanitizer, - const ToolChain &TC) { - addLinkRuntimeLibForWindows( - Args, Arguments, - getSanitizerRuntimeLibNameForWindows(Sanitizer, TC.getTriple()), TC); -} - -static void addLinkSanitizerLibArgsForLinux(const ArgList &Args, - ArgStringList &Arguments, - StringRef Sanitizer, - const ToolChain &TC) { - addLinkRuntimeLibForLinux( - Args, Arguments, - getSanitizerRuntimeLibNameForLinux(Sanitizer, TC.getTriple()), TC); - - // Code taken from - // https://github.com/apple/swift-clang/blob/ab3cbe7/lib/Driver/Tools.cpp#L3264-L3276 - // There's no libpthread or librt on RTEMS. - if (TC.getTriple().getOS() != llvm::Triple::RTEMS) { - Arguments.push_back("-lpthread"); - Arguments.push_back("-lrt"); - } - Arguments.push_back("-lm"); - - // There's no libdl on FreeBSD or RTEMS. - if (TC.getTriple().getOS() != llvm::Triple::FreeBSD && - TC.getTriple().getOS() != llvm::Triple::RTEMS) - Arguments.push_back("-ldl"); -} - -ToolChain::InvocationInfo -toolchains::Darwin::constructInvocation(const LinkJobAction &job, - const JobContext &context) const { - assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && - "Invalid linker output type."); - - if (context.Args.hasFlag(options::OPT_static_executable, - options::OPT_no_static_executable, - false)) { - llvm::report_fatal_error("-static-executable is not supported on Darwin"); - } - - const Driver &D = getDriver(); - const llvm::Triple &Triple = getTriple(); - - // 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.shouldUseInputFileList()) { - Arguments.push_back("-filelist"); - Arguments.push_back(context.getTemporaryFilePath("inputs", "LinkFileList")); - II.FilelistInfos.push_back({Arguments.back(), file_types::TY_Object, - FilelistInfo::WhichFiles::Input}); - } else { - addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, - file_types::TY_Object); - } - - addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); - - if (context.OI.CompilerMode == OutputInfo::Mode::SingleCompile) - addInputsOfType(Arguments, context.Inputs, context.Args, - file_types::TY_SwiftModuleFile, "-add_ast_path"); - else - addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, - file_types::TY_SwiftModuleFile, "-add_ast_path"); - - // Add all .swiftmodule file inputs as arguments, preceded by the - // "-add_ast_path" linker option. - addInputsOfType(Arguments, context.InputActions, - file_types::TY_SwiftModuleFile, "-add_ast_path"); - - switch (job.getKind()) { - case LinkKind::None: - llvm_unreachable("invalid link kind"); - case LinkKind::Executable: - // The default for ld; no extra flags necessary. - break; - case LinkKind::DynamicLibrary: - Arguments.push_back("-dylib"); - break; - } - - assert(Triple.isOSDarwin()); - - // FIXME: If we used Clang as a linker instead of going straight to ld, - // we wouldn't have to replicate Clang's logic here. - bool wantsObjCRuntime = false; - if (Triple.isiOS()) - wantsObjCRuntime = Triple.isOSVersionLT(9); - else if (Triple.isMacOSX()) - wantsObjCRuntime = Triple.isMacOSXVersionLT(10, 11); - - if (context.Args.hasFlag(options::OPT_link_objc_runtime, - options::OPT_no_link_objc_runtime, - /*Default=*/wantsObjCRuntime)) { - llvm::SmallString<128> ARCLiteLib(D.getSwiftProgramPath()); - llvm::sys::path::remove_filename(ARCLiteLib); // 'swift' - llvm::sys::path::remove_filename(ARCLiteLib); // 'bin' - llvm::sys::path::append(ARCLiteLib, "lib", "arc"); - - if (!llvm::sys::fs::is_directory(ARCLiteLib)) { - // If we don't have a 'lib/arc/' directory, find the "arclite" library - // relative to the Clang in the active Xcode. - ARCLiteLib.clear(); - if (findXcodeClangPath(ARCLiteLib)) { - llvm::sys::path::remove_filename(ARCLiteLib); // 'clang' - llvm::sys::path::remove_filename(ARCLiteLib); // 'bin' - llvm::sys::path::append(ARCLiteLib, "lib", "arc"); - } - } - - if (!ARCLiteLib.empty()) { - llvm::sys::path::append(ARCLiteLib, "libarclite_"); - ARCLiteLib += getPlatformNameForTriple(Triple); - ARCLiteLib += ".a"; - - Arguments.push_back("-force_load"); - Arguments.push_back(context.Args.MakeArgString(ARCLiteLib)); - - // Arclite depends on CoreFoundation. - Arguments.push_back("-framework"); - Arguments.push_back("CoreFoundation"); - } else { - // FIXME: We should probably diagnose this, but this is not a place where - // we can emit diagnostics. Silently ignore it for now. - } - } - - context.Args.AddAllArgValues(Arguments, options::OPT_Xlinker); - context.Args.AddAllArgs(Arguments, options::OPT_linker_option_Group); - for (const Arg *arg : context.Args.filtered(options::OPT_F, - options::OPT_Fsystem)) { - Arguments.push_back("-F"); - Arguments.push_back(arg->getValue()); - } - - if (context.Args.hasArg(options::OPT_enable_app_extension)) { - // Keep this string fixed in case the option used by the - // compiler itself changes. - Arguments.push_back("-application_extension"); - } - - // Linking sanitizers will add rpaths, which might negatively interact when - // other rpaths are involved, so we should make sure we add the rpaths after - // all user-specified rpaths. - if (context.OI.SelectedSanitizers & SanitizerKind::Address) - addLinkSanitizerLibArgsForDarwin(context.Args, Arguments, "asan", *this); - - if (context.OI.SelectedSanitizers & SanitizerKind::Thread) - addLinkSanitizerLibArgsForDarwin(context.Args, Arguments, "tsan", *this); - - // Only link in libFuzzer for executables. - if (job.getKind() == LinkKind::Executable && - (context.OI.SelectedSanitizers & SanitizerKind::Fuzzer)) - addLinkSanitizerLibArgsForDarwin( - context.Args, Arguments, "fuzzer", *this, /*shared=*/false); - - if (context.Args.hasArg(options::OPT_embed_bitcode, - options::OPT_embed_bitcode_marker)) { - Arguments.push_back("-bitcode_bundle"); - } - - if (!context.OI.SDKPath.empty()) { - Arguments.push_back("-syslibroot"); - Arguments.push_back(context.Args.MakeArgString(context.OI.SDKPath)); - } - - Arguments.push_back("-lobjc"); - Arguments.push_back("-lSystem"); - - Arguments.push_back("-arch"); - Arguments.push_back(context.Args.MakeArgString(getTriple().getArchName())); - - // Add the runtime library link path, which is platform-specific and found - // relative to the compiler. - SmallString<128> RuntimeLibPath; - getRuntimeLibraryPath(RuntimeLibPath, context.Args, *this, /*Shared=*/ true); - - // Link the standard library. - Arguments.push_back("-L"); - if (context.Args.hasFlag(options::OPT_static_stdlib, - options::OPT_no_static_stdlib, - false)) { - SmallString<128> StaticRuntimeLibPath; - getRuntimeLibraryPath(StaticRuntimeLibPath, context.Args, *this, /*Shared=*/ false); - Arguments.push_back(context.Args.MakeArgString(StaticRuntimeLibPath)); - Arguments.push_back("-lc++"); - Arguments.push_back("-framework"); - Arguments.push_back("Foundation"); - Arguments.push_back("-force_load_swift_libs"); - } else { - Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); - // FIXME: We probably shouldn't be adding an rpath here unless we know ahead - // of time the standard library won't be copied. SR-1967 - Arguments.push_back("-rpath"); - Arguments.push_back(context.Args.MakeArgString(RuntimeLibPath)); - } - - if (context.Args.hasArg(options::OPT_profile_generate)) { - SmallString<128> LibProfile(RuntimeLibPath); - llvm::sys::path::remove_filename(LibProfile); // remove platform name - llvm::sys::path::append(LibProfile, "clang", "lib", "darwin"); - - StringRef RT; - if (Triple.isiOS()) { - if (Triple.isTvOS()) - RT = "tvos"; - else - RT = "ios"; - } else if (Triple.isWatchOS()) { - RT = "watchos"; - } else { - assert(Triple.isMacOSX()); - RT = "osx"; - } - - StringRef Sim; - if (tripleIsAnySimulator(Triple)) { - Sim = "sim"; - } - - llvm::sys::path::append(LibProfile, - "libclang_rt.profile_" + RT + Sim + ".a"); - - // FIXME: Continue accepting the old path for simulator libraries for now. - if (!Sim.empty() && !llvm::sys::fs::exists(LibProfile)) { - llvm::sys::path::remove_filename(LibProfile); - llvm::sys::path::append(LibProfile, - "libclang_rt.profile_" + RT + ".a"); - } - - Arguments.push_back(context.Args.MakeArgString(LibProfile)); - } - - // FIXME: Properly handle deployment targets. - assert(Triple.isiOS() || Triple.isWatchOS() || Triple.isMacOSX()); - if (Triple.isiOS()) { - bool isiOSSimulator = tripleIsiOSSimulator(Triple); - if (Triple.isTvOS()) { - if (isiOSSimulator) - Arguments.push_back("-tvos_simulator_version_min"); - else - Arguments.push_back("-tvos_version_min"); - } else { - if (isiOSSimulator) - Arguments.push_back("-ios_simulator_version_min"); - else - Arguments.push_back("-iphoneos_version_min"); - } - unsigned major, minor, micro; - Triple.getiOSVersion(major, minor, micro); - addVersionString(context.Args, Arguments, major, minor, micro); - } else if (Triple.isWatchOS()) { - if (tripleIsWatchSimulator(Triple)) - Arguments.push_back("-watchos_simulator_version_min"); - else - Arguments.push_back("-watchos_version_min"); - unsigned major, minor, micro; - Triple.getOSVersion(major, minor, micro); - addVersionString(context.Args, Arguments, major, minor, micro); - } else { - Arguments.push_back("-macosx_version_min"); - unsigned major, minor, micro; - Triple.getMacOSXVersion(major, minor, micro); - addVersionString(context.Args, Arguments, major, minor, micro); - } - - Arguments.push_back("-no_objc_category_merging"); - - // This should be the last option, for convenience in checking output. - Arguments.push_back("-o"); - Arguments.push_back(context.Args.MakeArgString( - context.Output.getPrimaryOutputFilename())); - - return II; -} - -ToolChain::InvocationInfo -toolchains::Windows::constructInvocation(const LinkJobAction &job, - const JobContext &context) const { - assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && - "Invalid linker output type."); - - ArgStringList Arguments; - - switch (job.getKind()) { - case LinkKind::None: - llvm_unreachable("invalid link kind"); - case LinkKind::Executable: - // Default case, nothing extra needed. - break; - case LinkKind::DynamicLibrary: - Arguments.push_back("-shared"); - break; - } - - // Select the linker to use. - std::string Linker; - if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) { - Linker = A->getValue(); - } - if (!Linker.empty()) - Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker)); - - // Configure the toolchain. - // By default, use the system clang++ to link. - const char *Clang = nullptr; - 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()); - } - if (Clang == nullptr) { - if (auto pathClang = llvm::sys::findProgramByName("clang++", None)) - Clang = context.Args.MakeArgString(pathClang.get()); - } - assert(Clang && - "clang++ was not found in the toolchain directory or system path."); - - std::string Target = getTriple().str(); - if (!Target.empty()) { - Arguments.push_back("-target"); - Arguments.push_back(context.Args.MakeArgString(Target)); - } - - SmallString<128> SharedRuntimeLibPath; - getRuntimeLibraryPath(SharedRuntimeLibPath, context.Args, *this, - /*Shared=*/true); - - // Link the standard library. - Arguments.push_back("-L"); - if (context.Args.hasFlag(options::OPT_static_stdlib, - options::OPT_no_static_stdlib, false)) { - SmallString<128> StaticRuntimeLibPath; - getRuntimeLibraryPath(StaticRuntimeLibPath, context.Args, *this, - /*Shared=*/false); - - // Since Windows has separate libraries per architecture, link against the - // architecture specific version of the static library. - Arguments.push_back(context.Args.MakeArgString(StaticRuntimeLibPath + "/" + - getTriple().getArchName())); - } else { - Arguments.push_back(context.Args.MakeArgString(SharedRuntimeLibPath + "/" + - getTriple().getArchName())); - } - - SmallString<128> swiftrtPath = SharedRuntimeLibPath; - llvm::sys::path::append(swiftrtPath, - swift::getMajorArchitectureName(getTriple())); - llvm::sys::path::append(swiftrtPath, "swiftrt.o"); - Arguments.push_back(context.Args.MakeArgString(swiftrtPath)); - - addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, - file_types::TY_Object); - addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); - - for (const Arg *arg : - context.Args.filtered(options::OPT_F, options::OPT_Fsystem)) { - if (arg->getOption().matches(options::OPT_Fsystem)) - Arguments.push_back("-iframework"); - else - Arguments.push_back(context.Args.MakeArgString(arg->getSpelling())); - Arguments.push_back(arg->getValue()); - } - - if (!context.OI.SDKPath.empty()) { - Arguments.push_back("-I"); - Arguments.push_back(context.Args.MakeArgString(context.OI.SDKPath)); - } - - if (job.getKind() == LinkKind::Executable) { - if (context.OI.SelectedSanitizers & SanitizerKind::Address) - addLinkSanitizerLibArgsForWindows(context.Args, Arguments, "asan", *this); - } - - if (context.Args.hasArg(options::OPT_profile_generate)) { - SmallString<128> LibProfile(SharedRuntimeLibPath); - llvm::sys::path::remove_filename(LibProfile); // remove platform name - llvm::sys::path::append(LibProfile, "clang", "lib"); - - llvm::sys::path::append(LibProfile, getTriple().getOSName(), - Twine("clang_rt.profile-") + - getTriple().getArchName() + ".lib"); - Arguments.push_back(context.Args.MakeArgString(LibProfile)); - Arguments.push_back(context.Args.MakeArgString( - Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); - } - - context.Args.AddAllArgs(Arguments, options::OPT_Xlinker); - context.Args.AddAllArgs(Arguments, options::OPT_linker_option_Group); - - // This should be the last option, for convenience in checking output. - Arguments.push_back("-o"); - Arguments.push_back( - context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); - - return {Clang, Arguments}; -} - -ToolChain::InvocationInfo -toolchains::GenericUnix::constructInvocation(const InterpretJobAction &job, - const JobContext &context) const { - InvocationInfo II = ToolChain::constructInvocation(job, context); - - SmallString<128> runtimeLibraryPath; - getRuntimeLibraryPath(runtimeLibraryPath, context.Args, *this, - /*Shared=*/true); - - addPathEnvironmentVariableIfNeeded(II.ExtraEnvironment, "LD_LIBRARY_PATH", - ":", options::OPT_L, context.Args, - runtimeLibraryPath); - return II; -} - -ToolChain::InvocationInfo toolchains::GenericUnix::constructInvocation( - const AutolinkExtractJobAction &job, const JobContext &context) const { - assert(context.Output.getPrimaryOutputType() == file_types::TY_AutolinkFile); - - ArgStringList Arguments; - addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, - file_types::TY_Object); - addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); - - Arguments.push_back("-o"); - Arguments.push_back( - context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); - - return {"swift-autolink-extract", Arguments}; -} - -std::string toolchains::GenericUnix::getDefaultLinker() const { - switch (getTriple().getArch()) { - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - // BFD linker has issues wrt relocation of the protocol conformance - // section on these targets, it also generates COPY relocations for - // final executables, as such, unless specified, we default to gold - // linker. - return "gold"; - case llvm::Triple::x86_64: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - case llvm::Triple::systemz: - // BFD linker has issues wrt relocations against protected symbols. - return "gold"; - default: - // Otherwise, use the default BFD linker. - return ""; - } -} - -std::string toolchains::GenericUnix::getTargetForLinker() const { - return getTriple().str(); -} - -bool toolchains::GenericUnix::shouldProvideRPathToLinker() const { - return true; -} - -ToolChain::InvocationInfo -toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, - const JobContext &context) const { - assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && - "Invalid linker output type."); - - ArgStringList Arguments; - - switch (job.getKind()) { - case LinkKind::None: - llvm_unreachable("invalid link kind"); - case LinkKind::Executable: - // Default case, nothing extra needed. - break; - case LinkKind::DynamicLibrary: - Arguments.push_back("-shared"); - break; - } - - // Select the linker to use. - std::string Linker; - if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) { - Linker = A->getValue(); - } else { - Linker = getDefaultLinker(); - } - if (!Linker.empty()) { -#if defined(__HAIKU__) - // For now, passing -fuse-ld on Haiku doesn't work as swiftc doesn't recognise - // it. Passing -use-ld= as the argument works fine. - Arguments.push_back(context.Args.MakeArgString("-use-ld=" + Linker)); -#else - Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker)); -#endif - } - - // 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())); - } - - if (getTriple().getOS() == llvm::Triple::Linux && - job.getKind() == LinkKind::Executable) { - Arguments.push_back("-pie"); - } - - std::string Target = getTargetForLinker(); - if (!Target.empty()) { - Arguments.push_back("-target"); - Arguments.push_back(context.Args.MakeArgString(Target)); - } - - bool staticExecutable = false; - bool staticStdlib = false; - - if (context.Args.hasFlag(options::OPT_static_executable, - options::OPT_no_static_executable, - false)) { - staticExecutable = true; - } else if (context.Args.hasFlag(options::OPT_static_stdlib, - options::OPT_no_static_stdlib, - false)) { - staticStdlib = true; - } - - SmallString<128> SharedRuntimeLibPath; - getRuntimeLibraryPath(SharedRuntimeLibPath, context.Args, *this, /*Shared=*/ true); - - SmallString<128> StaticRuntimeLibPath; - getRuntimeLibraryPath(StaticRuntimeLibPath, context.Args, *this, /*Shared=*/ false); - - // Add the runtime library link path, which is platform-specific and found - // relative to the compiler. - if (!(staticExecutable || staticStdlib) && shouldProvideRPathToLinker()) { - // FIXME: We probably shouldn't be adding an rpath here unless we know - // ahead of time the standard library won't be copied. - Arguments.push_back("-Xlinker"); - Arguments.push_back("-rpath"); - Arguments.push_back("-Xlinker"); - Arguments.push_back(context.Args.MakeArgString(SharedRuntimeLibPath)); - } - - SmallString<128> swiftrtPath = SharedRuntimeLibPath; - llvm::sys::path::append(swiftrtPath, - swift::getMajorArchitectureName(getTriple())); - llvm::sys::path::append(swiftrtPath, "swiftrt.o"); - Arguments.push_back(context.Args.MakeArgString(swiftrtPath)); - - addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, - file_types::TY_Object); - addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); - - for (const Arg *arg : context.Args.filtered(options::OPT_F, - options::OPT_Fsystem)) { - if (arg->getOption().matches(options::OPT_Fsystem)) - Arguments.push_back("-iframework"); - else - Arguments.push_back(context.Args.MakeArgString(arg->getSpelling())); - Arguments.push_back(arg->getValue()); - } - - if (!context.OI.SDKPath.empty()) { - Arguments.push_back("--sysroot"); - Arguments.push_back(context.Args.MakeArgString(context.OI.SDKPath)); - } - - // Add any autolinking scripts to the arguments - for (const Job *Cmd : context.Inputs) { - auto &OutputInfo = Cmd->getOutput(); - if (OutputInfo.getPrimaryOutputType() == file_types::TY_AutolinkFile) - Arguments.push_back(context.Args.MakeArgString( - Twine("@") + OutputInfo.getPrimaryOutputFilename())); - } - - // Link the standard library. - Arguments.push_back("-L"); - - if (staticExecutable) { - Arguments.push_back(context.Args.MakeArgString(StaticRuntimeLibPath)); - - SmallString<128> linkFilePath = StaticRuntimeLibPath; - llvm::sys::path::append(linkFilePath, "static-executable-args.lnk"); - auto linkFile = linkFilePath.str(); - - if (llvm::sys::fs::is_regular_file(linkFile)) { - Arguments.push_back(context.Args.MakeArgString(Twine("@") + linkFile)); - } else { - llvm::report_fatal_error("-static-executable not supported on this platform"); - } - } - else if (staticStdlib) { - Arguments.push_back(context.Args.MakeArgString(StaticRuntimeLibPath)); - - SmallString<128> linkFilePath = StaticRuntimeLibPath; - llvm::sys::path::append(linkFilePath, "static-stdlib-args.lnk"); - auto linkFile = linkFilePath.str(); - if (llvm::sys::fs::is_regular_file(linkFile)) { - Arguments.push_back(context.Args.MakeArgString(Twine("@") + linkFile)); - } else { - llvm::report_fatal_error(linkFile + " not found"); - } - } - else { - Arguments.push_back(context.Args.MakeArgString(SharedRuntimeLibPath)); - Arguments.push_back("-lswiftCore"); - } - - // Explicitly pass the target to the linker - Arguments.push_back(context.Args.MakeArgString("--target=" + getTriple().str())); - - if (getTriple().getOS() == llvm::Triple::Linux) { - //Make sure we only add SanitizerLibs for executables - if (job.getKind() == LinkKind::Executable) { - if (context.OI.SelectedSanitizers & SanitizerKind::Address) - addLinkSanitizerLibArgsForLinux(context.Args, Arguments, "asan", *this); - - if (context.OI.SelectedSanitizers & SanitizerKind::Thread) - addLinkSanitizerLibArgsForLinux(context.Args, Arguments, "tsan", *this); - - if (context.OI.SelectedSanitizers & SanitizerKind::Fuzzer) - addLinkRuntimeLibForLinux(context.Args, Arguments, - getSanitizerRuntimeLibNameForLinux( - "fuzzer", this->getTriple()), *this); - } - } - - if (context.Args.hasArg(options::OPT_profile_generate)) { - SmallString<128> LibProfile(SharedRuntimeLibPath); - llvm::sys::path::remove_filename(LibProfile); // remove platform name - llvm::sys::path::append(LibProfile, "clang", "lib"); - - llvm::sys::path::append(LibProfile, getTriple().getOSName(), - Twine("libclang_rt.profile-") + - getTriple().getArchName() + - ".a"); - Arguments.push_back(context.Args.MakeArgString(LibProfile)); - Arguments.push_back(context.Args.MakeArgString( - Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); - } - - context.Args.AddAllArgs(Arguments, options::OPT_Xlinker); - context.Args.AddAllArgs(Arguments, options::OPT_linker_option_Group); - - // This should be the last option, for convenience in checking output. - Arguments.push_back("-o"); - Arguments.push_back(context.Args.MakeArgString( - context.Output.getPrimaryOutputFilename())); - - return {Clang, Arguments}; -} - -std::string -toolchains::Android::getTargetForLinker() const { - // Explicitly set the linker target to "androideabi", as opposed to the - // llvm::Triple representation of "armv7-none-linux-android". - // This is the only ABI we currently support for Android. - assert( - getTriple().getArch() == llvm::Triple::arm && - getTriple().getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v7 && - "Only armv7 targets are supported for Android"); - return "armv7-none-linux-androideabi"; -} - -bool toolchains::Android::shouldProvideRPathToLinker() const { - return false; -} - -std::string toolchains::Cygwin::getDefaultLinker() const { - // Cygwin uses the default BFD linker, even on ARM. - return ""; -} - -std::string toolchains::Cygwin::getTargetForLinker() const { - return ""; -} diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 34f0097132f37..0db33283c4090 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -33,10 +33,8 @@ class LLVM_LIBRARY_VISIBILITY Darwin : public ToolChain { public: Darwin(const Driver &D, const llvm::Triple &Triple) : ToolChain(D, Triple) {} ~Darwin() = default; - bool sanitizerRuntimeLibExists(const llvm::opt::ArgList &args, - StringRef sanitizerLibName, - bool shared) - const override; + std::string sanitizerRuntimeLibName(StringRef Sanitizer, + bool shared = true) const override; }; class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain { @@ -47,10 +45,8 @@ class LLVM_LIBRARY_VISIBILITY Windows : public ToolChain { public: Windows(const Driver &D, const llvm::Triple &Triple) : ToolChain(D, Triple) {} ~Windows() = default; - bool sanitizerRuntimeLibExists(const llvm::opt::ArgList &args, - StringRef sanitizerLibName, - bool shared) - const override; + std::string sanitizerRuntimeLibName(StringRef Sanitizer, + bool shared = true) const override; }; class LLVM_LIBRARY_VISIBILITY GenericUnix : public ToolChain { @@ -85,12 +81,11 @@ class LLVM_LIBRARY_VISIBILITY GenericUnix : public ToolChain { const JobContext &context) const override; public: - GenericUnix(const Driver &D, const llvm::Triple &Triple) : ToolChain(D, Triple) {} + GenericUnix(const Driver &D, const llvm::Triple &Triple) + : ToolChain(D, Triple) {} ~GenericUnix() = default; - bool sanitizerRuntimeLibExists(const llvm::opt::ArgList &args, - StringRef sanitizerLibName, - bool shared) - const override; + std::string sanitizerRuntimeLibName(StringRef Sanitizer, + bool shared = true) const override; }; class LLVM_LIBRARY_VISIBILITY Android : public GenericUnix { @@ -98,8 +93,10 @@ class LLVM_LIBRARY_VISIBILITY Android : public GenericUnix { std::string getTargetForLinker() const override; bool shouldProvideRPathToLinker() const override; + public: - Android(const Driver &D, const llvm::Triple &Triple) : GenericUnix(D, Triple) {} + Android(const Driver &D, const llvm::Triple &Triple) + : GenericUnix(D, Triple) {} ~Android() = default; }; @@ -110,7 +107,8 @@ class LLVM_LIBRARY_VISIBILITY Cygwin : public GenericUnix { std::string getTargetForLinker() const override; public: - Cygwin(const Driver &D, const llvm::Triple &Triple) : GenericUnix(D, Triple) {} + Cygwin(const Driver &D, const llvm::Triple &Triple) + : GenericUnix(D, Triple) {} ~Cygwin() = default; }; @@ -119,4 +117,3 @@ class LLVM_LIBRARY_VISIBILITY Cygwin : public GenericUnix { } // end namespace swift #endif - diff --git a/lib/Driver/UnixToolChains.cpp b/lib/Driver/UnixToolChains.cpp new file mode 100644 index 0000000000000..e738362f6b1c6 --- /dev/null +++ b/lib/Driver/UnixToolChains.cpp @@ -0,0 +1,348 @@ +//===------ UnixToolChains.cpp - Job invocations (non-Darwin Unix) --------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "ToolChains.h" + +#include "swift/Basic/Dwarf.h" +#include "swift/Basic/LLVM.h" +#include "swift/Basic/Platform.h" +#include "swift/Basic/Range.h" +#include "swift/Basic/TaskQueue.h" +#include "swift/Config.h" +#include "swift/Driver/Compilation.h" +#include "swift/Driver/Driver.h" +#include "swift/Driver/Job.h" +#include "swift/Frontend/Frontend.h" +#include "swift/Option/Options.h" +#include "clang/Basic/Version.h" +#include "clang/Driver/Util.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" + +using namespace swift; +using namespace swift::driver; +using namespace llvm::opt; + +static void addLinkSanitizerLibArgsForLinux(const ArgList &Args, + ArgStringList &Arguments, + StringRef Sanitizer, + const ToolChain &TC) { + TC.addLinkRuntimeLib(Args, Arguments, TC.sanitizerRuntimeLibName(Sanitizer)); + + // Code taken from + // https://github.com/apple/swift-clang/blob/ab3cbe7/lib/Driver/Tools.cpp#L3264-L3276 + // There's no libpthread or librt on RTEMS. + if (TC.getTriple().getOS() != llvm::Triple::RTEMS) { + Arguments.push_back("-lpthread"); + Arguments.push_back("-lrt"); + } + Arguments.push_back("-lm"); + + // There's no libdl on FreeBSD or RTEMS. + if (TC.getTriple().getOS() != llvm::Triple::FreeBSD && + TC.getTriple().getOS() != llvm::Triple::RTEMS) + Arguments.push_back("-ldl"); +} + +std::string +toolchains::GenericUnix::sanitizerRuntimeLibName(StringRef Sanitizer, + bool shared) const { + return (Twine("libclang_rt.") + Sanitizer + "-" + + this->getTriple().getArchName() + ".a") + .str(); +} + +ToolChain::InvocationInfo +toolchains::GenericUnix::constructInvocation(const InterpretJobAction &job, + const JobContext &context) const { + InvocationInfo II = ToolChain::constructInvocation(job, context); + + SmallString<128> runtimeLibraryPath; + getRuntimeLibraryPath(runtimeLibraryPath, context.Args, + /*Shared=*/true); + + addPathEnvironmentVariableIfNeeded(II.ExtraEnvironment, "LD_LIBRARY_PATH", + ":", options::OPT_L, context.Args, + runtimeLibraryPath); + return II; +} + +ToolChain::InvocationInfo toolchains::GenericUnix::constructInvocation( + const AutolinkExtractJobAction &job, const JobContext &context) const { + assert(context.Output.getPrimaryOutputType() == file_types::TY_AutolinkFile); + + ArgStringList Arguments; + addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, + file_types::TY_Object); + addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); + + Arguments.push_back("-o"); + Arguments.push_back( + context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); + + return {"swift-autolink-extract", Arguments}; +} + +std::string toolchains::GenericUnix::getDefaultLinker() const { + switch (getTriple().getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + // BFD linker has issues wrt relocation of the protocol conformance + // section on these targets, it also generates COPY relocations for + // final executables, as such, unless specified, we default to gold + // linker. + return "gold"; + case llvm::Triple::x86_64: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + case llvm::Triple::systemz: + // BFD linker has issues wrt relocations against protected symbols. + return "gold"; + default: + // Otherwise, use the default BFD linker. + return ""; + } +} + +std::string toolchains::GenericUnix::getTargetForLinker() const { + return getTriple().str(); +} + +bool toolchains::GenericUnix::shouldProvideRPathToLinker() const { + return true; +} + +ToolChain::InvocationInfo +toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, + const JobContext &context) const { + assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && + "Invalid linker output type."); + + ArgStringList Arguments; + + switch (job.getKind()) { + case LinkKind::None: + llvm_unreachable("invalid link kind"); + case LinkKind::Executable: + // Default case, nothing extra needed. + break; + case LinkKind::DynamicLibrary: + Arguments.push_back("-shared"); + break; + } + + // Select the linker to use. + std::string Linker; + if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) { + Linker = A->getValue(); + } else { + Linker = getDefaultLinker(); + } + if (!Linker.empty()) { +#if defined(__HAIKU__) + // For now, passing -fuse-ld on Haiku doesn't work as swiftc doesn't + // recognise it. Passing -use-ld= as the argument works fine. + Arguments.push_back(context.Args.MakeArgString("-use-ld=" + Linker)); +#else + Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker)); +#endif + } + + // 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())); + } + + if (getTriple().getOS() == llvm::Triple::Linux && + job.getKind() == LinkKind::Executable) { + Arguments.push_back("-pie"); + } + + std::string Target = getTargetForLinker(); + if (!Target.empty()) { + Arguments.push_back("-target"); + Arguments.push_back(context.Args.MakeArgString(Target)); + } + + bool staticExecutable = false; + bool staticStdlib = false; + + if (context.Args.hasFlag(options::OPT_static_executable, + options::OPT_no_static_executable, false)) { + staticExecutable = true; + } else if (context.Args.hasFlag(options::OPT_static_stdlib, + options::OPT_no_static_stdlib, false)) { + staticStdlib = true; + } + + SmallString<128> SharedRuntimeLibPath; + getRuntimeLibraryPath(SharedRuntimeLibPath, context.Args, /*Shared=*/true); + + SmallString<128> StaticRuntimeLibPath; + getRuntimeLibraryPath(StaticRuntimeLibPath, context.Args, /*Shared=*/false); + + // Add the runtime library link path, which is platform-specific and found + // relative to the compiler. + if (!(staticExecutable || staticStdlib) && shouldProvideRPathToLinker()) { + // FIXME: We probably shouldn't be adding an rpath here unless we know + // ahead of time the standard library won't be copied. + Arguments.push_back("-Xlinker"); + Arguments.push_back("-rpath"); + Arguments.push_back("-Xlinker"); + Arguments.push_back(context.Args.MakeArgString(SharedRuntimeLibPath)); + } + + SmallString<128> swiftrtPath = SharedRuntimeLibPath; + llvm::sys::path::append(swiftrtPath, + swift::getMajorArchitectureName(getTriple())); + llvm::sys::path::append(swiftrtPath, "swiftrt.o"); + Arguments.push_back(context.Args.MakeArgString(swiftrtPath)); + + addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, + file_types::TY_Object); + addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); + + for (const Arg *arg : + context.Args.filtered(options::OPT_F, options::OPT_Fsystem)) { + if (arg->getOption().matches(options::OPT_Fsystem)) + Arguments.push_back("-iframework"); + else + Arguments.push_back(context.Args.MakeArgString(arg->getSpelling())); + Arguments.push_back(arg->getValue()); + } + + if (!context.OI.SDKPath.empty()) { + Arguments.push_back("--sysroot"); + Arguments.push_back(context.Args.MakeArgString(context.OI.SDKPath)); + } + + // Add any autolinking scripts to the arguments + for (const Job *Cmd : context.Inputs) { + auto &OutputInfo = Cmd->getOutput(); + if (OutputInfo.getPrimaryOutputType() == file_types::TY_AutolinkFile) + Arguments.push_back(context.Args.MakeArgString( + Twine("@") + OutputInfo.getPrimaryOutputFilename())); + } + + // Link the standard library. + Arguments.push_back("-L"); + + if (staticExecutable) { + Arguments.push_back(context.Args.MakeArgString(StaticRuntimeLibPath)); + + SmallString<128> linkFilePath = StaticRuntimeLibPath; + llvm::sys::path::append(linkFilePath, "static-executable-args.lnk"); + auto linkFile = linkFilePath.str(); + + if (llvm::sys::fs::is_regular_file(linkFile)) { + Arguments.push_back(context.Args.MakeArgString(Twine("@") + linkFile)); + } else { + llvm::report_fatal_error( + "-static-executable not supported on this platform"); + } + } else if (staticStdlib) { + Arguments.push_back(context.Args.MakeArgString(StaticRuntimeLibPath)); + + SmallString<128> linkFilePath = StaticRuntimeLibPath; + llvm::sys::path::append(linkFilePath, "static-stdlib-args.lnk"); + auto linkFile = linkFilePath.str(); + if (llvm::sys::fs::is_regular_file(linkFile)) { + Arguments.push_back(context.Args.MakeArgString(Twine("@") + linkFile)); + } else { + llvm::report_fatal_error(linkFile + " not found"); + } + } else { + Arguments.push_back(context.Args.MakeArgString(SharedRuntimeLibPath)); + Arguments.push_back("-lswiftCore"); + } + + // Explicitly pass the target to the linker + Arguments.push_back( + context.Args.MakeArgString("--target=" + getTriple().str())); + + if (getTriple().getOS() == llvm::Triple::Linux) { + // Make sure we only add SanitizerLibs for executables + if (job.getKind() == LinkKind::Executable) { + if (context.OI.SelectedSanitizers & SanitizerKind::Address) + addLinkSanitizerLibArgsForLinux(context.Args, Arguments, "asan", *this); + + if (context.OI.SelectedSanitizers & SanitizerKind::Thread) + addLinkSanitizerLibArgsForLinux(context.Args, Arguments, "tsan", *this); + + if (context.OI.SelectedSanitizers & SanitizerKind::Fuzzer) + addLinkRuntimeLib(context.Args, Arguments, + sanitizerRuntimeLibName("fuzzer")); + } + } + + if (context.Args.hasArg(options::OPT_profile_generate)) { + SmallString<128> LibProfile(SharedRuntimeLibPath); + llvm::sys::path::remove_filename(LibProfile); // remove platform name + llvm::sys::path::append(LibProfile, "clang", "lib"); + + llvm::sys::path::append(LibProfile, getTriple().getOSName(), + Twine("libclang_rt.profile-") + + getTriple().getArchName() + ".a"); + Arguments.push_back(context.Args.MakeArgString(LibProfile)); + Arguments.push_back(context.Args.MakeArgString( + Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); + } + + context.Args.AddAllArgs(Arguments, options::OPT_Xlinker); + context.Args.AddAllArgs(Arguments, options::OPT_linker_option_Group); + + // This should be the last option, for convenience in checking output. + Arguments.push_back("-o"); + Arguments.push_back( + context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); + + return {Clang, Arguments}; +} + +std::string toolchains::Android::getTargetForLinker() const { + // Explicitly set the linker target to "androideabi", as opposed to the + // llvm::Triple representation of "armv7-none-linux-android". + // This is the only ABI we currently support for Android. + assert(getTriple().getArch() == llvm::Triple::arm && + getTriple().getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v7 && + "Only armv7 targets are supported for Android"); + return "armv7-none-linux-androideabi"; +} + +bool toolchains::Android::shouldProvideRPathToLinker() const { return false; } + +std::string toolchains::Cygwin::getDefaultLinker() const { + // Cygwin uses the default BFD linker, even on ARM. + return ""; +} + +std::string toolchains::Cygwin::getTargetForLinker() const { return ""; } diff --git a/lib/Driver/WindowsToolChains.cpp b/lib/Driver/WindowsToolChains.cpp new file mode 100644 index 0000000000000..8318d60969659 --- /dev/null +++ b/lib/Driver/WindowsToolChains.cpp @@ -0,0 +1,172 @@ +//===---- WindowsToolChains.cpp - Job invocations (Windows-specific) ------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "ToolChains.h" + +#include "swift/Basic/Dwarf.h" +#include "swift/Basic/LLVM.h" +#include "swift/Basic/Platform.h" +#include "swift/Basic/Range.h" +#include "swift/Basic/TaskQueue.h" +#include "swift/Config.h" +#include "swift/Driver/Compilation.h" +#include "swift/Driver/Driver.h" +#include "swift/Driver/Job.h" +#include "swift/Frontend/Frontend.h" +#include "swift/Option/Options.h" +#include "clang/Basic/Version.h" +#include "clang/Driver/Util.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" + +using namespace swift; +using namespace swift::driver; +using namespace llvm::opt; + +std::string toolchains::Windows::sanitizerRuntimeLibName(StringRef Sanitizer, + bool shared) const { + return (Twine("clang_rt.") + Sanitizer + "-" + + this->getTriple().getArchName() + ".lib") + .str(); +} + +ToolChain::InvocationInfo +toolchains::Windows::constructInvocation(const LinkJobAction &job, + const JobContext &context) const { + assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && + "Invalid linker output type."); + + ArgStringList Arguments; + + switch (job.getKind()) { + case LinkKind::None: + llvm_unreachable("invalid link kind"); + case LinkKind::Executable: + // Default case, nothing extra needed. + break; + case LinkKind::DynamicLibrary: + Arguments.push_back("-shared"); + break; + } + + // Select the linker to use. + std::string Linker; + if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) { + Linker = A->getValue(); + } + if (!Linker.empty()) + Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker)); + + // Configure the toolchain. + // By default, use the system clang++ to link. + const char *Clang = nullptr; + 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()); + } + if (Clang == nullptr) { + if (auto pathClang = llvm::sys::findProgramByName("clang++", None)) + Clang = context.Args.MakeArgString(pathClang.get()); + } + assert(Clang && + "clang++ was not found in the toolchain directory or system path."); + + std::string Target = getTriple().str(); + if (!Target.empty()) { + Arguments.push_back("-target"); + Arguments.push_back(context.Args.MakeArgString(Target)); + } + + SmallString<128> SharedRuntimeLibPath; + getRuntimeLibraryPath(SharedRuntimeLibPath, context.Args, + /*Shared=*/true); + + // Link the standard library. + Arguments.push_back("-L"); + if (context.Args.hasFlag(options::OPT_static_stdlib, + options::OPT_no_static_stdlib, false)) { + SmallString<128> StaticRuntimeLibPath; + getRuntimeLibraryPath(StaticRuntimeLibPath, context.Args, + /*Shared=*/false); + + // Since Windows has separate libraries per architecture, link against the + // architecture specific version of the static library. + Arguments.push_back(context.Args.MakeArgString(StaticRuntimeLibPath + "/" + + getTriple().getArchName())); + } else { + Arguments.push_back(context.Args.MakeArgString(SharedRuntimeLibPath + "/" + + getTriple().getArchName())); + } + + SmallString<128> swiftrtPath = SharedRuntimeLibPath; + llvm::sys::path::append(swiftrtPath, + swift::getMajorArchitectureName(getTriple())); + llvm::sys::path::append(swiftrtPath, "swiftrt.o"); + Arguments.push_back(context.Args.MakeArgString(swiftrtPath)); + + addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, + file_types::TY_Object); + addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); + + for (const Arg *arg : + context.Args.filtered(options::OPT_F, options::OPT_Fsystem)) { + if (arg->getOption().matches(options::OPT_Fsystem)) + Arguments.push_back("-iframework"); + else + Arguments.push_back(context.Args.MakeArgString(arg->getSpelling())); + Arguments.push_back(arg->getValue()); + } + + if (!context.OI.SDKPath.empty()) { + Arguments.push_back("-I"); + Arguments.push_back(context.Args.MakeArgString(context.OI.SDKPath)); + } + + if (job.getKind() == LinkKind::Executable) { + if (context.OI.SelectedSanitizers & SanitizerKind::Address) + addLinkRuntimeLib(context.Args, Arguments, + sanitizerRuntimeLibName("asan")); + } + + if (context.Args.hasArg(options::OPT_profile_generate)) { + SmallString<128> LibProfile(SharedRuntimeLibPath); + llvm::sys::path::remove_filename(LibProfile); // remove platform name + llvm::sys::path::append(LibProfile, "clang", "lib"); + + llvm::sys::path::append(LibProfile, getTriple().getOSName(), + Twine("clang_rt.profile-") + + getTriple().getArchName() + ".lib"); + Arguments.push_back(context.Args.MakeArgString(LibProfile)); + Arguments.push_back(context.Args.MakeArgString( + Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); + } + + context.Args.AddAllArgs(Arguments, options::OPT_Xlinker); + context.Args.AddAllArgs(Arguments, options::OPT_linker_option_Group); + + // This should be the last option, for convenience in checking output. + Arguments.push_back("-o"); + Arguments.push_back( + context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); + + return {Clang, Arguments}; +}