diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp index 0b30ccfac9bc2..8f8f9ca4f0bb5 100644 --- a/lib/Basic/LangOptions.cpp +++ b/lib/Basic/LangOptions.cpp @@ -292,6 +292,12 @@ std::pair LangOptions::setTarget(llvm::Triple triple) { case llvm::Triple::WASI: addPlatformConditionValue(PlatformConditionKind::OS, "WASI"); break; + case llvm::Triple::UnknownOS: + if (Target.getOSName() == "none") { + addPlatformConditionValue(PlatformConditionKind::OS, "none"); + break; + } + LLVM_FALLTHROUGH; default: UnsupportedOS = true; break; diff --git a/lib/Basic/Platform.cpp b/lib/Basic/Platform.cpp index a10d52099212e..bf513071282de 100644 --- a/lib/Basic/Platform.cpp +++ b/lib/Basic/Platform.cpp @@ -175,8 +175,6 @@ static StringRef getPlatformNameForDarwin(const DarwinPlatformKind platform) { StringRef swift::getPlatformNameForTriple(const llvm::Triple &triple) { switch (triple.getOS()) { - case llvm::Triple::UnknownOS: - llvm_unreachable("unknown OS"); case llvm::Triple::ZOS: case llvm::Triple::Ananas: case llvm::Triple::CloudABI: @@ -231,6 +229,8 @@ StringRef swift::getPlatformNameForTriple(const llvm::Triple &triple) { return "haiku"; case llvm::Triple::WASI: return "wasi"; + case llvm::Triple::UnknownOS: + return "none"; } llvm_unreachable("unsupported OS"); } diff --git a/lib/Driver/BareMetalToolchains.cpp b/lib/Driver/BareMetalToolchains.cpp new file mode 100644 index 0000000000000..95e7eed168189 --- /dev/null +++ b/lib/Driver/BareMetalToolchains.cpp @@ -0,0 +1,410 @@ +//===--- BareMetalToolChains.cpp - Job invocations (bare metal triples) ---===// +// +// 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 "swift/Option/SanitizerOptions.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::BareMetal::sanitizerRuntimeLibName(StringRef Sanitizer, + bool shared) const { + return (Twine("libclang_rt.") + Sanitizer + "-" + + this->getTriple().getArchName() + + (this->getTriple().isAndroid() ? "-android" : "") + ".a") + .str(); +} + +ToolChain::InvocationInfo +toolchains::BareMetal::constructInvocation(const InterpretJobAction &job, + const JobContext &context) const { + InvocationInfo II = ToolChain::constructInvocation(job, context); + + SmallVector runtimeLibraryPaths; + getRuntimeLibraryPaths(runtimeLibraryPaths, context.Args, context.OI.SDKPath, + /*Shared=*/true); + + addPathEnvironmentVariableIfNeeded(II.ExtraEnvironment, "LD_LIBRARY_PATH", + ":", options::OPT_L, context.Args, + runtimeLibraryPaths); + return II; +} + +ToolChain::InvocationInfo toolchains::BareMetal::constructInvocation( + const AutolinkExtractJobAction &job, const JobContext &context) const { + assert(context.Output.getPrimaryOutputType() == file_types::TY_AutolinkFile); + + InvocationInfo II{"swift-autolink-extract"}; + ArgStringList &Arguments = II.Arguments; + II.allowsResponseFiles = true; + + 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); + + Arguments.push_back("-o"); + Arguments.push_back( + context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); + + return II; +} + +std::string toolchains::BareMetal::getDefaultLinker() const { + if (getTriple().isAndroid()) + return "lld"; + + switch (getTriple().getArch()) { + case llvm::Triple::arm: + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: + 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: + 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 ""; + } +} + +bool toolchains::BareMetal::addRuntimeRPath(const llvm::Triple &T, + const llvm::opt::ArgList &Args) const { + // If we are building a static executable, do not add a rpath for the runtime + // as it is a static binary and the loader will not be invoked. + if (Args.hasFlag(options::OPT_static_executable, + options::OPT_no_static_executable, false)) + return false; + + // If we are building with a static standard library, do not add a rpath for + // the runtime because the runtime will be part of the binary and the rpath is + // no longer necessary. + if (Args.hasFlag(options::OPT_static_stdlib, options::OPT_no_static_stdlib, + false)) + return false; + + // FIXME: We probably shouldn't be adding an rpath here unless we know ahead + // of time the standard library won't be copied. + + // Honour the user's request to add a rpath to the binary. This defaults to + // `true` on non-android and `false` on android since the library must be + // copied into the bundle. + return Args.hasFlag(options::OPT_toolchain_stdlib_rpath, + options::OPT_no_toolchain_stdlib_rpath, + !T.isAndroid()); +} + +ToolChain::InvocationInfo +toolchains::BareMetal::constructInvocation(const DynamicLinkJobAction &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; + case LinkKind::StaticLibrary: + llvm_unreachable("the dynamic linker cannot build static libraries"); + } + + // Select the linker to use. + std::string Linker; + if (context.OI.LTOVariant != OutputInfo::LTOKind::None) { + // Force to use lld for LTO on Unix-like platform (not including Darwin) + // because we don't support gold LTO or something else except for lld LTO + // at this time. + Linker = "lld"; + } + + if (const Arg *A = context.Args.getLastArg(options::OPT_use_ld)) { + Linker = A->getValue(); + } + + if (Linker.empty()) { + 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. + if (const Arg *A = context.Args.getLastArg(options::OPT_tools_directory)) { + StringRef toolchainPath(A->getValue()); + + // Look for binutils in the toolchain folder. + Arguments.push_back("-B"); + Arguments.push_back(context.Args.MakeArgString(A->getValue())); + } + + if (getTriple().getObjectFormat() == llvm::Triple::ELF && + job.getKind() == LinkKind::Executable && + !context.Args.hasFlag(options::OPT_static_executable, + options::OPT_no_static_executable, false)) { + Arguments.push_back("-pie"); + } + + 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; + } + + 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; + } + + SmallVector RuntimeLibPaths; + getRuntimeLibraryPaths(RuntimeLibPaths, context.Args, context.OI.SDKPath, + /*Shared=*/!(staticExecutable || staticStdlib)); + + if (addRuntimeRPath(getTriple(), context.Args)) { + for (auto path : RuntimeLibPaths) { + Arguments.push_back("-Xlinker"); + Arguments.push_back("-rpath"); + Arguments.push_back("-Xlinker"); + Arguments.push_back(context.Args.MakeArgString(path)); + } + } + + SmallString<128> SharedResourceDirPath; + getResourceDirPath(SharedResourceDirPath, context.Args, /*Shared=*/true); + + SmallString<128> swiftrtPath = SharedResourceDirPath; + llvm::sys::path::append(swiftrtPath, + swift::getMajorArchitectureName(getTriple())); + 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("--sysroot"); + Arguments.push_back(context.Args.MakeArgString(context.OI.SDKPath)); + } + + // If we are linking statically, we need to add all + // dependencies to a library search group to resolve + // potential circular dependencies + if (staticExecutable || staticStdlib) { + Arguments.push_back("-Xlinker"); + Arguments.push_back("--start-group"); + } + + // 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())); + } + + if (staticExecutable || staticStdlib) { + Arguments.push_back("-Xlinker"); + Arguments.push_back("--end-group"); + } + + // Add the runtime library link paths. + for (auto path : RuntimeLibPaths) { + Arguments.push_back("-L"); + Arguments.push_back(context.Args.MakeArgString(path)); + } + + // Link the standard library. In two paths, we do this using a .lnk file; + // if we're going that route, we'll set `linkFilePath` to the path to that + // file. + SmallString<128> linkFilePath; + getResourceDirPath(linkFilePath, context.Args, /*Shared=*/false); + + if (staticExecutable) { + llvm::sys::path::append(linkFilePath, "static-executable-args.lnk"); + } else if (staticStdlib) { + llvm::sys::path::append(linkFilePath, "static-stdlib-args.lnk"); + } else { + linkFilePath.clear(); + Arguments.push_back("-lswiftCore"); + } + + if (!linkFilePath.empty()) { + if (llvm::sys::fs::is_regular_file(linkFilePath)) { + Arguments.push_back( + context.Args.MakeArgString(Twine("@") + linkFilePath)); + } else { + llvm::report_fatal_error(Twine(linkFilePath) + " not found"); + } + } + + // 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())); + } + + // Explicitly pass the target to the linker + Arguments.push_back( + context.Args.MakeArgString("--target=" + getTriple().str())); + + // Delegate to Clang for sanitizers. It will figure out the correct linker + // options. + if (job.getKind() == LinkKind::Executable && context.OI.SelectedSanitizers) { + Arguments.push_back(context.Args.MakeArgString( + "-fsanitize=" + getSanitizerList(context.OI.SelectedSanitizers))); + + // The TSan runtime depends on the blocks runtime and libdispatch. + if (context.OI.SelectedSanitizers & SanitizerKind::Thread) { + Arguments.push_back("-lBlocksRuntime"); + Arguments.push_back("-ldispatch"); + } + } + + 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("libclang_rt.profile-") + + getTriple().getArchName() + ".a"); + Arguments.push_back(context.Args.MakeArgString(LibProfile)); + Arguments.push_back(context.Args.MakeArgString( + Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); + } + + // Run clang in verbose mode if "-v" is set + if (context.Args.hasArg(options::OPT_v)) { + Arguments.push_back("-v"); + } + + // These custom arguments should be right before the object file at the end. + context.Args.AddAllArgsExcept(Arguments, {options::OPT_linker_option_Group}, + {options::OPT_l}); + ToolChain::addLinkedLibArgs(context.Args, Arguments); + context.Args.AddAllArgs(Arguments, options::OPT_Xlinker); + context.Args.AddAllArgValues(Arguments, options::OPT_Xclang_linker); + + // 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::BareMetal::constructInvocation(const StaticLinkJobAction &job, + const JobContext &context) const { + assert(context.Output.getPrimaryOutputType() == file_types::TY_Image && + "Invalid linker output type."); + + ArgStringList Arguments; + + const char *AR; + // Configure the toolchain. + if (getTriple().isAndroid()) + AR = "llvm-ar"; + else + AR = context.OI.LTOVariant != OutputInfo::LTOKind::None ? "llvm-ar" : "ar"; + Arguments.push_back("crs"); + + Arguments.push_back( + context.Args.MakeArgString(context.Output.getPrimaryOutputFilename())); + + 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); + + InvocationInfo II{AR, Arguments}; + + return II; +} diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index 389534745fcbc..df93f0fd8c8c0 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -2,6 +2,7 @@ set(swiftDriver_sources Action.cpp + BareMetalToolchains.cpp Compilation.cpp DarwinToolChains.cpp Driver.cpp diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 8397d62a446c6..604682d53bcf1 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -369,6 +369,8 @@ Driver::buildToolChain(const llvm::opt::InputArgList &ArgList) { return std::make_unique(*this, target); case llvm::Triple::WASI: return std::make_unique(*this, target); + case llvm::Triple::UnknownOS: + return std::make_unique(*this, target); default: Diags.diagnose(SourceLoc(), diag::error_unknown_target, ArgList.getLastArg(options::OPT_target)->getValue()); diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index cdc4fe92e3166..35224be5f5732 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -133,6 +133,38 @@ class LLVM_LIBRARY_VISIBILITY WebAssembly : public ToolChain { bool shared = true) const override; }; +class LLVM_LIBRARY_VISIBILITY BareMetal : public ToolChain { +protected: + InvocationInfo constructInvocation(const InterpretJobAction &job, + const JobContext &context) const override; + InvocationInfo constructInvocation(const AutolinkExtractJobAction &job, + const JobContext &context) const override; + + /// If provided, and if the user has not already explicitly specified a + /// linker to use via the "-fuse-ld=" option, this linker will be passed to + /// the compiler invocation via "-fuse-ld=". Return an empty string to not + /// specify any specific linker (the "-fuse-ld=" option will not be + /// specified). + /// + /// The default behavior is to use the gold linker on ARM architectures, + /// and to not provide a specific linker otherwise. + virtual std::string getDefaultLinker() const; + + bool addRuntimeRPath(const llvm::Triple &T, + const llvm::opt::ArgList &Args) const; + + InvocationInfo constructInvocation(const DynamicLinkJobAction &job, + const JobContext &context) const override; + InvocationInfo constructInvocation(const StaticLinkJobAction &job, + const JobContext &context) const override; + +public: + BareMetal(const Driver &D, const llvm::Triple &Triple) + : ToolChain(D, Triple) {} + ~BareMetal() = default; + std::string sanitizerRuntimeLibName(StringRef Sanitizer, + bool shared = true) const override; +}; class LLVM_LIBRARY_VISIBILITY GenericUnix : public ToolChain { protected: diff --git a/test/Driver/baremetal-target.swift b/test/Driver/baremetal-target.swift new file mode 100644 index 0000000000000..25f292954a1c4 --- /dev/null +++ b/test/Driver/baremetal-target.swift @@ -0,0 +1,4 @@ +// RUN: %swiftc_driver_plain -target aarch64-unknwon-none-none -driver-print-jobs %s 2>&1 | %FileCheck %s + +// CHECK: {{.*}}swift{{c|-frontend}}{{(.exe)?"?}} -frontend -c +// CHECK: {{.*}}clang{{(.exe)?"?}} -fuse-ld=gold diff --git a/test/Driver/options.swift b/test/Driver/options.swift index 130eb959bf901..1a112fde920c1 100644 --- a/test/Driver/options.swift +++ b/test/Driver/options.swift @@ -80,8 +80,8 @@ // RUN: %swift_driver -g -### %s 2>&1 | %FileCheck -check-prefix=OPTIONS_BEFORE_FILE %s // OPTIONS_BEFORE_FILE: -g -// RUN: not %swift_driver -target abc -### %s 2>&1 | %FileCheck -check-prefix=BAD_TARGET %s -// BAD_TARGET: error: unknown target 'abc' +// RUN: not %swift_driver -target m68k-unknown-windows-msvc -### %s 2>&1 | %FileCheck -check-prefix=BAD_TARGET %s +// BAD_TARGET: error: unknown target 'm68k-unknown-windows-msvc' // RUN: %swiftc_driver -incremental %s -### 2>&1 | %FileCheck -check-prefix=INCREMENTAL_WITHOUT_OFM %s // INCREMENTAL_WITHOUT_OFM: warning: ignoring -incremental (currently requires an output file map)