Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -823,6 +823,28 @@ } }; +// Fuchsia Target +template +class FuchsiaTargetInfo : public OSTargetInfo { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + Builder.defineMacro("__Fuchsia__"); + Builder.defineMacro("__ELF__"); + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + // Required by the libc++ locale support. + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + } +public: + FuchsiaTargetInfo(const llvm::Triple &Triple, + const TargetOptions &Opts) + : OSTargetInfo(Triple, Opts) { + this->MCountName = "__mcount"; + } +}; + // WebAssembly target template class WebAssemblyOSTargetInfo : public OSTargetInfo { @@ -8263,6 +8285,8 @@ return new LinuxTargetInfo(Triple, Opts); case llvm::Triple::NetBSD: return new NetBSDTargetInfo(Triple, Opts); + case llvm::Triple::Fuchsia: + return new FuchsiaTargetInfo(Triple, Opts); default: return new AArch64leTargetInfo(Triple, Opts); } @@ -8631,6 +8655,8 @@ return new HaikuTargetInfo(Triple, Opts); case llvm::Triple::NaCl: return new NaClTargetInfo(Triple, Opts); + case llvm::Triple::Fuchsia: + return new FuchsiaTargetInfo(Triple, Opts); case llvm::Triple::PS4: return new PS4OSTargetInfo(Triple, Opts); default: Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ lib/Driver/Driver.cpp @@ -3077,6 +3077,9 @@ case llvm::Triple::NaCl: TC = new toolchains::NaClToolChain(*this, Target, Args); break; + case llvm::Triple::Fuchsia: + TC = new toolchains::Fuchsia(*this, Target, Args); + break; case llvm::Triple::Solaris: TC = new toolchains::Solaris(*this, Target, Args); break; Index: lib/Driver/ToolChains.h =================================================================== --- lib/Driver/ToolChains.h +++ lib/Driver/ToolChains.h @@ -1008,6 +1008,39 @@ std::string NaClArmMacrosPath; }; +class LLVM_LIBRARY_VISIBILITY Fuchsia : public Generic_ELF { +public: + Fuchsia(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool isPIEDefault() const override { return true; } + bool HasNativeLLVMSupport() const override { return true; } + bool IsIntegratedAssemblerDefault() const override { return true; } + llvm::DebuggerKind getDefaultDebuggerTuning() const override { + return llvm::DebuggerKind::GDB; + } + + RuntimeLibType + GetRuntimeLibType(const llvm::opt::ArgList &Args) const override; + CXXStdlibType + GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + /// TCEToolChain - A tool chain using the llvm bitcode tools to perform /// all subcommands. See http://tce.cs.tut.fi for our peculiar target. class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain { Index: lib/Driver/ToolChains.cpp =================================================================== --- lib/Driver/ToolChains.cpp +++ lib/Driver/ToolChains.cpp @@ -4761,6 +4761,108 @@ ToolChain::addProfileRTLibs(Args, CmdArgs); } +/// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly. + +Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + + getFilePaths().push_back(D.SysRoot + "/lib"); + getFilePaths().push_back(D.ResourceDir + "/lib/fuchsia"); + + // Use LLD by default. + DefaultLinker = "lld"; +} + +Tool *Fuchsia::buildAssembler() const { + return new tools::gnutools::Assembler(*this); +} + +Tool *Fuchsia::buildLinker() const { + return new tools::fuchsia::Linker(*this); +} + +ToolChain::RuntimeLibType Fuchsia::GetRuntimeLibType( + const ArgList &Args) const { + if (Arg *A = Args.getLastArg(options::OPT_rtlib_EQ)) { + StringRef Value = A->getValue(); + if (Value != "compiler-rt") + getDriver().Diag(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) 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 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; + } + + addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include"); +} + +void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/include/c++/v1"); +} + +void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + (void) GetCXXStdlibType(Args); + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lc++abi"); + CmdArgs.push_back("-lunwind"); +} + /// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. DragonFly::DragonFly(const Driver &D, const llvm::Triple &Triple, Index: lib/Driver/Tools.h =================================================================== --- lib/Driver/Tools.h +++ lib/Driver/Tools.h @@ -596,6 +596,21 @@ }; } // end namespace nacltools +namespace fuchsia { +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: + Linker(const ToolChain &TC) : GnuTool("fuchsia::Linker", "ld.lld", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace fuchsia + /// minix -- Directly call GNU Binutils assembler and linker namespace minix { class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp +++ lib/Driver/Tools.cpp @@ -9493,6 +9493,7 @@ llvm_unreachable("unsupported OS"); case llvm::Triple::Win32: case llvm::Triple::Linux: + case llvm::Triple::Fuchsia: addClangRT(TC, Args, CmdArgs); break; } @@ -9979,6 +9980,112 @@ C.addCommand(llvm::make_unique(JA, *this, Exec, CmdArgs, Inputs)); } +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(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::filename(Exec).equals_lower("lld")) { + CmdArgs.push_back("-flavor"); + CmdArgs.push_back("gnu"); + } + + 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); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (Args.hasArg(options::OPT_static)) + CmdArgs.push_back("-Bdynamic"); + + if (D.CCCIsCXX()) { + bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && + !Args.hasArg(options::OPT_static); + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bstatic"); + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bdynamic"); + 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(JA, *this, Exec, CmdArgs, Inputs)); +} + void minix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, Index: test/Driver/fuchsia.c =================================================================== --- /dev/null +++ test/Driver/fuchsia.c @@ -0,0 +1,40 @@ +// RUN: %clang %s -### --target=x86_64-unknown-fuchsia \ +// RUN: --sysroot=%S/platform 2>&1 | FileCheck %s +// CHECK: {{.*}}clang{{.*}}" "-cc1" +// CHECK: "-fuse-init-array" +// CHECK: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK: "-internal-externc-isystem" "[[SYSROOT]]{{/|\\\\}}include" +// CHECK: {{.*}}lld{{.*}}" "-flavor" "gnu" +// CHECK: "--sysroot=[[SYSROOT]]" +// CHECK: "-pie" +// CHECK: "--build-id" +// CHECK: "-dynamic-linker" "ld.so.1" +// CHECK: Scrt1.o +// CHECK-NOT: crti.o +// CHECK-NOT: crtbegin.o +// CHECK: "-L[[SYSROOT]]/lib" +// CHECK: "{{.*[/\\]}}libclang_rt.builtins-x86_64.a" +// CHECK: "-lc" +// CHECK-NOT: crtend.o +// CHECK-NOT: crtn.o + +// RUN: %clang %s -### --target=x86_64-unknown-fuchsia -rtlib=libgcc 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-RTLIB +// CHECK-RTLIB: error: invalid runtime library name in argument '-rtlib=libgcc' + +// RUN: %clang %s -### --target=x86_64-unknown-fuchsia -static 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-STATIC +// CHECK-STATIC: "-Bstatic" +// CHECK-STATIC: "-Bdynamic" +// CHECK-STATIC: "-lc" + +// RUN: %clang %s -### --target=x86_64-unknown-fuchsia -shared 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-SHARED +// CHECK-SHARED-NOT: "-pie" +// CHECK-SHARED: "-shared" + +// RUN: %clang %s -### --target=x86_64-unknown-fuchsia -r 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-RELOCATABLE +// CHECK-RELOCATABLE-NOT: "-pie" +// CHECK-RELOCATABLE-NOT: "--build-id" +// CHECK-RELOCATABLE: "-r" Index: test/Driver/fuchsia.cpp =================================================================== --- /dev/null +++ test/Driver/fuchsia.cpp @@ -0,0 +1,33 @@ +// RUN: %clangxx %s -### --target=x86_64-unknown-fuchsia \ +// RUN: --sysroot=%S/platform 2>&1 | FileCheck %s +// CHECK: {{.*}}clang{{.*}}" "-cc1" +// CHECK: "-fuse-init-array" +// CHECK: "-isysroot" "[[SYSROOT:[^"]+]]" +// CHECK: "-internal-isystem" "[[SYSROOT]]{{/|\\\\}}include{{/|\\\\}}c++{{/|\\\\}}v1" +// CHECK: "-internal-externc-isystem" "[[SYSROOT]]{{/|\\\\}}include" +// CHECK: {{.*}}lld{{.*}}" "-flavor" "gnu" +// CHECK: "--sysroot=[[SYSROOT]]" +// CHECK: "-pie" +// CHECK: "--build-id" +// CHECK: "-dynamic-linker" "ld.so.1" +// CHECK: Scrt1.o +// CHECK-NOT: crti.o +// CHECK-NOT: crtbegin.o +// CHECK: "-L[[SYSROOT]]/lib" +// CHECK: "-lc++" "-lc++abi" "-lunwind" "-lm" +// CHECK: "{{.*[/\\]}}libclang_rt.builtins-x86_64.a" +// CHECK: "-lc" +// CHECK-NOT: crtend.o +// CHECK-NOT: crtn.o + +// RUN: %clangxx %s -### --target=x86_64-unknown-fuchsia -stdlib=libstdc++ 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-STDLIB +// CHECK-STDLIB: error: invalid library name in argument '-stdlib=libstdc++' + +// RUN: %clangxx %s -### --target=x86_64-unknown-fuchsia -static-libstdc++ 2>&1 \ +// RUN: | FileCheck %s -check-prefix=CHECK-STATIC +// CHECK-STATIC: "-Bstatic" +// CHECK-STATIC: "-lc++" "-lc++abi" "-lunwind" +// CHECK-STATIC: "-Bdynamic" +// CHECK-STATIC: "-lm" +// CHECK-STATIC: "-lc"