//===---- 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/Assertions.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/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; using namespace swift::driver::toolchains; 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 DynamicLinkJobAction &job, const JobContext &context) const { assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && "Invalid linker output type."); ArgStringList Arguments; std::string Target = getTriple().str(); if (!Target.empty()) { Arguments.push_back("-target"); Arguments.push_back(context.Args.MakeArgString(Target)); } 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; case LinkKind::StaticLibrary: llvm_unreachable("invalid link kind"); } // Check to see whether we need to use lld as the linker. auto requiresLLD = [&]{ if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) { return llvm::StringSwitch(A->getValue()) .Cases({"lld", "lld.exe", "lld-link", "lld-link.exe"}, true) .Default(false); } // Force to use lld for LTO on Windows because we don't support link LTO or // something else except for lld LTO at this time. if (context.OI.LTOVariant != OutputInfo::LTOKind::None) { return true; } // Profiling currently relies on the ability to emit duplicate weak // symbols across translation units and having the linker coalesce them. // Unfortunately link.exe does not support this, so require lld-link // for now, which supports the behavior via a flag. // TODO: Once we've changed coverage to no longer rely on emitting // duplicate weak symbols (rdar://131295678), we can remove this. if (swift::driver::toolchains::needsInstrProfileRuntime(context.Args)) { return true; } return false; }(); // Select the linker to use. std::string Linker; if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) { Linker = A->getValue(); } else if (requiresLLD) { Linker = "lld"; } switch (context.OI.LTOVariant) { case OutputInfo::LTOKind::LLVMThin: Arguments.push_back("-flto=thin"); break; case OutputInfo::LTOKind::LLVMFull: Arguments.push_back("-flto=full"); break; case OutputInfo::LTOKind::None: break; } if (!Linker.empty()) Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker)); if (context.OI.DebugInfoFormat == IRGenDebugInfoFormat::CodeView) { Arguments.push_back("-Xlinker"); Arguments.push_back("/DEBUG"); } // Rely on `-libc` to correctly identify the MSVC Runtime Library. We use // `-nostartfiles` as that limits the difference to just the // `-defaultlib:libcmt` which is passed unconditionally with the `clang` // driver rather than the `clang-cl` driver. Arguments.push_back("-nostartfiles"); bool wantsStaticStdlib = context.Args.hasFlag(options::OPT_static_stdlib, options::OPT_no_static_stdlib, false); SmallVector RuntimeLibPaths; getRuntimeLibraryPaths(RuntimeLibPaths, context.Args, context.OI.SDKPath, /*Shared=*/!wantsStaticStdlib); for (auto path : RuntimeLibPaths) { Arguments.push_back("-L"); // Since Windows has separate libraries per architecture, link against the // architecture specific version of the static library. Arguments.push_back(context.Args.MakeArgString(path + "/" + getTriple().getArchName())); } if (!context.Args.hasArg(options::OPT_nostartfiles)) { SmallString<128> SharedResourceDirPath; getResourceDirPath(SharedResourceDirPath, context.Args, /*Shared=*/true); SmallString<128> swiftrtPath = SharedResourceDirPath; llvm::sys::path::append(swiftrtPath, swift::getMajorArchitectureName(getTriple())); llvm::sys::path::append(swiftrtPath, "swiftrt.obj"); Arguments.push_back(context.Args.MakeArgString(swiftrtPath)); } addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, file_types::TY_Object); addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, file_types::TY_LLVM_BC); addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); addInputsOfType(Arguments, context.InputActions, file_types::TY_LLVM_BC); 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.OI.SelectedSanitizers & SanitizerKind::Undefined) addLinkRuntimeLib(context.Args, Arguments, sanitizerRuntimeLibName("ubsan")); } if (needsInstrProfileRuntime(context.Args)) { Arguments.push_back(context.Args.MakeArgString("-Xlinker")); Arguments.push_back(context.Args.MakeArgString( Twine({"-include:", llvm::getInstrProfRuntimeHookVarName()}))); Arguments.push_back(context.Args.MakeArgString("-lclang_rt.profile")); // FIXME(rdar://131295678): Currently profiling requires the ability to // emit duplicate weak symbols. Assuming we're using lld, pass // -lld-allow-duplicate-weak to enable this behavior. if (requiresLLD) { Arguments.push_back("-Xlinker"); Arguments.push_back("-lld-allow-duplicate-weak"); } } context.Args.AddAllArgs(Arguments, options::OPT_Xlinker); context.Args.AddAllArgsExcept(Arguments, {options::OPT_linker_option_Group}, {options::OPT_l}); ToolChain::addLinkedLibArgs(context.Args, Arguments); context.Args.AddAllArgValues(Arguments, options::OPT_Xclang_linker); // Run clang in verbose mode if "-v" is set if (context.Args.hasArg(options::OPT_v)) { Arguments.push_back("-v"); } // This should be the last option, for convenience in checking output. Arguments.push_back("-o"); Arguments.push_back( context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); InvocationInfo II{getClangLinkerDriver(context.Args), Arguments}; II.allowsResponseFiles = true; return II; } ToolChain::InvocationInfo toolchains::Windows::constructInvocation(const StaticLinkJobAction &job, const JobContext &context) const { assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && "Invalid linker output type."); ArgStringList Arguments; const char *Linker = "link"; if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) Linker = context.Args.MakeArgString(A->getValue()); Arguments.push_back("/lib"); Arguments.push_back("-nologo"); addPrimaryInputsOfType(Arguments, context.Inputs, context.Args, file_types::TY_Object); addInputsOfType(Arguments, context.InputActions, file_types::TY_Object); StringRef OutputFile = context.Output.getPrimaryOutputFilename(); Arguments.push_back(context.Args.MakeArgString(Twine("/OUT:") + OutputFile)); InvocationInfo II{Linker, Arguments}; II.allowsResponseFiles = true; return II; }