| //===---- 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/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 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"); |
| } |
| |
| // Select the linker to use. |
| std::string Linker; |
| if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) { |
| Linker = A->getValue(); |
| } |
| |
| 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() && context.OI.LTOVariant != OutputInfo::LTOKind::None) { |
| // 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. |
| Linker = "lld"; |
| } |
| |
| 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<std::string, 4> 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())); |
| } |
| |
| 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)); |
| } |
| |
| // Link against the desired C++ standard library. |
| if (const Arg *A = |
| context.Args.getLastArg(options::OPT_experimental_cxx_stdlib)) { |
| Arguments.push_back(context.Args.MakeArgString( |
| Twine("-stdlib=") + A->getValue())); |
| } |
| |
| 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 (context.Args.hasArg(options::OPT_profile_generate)) { |
| SmallString<128> LibProfile(SharedResourceDirPath); |
| 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); |
| 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; |
| } |