|  | //===--- Fuchsia.cpp - Fuchsia ToolChain Implementations --------*- C++ -*-===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "Fuchsia.h" | 
|  | #include "CommonArgs.h" | 
|  | #include "clang/Config/config.h" | 
|  | #include "clang/Driver/Compilation.h" | 
|  | #include "clang/Driver/Driver.h" | 
|  | #include "clang/Driver/DriverDiagnostic.h" | 
|  | #include "clang/Driver/Options.h" | 
|  | #include "llvm/Option/ArgList.h" | 
|  | #include "llvm/Support/Path.h" | 
|  |  | 
|  | using namespace clang::driver; | 
|  | using namespace clang::driver::toolchains; | 
|  | using namespace clang::driver::tools; | 
|  | using namespace clang; | 
|  | using namespace llvm::opt; | 
|  |  | 
|  | void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, | 
|  | const InputInfo &Output, | 
|  | const InputInfoList &Inputs, | 
|  | const ArgList &Args, | 
|  | const char *LinkingOutput) const { | 
|  | const toolchains::Fuchsia &ToolChain = | 
|  | static_cast<const toolchains::Fuchsia &>(getToolChain()); | 
|  | const Driver &D = ToolChain.getDriver(); | 
|  |  | 
|  | ArgStringList CmdArgs; | 
|  |  | 
|  | // Silence warning for "clang -g foo.o -o foo" | 
|  | Args.ClaimAllArgs(options::OPT_g_Group); | 
|  | // and "clang -emit-llvm foo.o -o foo" | 
|  | Args.ClaimAllArgs(options::OPT_emit_llvm); | 
|  | // and for "clang -w foo.o -o foo". Other warning options are already | 
|  | // handled somewhere else. | 
|  | Args.ClaimAllArgs(options::OPT_w); | 
|  |  | 
|  | const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); | 
|  | if (llvm::sys::path::stem(Exec).equals_lower("lld")) { | 
|  | CmdArgs.push_back("-flavor"); | 
|  | CmdArgs.push_back("gnu"); | 
|  |  | 
|  | CmdArgs.push_back("-z"); | 
|  | CmdArgs.push_back("rodynamic"); | 
|  | } | 
|  |  | 
|  | if (!D.SysRoot.empty()) | 
|  | CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); | 
|  |  | 
|  | if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r)) | 
|  | CmdArgs.push_back("-pie"); | 
|  |  | 
|  | if (Args.hasArg(options::OPT_rdynamic)) | 
|  | CmdArgs.push_back("-export-dynamic"); | 
|  |  | 
|  | if (Args.hasArg(options::OPT_s)) | 
|  | CmdArgs.push_back("-s"); | 
|  |  | 
|  | if (Args.hasArg(options::OPT_r)) | 
|  | CmdArgs.push_back("-r"); | 
|  | else | 
|  | CmdArgs.push_back("--build-id"); | 
|  |  | 
|  | if (!Args.hasArg(options::OPT_static)) | 
|  | CmdArgs.push_back("--eh-frame-hdr"); | 
|  |  | 
|  | if (Args.hasArg(options::OPT_static)) | 
|  | CmdArgs.push_back("-Bstatic"); | 
|  | else if (Args.hasArg(options::OPT_shared)) | 
|  | CmdArgs.push_back("-shared"); | 
|  |  | 
|  | if (!Args.hasArg(options::OPT_static)) { | 
|  | if (Args.hasArg(options::OPT_rdynamic)) | 
|  | CmdArgs.push_back("-export-dynamic"); | 
|  |  | 
|  | if (!Args.hasArg(options::OPT_shared)) { | 
|  | CmdArgs.push_back("-dynamic-linker"); | 
|  | CmdArgs.push_back(Args.MakeArgString(D.DyldPrefix + "ld.so.1")); | 
|  | } | 
|  | } | 
|  |  | 
|  | CmdArgs.push_back("-o"); | 
|  | CmdArgs.push_back(Output.getFilename()); | 
|  |  | 
|  | if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { | 
|  | if (!Args.hasArg(options::OPT_shared)) { | 
|  | CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o"))); | 
|  | } | 
|  | } | 
|  |  | 
|  | Args.AddAllArgs(CmdArgs, options::OPT_L); | 
|  | Args.AddAllArgs(CmdArgs, options::OPT_u); | 
|  |  | 
|  | ToolChain.AddFilePathLibArgs(Args, CmdArgs); | 
|  |  | 
|  | AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); | 
|  |  | 
|  | if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { | 
|  | if (Args.hasArg(options::OPT_static)) | 
|  | CmdArgs.push_back("-Bdynamic"); | 
|  |  | 
|  | if (D.CCCIsCXX()) { | 
|  | if (ToolChain.ShouldLinkCXXStdlib(Args)) | 
|  | ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); | 
|  | CmdArgs.push_back("-lm"); | 
|  | } | 
|  |  | 
|  | AddRunTimeLibs(ToolChain, D, CmdArgs, Args); | 
|  |  | 
|  | if (Args.hasArg(options::OPT_pthread) || | 
|  | Args.hasArg(options::OPT_pthreads)) | 
|  | CmdArgs.push_back("-lpthread"); | 
|  |  | 
|  | if (Args.hasArg(options::OPT_fsplit_stack)) | 
|  | CmdArgs.push_back("--wrap=pthread_create"); | 
|  |  | 
|  | CmdArgs.push_back("-lc"); | 
|  | } | 
|  |  | 
|  | C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); | 
|  | } | 
|  |  | 
|  | /// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly. | 
|  |  | 
|  | static std::string normalizeTriple(llvm::Triple Triple) { | 
|  | SmallString<64> T; | 
|  | T += Triple.getArchName(); | 
|  | T += "-"; | 
|  | T += Triple.getOSName(); | 
|  | return T.str(); | 
|  | } | 
|  |  | 
|  | static std::string getTargetDir(const Driver &D, | 
|  | llvm::Triple Triple) { | 
|  | SmallString<128> P(llvm::sys::path::parent_path(D.Dir)); | 
|  | llvm::sys::path::append(P, "lib", normalizeTriple(Triple)); | 
|  | return P.str(); | 
|  | } | 
|  |  | 
|  | Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, | 
|  | const ArgList &Args) | 
|  | : ToolChain(D, Triple, Args) { | 
|  | getProgramPaths().push_back(getDriver().getInstalledDir()); | 
|  | if (getDriver().getInstalledDir() != D.Dir) | 
|  | getProgramPaths().push_back(D.Dir); | 
|  |  | 
|  | SmallString<128> P(getTargetDir(D, getTriple())); | 
|  | llvm::sys::path::append(P, "lib"); | 
|  | getFilePaths().push_back(P.str()); | 
|  |  | 
|  | if (!D.SysRoot.empty()) { | 
|  | SmallString<128> P(D.SysRoot); | 
|  | llvm::sys::path::append(P, "lib"); | 
|  | getFilePaths().push_back(P.str()); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args, | 
|  | types::ID InputType) const { | 
|  | llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); | 
|  | Triple.setTriple(normalizeTriple(Triple)); | 
|  | return Triple.getTriple(); | 
|  | } | 
|  |  | 
|  | Tool *Fuchsia::buildLinker() const { | 
|  | return new tools::fuchsia::Linker(*this); | 
|  | } | 
|  |  | 
|  | ToolChain::RuntimeLibType Fuchsia::GetRuntimeLibType( | 
|  | const ArgList &Args) const { | 
|  | if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) { | 
|  | StringRef Value = A->getValue(); | 
|  | if (Value != "compiler-rt") | 
|  | getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name) | 
|  | << A->getAsString(Args); | 
|  | } | 
|  |  | 
|  | return ToolChain::RLT_CompilerRT; | 
|  | } | 
|  |  | 
|  | ToolChain::CXXStdlibType | 
|  | Fuchsia::GetCXXStdlibType(const ArgList &Args) const { | 
|  | if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { | 
|  | StringRef Value = A->getValue(); | 
|  | if (Value != "libc++") | 
|  | getDriver().Diag(diag::err_drv_invalid_stdlib_name) | 
|  | << A->getAsString(Args); | 
|  | } | 
|  |  | 
|  | return ToolChain::CST_Libcxx; | 
|  | } | 
|  |  | 
|  | void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs, | 
|  | ArgStringList &CC1Args, | 
|  | Action::OffloadKind) const { | 
|  | if (DriverArgs.hasFlag(options::OPT_fuse_init_array, | 
|  | options::OPT_fno_use_init_array, true)) | 
|  | CC1Args.push_back("-fuse-init-array"); | 
|  | } | 
|  |  | 
|  | void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs, | 
|  | ArgStringList &CC1Args) const { | 
|  | const Driver &D = getDriver(); | 
|  |  | 
|  | if (DriverArgs.hasArg(options::OPT_nostdinc)) | 
|  | return; | 
|  |  | 
|  | if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { | 
|  | SmallString<128> P(D.ResourceDir); | 
|  | llvm::sys::path::append(P, "include"); | 
|  | addSystemInclude(DriverArgs, CC1Args, P); | 
|  | } | 
|  |  | 
|  | if (DriverArgs.hasArg(options::OPT_nostdlibinc)) | 
|  | return; | 
|  |  | 
|  | // Check for configure-time C include directories. | 
|  | StringRef CIncludeDirs(C_INCLUDE_DIRS); | 
|  | if (CIncludeDirs != "") { | 
|  | SmallVector<StringRef, 5> dirs; | 
|  | CIncludeDirs.split(dirs, ":"); | 
|  | for (StringRef dir : dirs) { | 
|  | StringRef Prefix = | 
|  | llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; | 
|  | addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); | 
|  | } | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!D.SysRoot.empty()) { | 
|  | SmallString<128> P(D.SysRoot); | 
|  | llvm::sys::path::append(P, "include"); | 
|  | addExternCSystemInclude(DriverArgs, CC1Args, P.str()); | 
|  | } | 
|  | } | 
|  |  | 
|  | void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, | 
|  | ArgStringList &CC1Args) const { | 
|  | if (DriverArgs.hasArg(options::OPT_nostdlibinc) || | 
|  | DriverArgs.hasArg(options::OPT_nostdincxx)) | 
|  | return; | 
|  |  | 
|  | switch (GetCXXStdlibType(DriverArgs)) { | 
|  | case ToolChain::CST_Libcxx: { | 
|  | SmallString<128> P(getTargetDir(getDriver(), getTriple())); | 
|  | llvm::sys::path::append(P, "include", "c++", "v1"); | 
|  | addSystemInclude(DriverArgs, CC1Args, P.str()); | 
|  | break; | 
|  | } | 
|  |  | 
|  | default: | 
|  | llvm_unreachable("invalid stdlib name"); | 
|  | } | 
|  | } | 
|  |  | 
|  | void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args, | 
|  | ArgStringList &CmdArgs) const { | 
|  | switch (GetCXXStdlibType(Args)) { | 
|  | case ToolChain::CST_Libcxx: | 
|  | CmdArgs.push_back("-lc++"); | 
|  | CmdArgs.push_back("-lc++abi"); | 
|  | CmdArgs.push_back("-lunwind"); | 
|  | break; | 
|  |  | 
|  | case ToolChain::CST_Libstdcxx: | 
|  | llvm_unreachable("invalid stdlib name"); | 
|  | } | 
|  | } | 
|  |  | 
|  | SanitizerMask Fuchsia::getSupportedSanitizers() const { | 
|  | SanitizerMask Res = ToolChain::getSupportedSanitizers(); | 
|  | Res |= SanitizerKind::SafeStack; | 
|  | return Res; | 
|  | } |