diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -166,6 +166,9 @@ case llvm::Triple::OpenBSD: return std::make_unique>(Triple, Opts); + case llvm::Triple::Serenity: + return std::make_unique>(Triple, + Opts); case llvm::Triple::Win32: switch (Triple.getEnvironment()) { case llvm::Triple::GNU: @@ -463,6 +466,11 @@ return std::make_unique>(Triple, Opts); } + + case llvm::Triple::Serenity: + return std::make_unique>(Triple, + Opts); + default: return std::make_unique(Triple, Opts); } @@ -586,6 +594,9 @@ return std::make_unique(Triple, Opts); case llvm::Triple::Hurd: return std::make_unique>(Triple, Opts); + case llvm::Triple::Serenity: + return std::make_unique>(Triple, + Opts); default: return std::make_unique(Triple, Opts); } @@ -644,6 +655,9 @@ return std::make_unique>(Triple, Opts); case llvm::Triple::PS5: return std::make_unique>(Triple, Opts); + case llvm::Triple::Serenity: + return std::make_unique>(Triple, + Opts); default: return std::make_unique(Triple, Opts); } diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h --- a/clang/lib/Basic/Targets/OSTargets.h +++ b/clang/lib/Basic/Targets/OSTargets.h @@ -982,6 +982,23 @@ } }; +// SerenityOS target +template +class LLVM_LIBRARY_VISIBILITY SerenityTargetInfo : public OSTargetInfo { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + Builder.defineMacro("__serenity__"); + DefineStd(Builder, "unix", Opts); + } + +public: + SerenityTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) + : OSTargetInfo(Triple, Opts) { + this->WIntType = TargetInfo::UnsignedInt; + } +}; + } // namespace targets } // namespace clang #endif // LLVM_CLANG_LIB_BASIC_TARGETS_OSTARGETS_H diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -75,6 +75,7 @@ ToolChains/OpenBSD.cpp ToolChains/PS4CPU.cpp ToolChains/RISCVToolchain.cpp + ToolChains/Serenity.cpp ToolChains/Solaris.cpp ToolChains/SPIRV.cpp ToolChains/TCE.cpp diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -43,6 +43,7 @@ #include "ToolChains/PS4CPU.h" #include "ToolChains/RISCVToolchain.h" #include "ToolChains/SPIRV.h" +#include "ToolChains/Serenity.h" #include "ToolChains/Solaris.h" #include "ToolChains/TCE.h" #include "ToolChains/VEToolchain.h" @@ -6239,6 +6240,9 @@ case llvm::Triple::Fuchsia: TC = std::make_unique(*this, Target, Args); break; + case llvm::Triple::Serenity: + TC = std::make_unique(*this, Target, Args); + break; case llvm::Triple::Solaris: TC = std::make_unique(*this, Target, Args); break; diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -589,6 +589,8 @@ return "sunos"; case llvm::Triple::AIX: return "aix"; + case llvm::Triple::Serenity: + return "serenity"; default: return getOS(); } diff --git a/clang/lib/Driver/ToolChains/Serenity.h b/clang/lib/Driver/ToolChains/Serenity.h new file mode 100644 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Serenity.h @@ -0,0 +1,89 @@ +//===---- Serenity.h - SerenityOS ToolChain Implementation ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SERENITY_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SERENITY_H + +#include "Gnu.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +namespace serenity { + +class LLVM_LIBRARY_VISIBILITY Linker final : public Tool { +public: + Linker(const ToolChain &TC) : Tool("serenity::Linker", "linker", 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 serenity +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Serenity final : public Generic_ELF { +public: + Serenity(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + RuntimeLibType GetDefaultRuntimeLibType() const override { + return ToolChain::RLT_CompilerRT; + } + + CXXStdlibType GetDefaultCXXStdlibType() const override { + return ToolChain::CST_Libcxx; + } + + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; + + const char *getDefaultLinker() const override { return "ld.lld"; } + + bool HasNativeLLVMSupport() const override { return true; } + + bool isPICDefault() const override { return true; } + bool isPIEDefault(const llvm::opt::ArgList &) const override { return true; } + bool isPICDefaultForced() const override { return false; } + + bool IsMathErrnoDefault() const override { return false; } + + UnwindTableLevel + getDefaultUnwindTableLevel(const llvm::opt::ArgList &Args) const override { + return UnwindTableLevel::Asynchronous; + } + + LangOptions::StackProtectorMode + GetDefaultStackProtectorLevel(bool KernelOrKext) const override { + return LangOptions::SSPStrong; + } + +protected: + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SERENITY_H diff --git a/clang/lib/Driver/ToolChains/Serenity.cpp b/clang/lib/Driver/ToolChains/Serenity.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Serenity.cpp @@ -0,0 +1,212 @@ +//===---- Serenity.cpp - SerenityOS ToolChain Implementation ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Serenity.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 "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/VirtualFileSystem.h" +#include + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +static bool getPIE(const ArgList &Args, const ToolChain &TC) { + if (Args.hasArg(options::OPT_static, options::OPT_shared, + options::OPT_static_pie)) + return false; + Arg *Last = Args.getLastArg(options::OPT_pie, options::OPT_no_pie, + options::OPT_nopie); + return Last ? Last->getOption().matches(options::OPT_pie) : true; +} + +void tools::serenity::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const auto &TC = getToolChain(); + const auto &D = TC.getDriver(); + const bool IsShared = Args.hasArg(options::OPT_shared); + const bool IsStatic = + Args.hasArg(options::OPT_static) && !Args.hasArg(options::OPT_static_pie); + const bool IsRdynamic = Args.hasArg(options::OPT_rdynamic); + const bool IsStaticPIE = Args.hasArg(options::OPT_static_pie); + const bool IsPIE = getPIE(Args, TC); + ArgStringList CmdArgs; + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + if (IsPIE || IsStaticPIE) + CmdArgs.push_back("-pie"); + + if (IsShared) + CmdArgs.push_back("-shared"); + + if (IsStatic || IsStaticPIE) + CmdArgs.push_back("-static"); + + if (IsStaticPIE) { + CmdArgs.push_back("--no-dynamic-linker"); + CmdArgs.push_back("-z"); + CmdArgs.push_back("text"); + } + + if (!IsStatic && !IsStaticPIE) { + if (IsRdynamic) + CmdArgs.push_back("-export-dynamic"); + CmdArgs.push_back("-dynamic-linker"); + CmdArgs.push_back("/usr/lib/Loader.so"); + } + + if (!IsStatic || IsStaticPIE) + CmdArgs.push_back("--eh-frame-hdr"); + + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } + + CmdArgs.push_back("-z"); + CmdArgs.push_back("pack-relative-relocs"); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { + CmdArgs.push_back(Args.MakeArgString( + TC.GetFilePath((IsShared) ? "crt0_shared.o" : "crt0.o"))); + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crti.o"))); + + std::string crtbegin_path; + if (TC.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT) { + std::string crtbegin = + TC.getCompilerRT(Args, "crtbegin", ToolChain::FT_Object); + if (TC.getVFS().exists(crtbegin)) + crtbegin_path = crtbegin; + } + if (crtbegin_path.empty()) { + const char *crtbegin = (IsShared || IsPIE) ? "crtbeginS.o" : "crtbegin.o"; + crtbegin_path = TC.GetFilePath(crtbegin); + } + CmdArgs.push_back(Args.MakeArgString(crtbegin_path)); + } + + Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_u}); + + TC.AddFilePathLibArgs(Args, CmdArgs); + + if (D.isUsingLTO()) { + assert(!Inputs.empty() && "Must have at least one input."); + addLTOOptions(TC, Args, CmdArgs, Output, Inputs[0], + D.getLTOMode() == LTOK_Thin); + } + + Args.addAllArgs(CmdArgs, {options::OPT_T_Group, options::OPT_s, + options::OPT_t, options::OPT_r}); + + addLinkerCompressDebugSectionsOption(TC, Args, CmdArgs); + + AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + AddRunTimeLibs(TC, D, CmdArgs, Args); + + // We supply our own sanitizer runtimes that output errors to the + // Kernel debug log as well as stderr. + // FIXME: Properly port clang/gcc sanitizers and use those instead. + const SanitizerArgs &Sanitize = TC.getSanitizerArgs(Args); + if (Sanitize.needsUbsanRt()) + CmdArgs.push_back("-lubsan"); + } + + if (D.CCCIsCXX() && TC.ShouldLinkCXXStdlib(Args)) { + bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && + !Args.hasArg(options::OPT_static); + CmdArgs.push_back("--push-state"); + CmdArgs.push_back("--as-needed"); + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bstatic"); + TC.AddCXXStdlibLibArgs(Args, CmdArgs); + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bdynamic"); + CmdArgs.push_back("--pop-state"); + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs, + options::OPT_r)) { + if (!Args.hasArg(options::OPT_nolibc)) + CmdArgs.push_back("-lc"); + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles, + options::OPT_r)) { + std::string crtend_path; + if (TC.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT) { + std::string crtend = + TC.getCompilerRT(Args, "crtend", ToolChain::FT_Object); + if (TC.getVFS().exists(crtend)) + crtend_path = crtend; + } + if (crtend_path.empty()) { + const char *crtend = (IsShared || IsPIE) ? "crtendS.o" : "crtend.o"; + crtend_path = TC.GetFilePath(crtend); + } + CmdArgs.push_back(Args.MakeArgString(crtend_path)); + + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtn.o"))); + } + + const char *Exec = Args.MakeArgString(TC.GetLinkerPath()); + C.addCommand(std::make_unique(JA, *this, + ResponseFileSupport::AtFileCurCP(), + Exec, CmdArgs, Inputs, Output)); +} + +Serenity::Serenity(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + getFilePaths().push_back(concat(getDriver().SysRoot, "/usr/lib")); +} + +Tool *Serenity::buildLinker() const { + return new tools::serenity::Linker(*this); +} + +void Serenity::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) + addSystemInclude(DriverArgs, CC1Args, concat(D.ResourceDir, "/include")); + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + addSystemInclude(DriverArgs, CC1Args, + concat(D.SysRoot, "/usr/local/include")); + addSystemInclude(DriverArgs, CC1Args, concat(D.SysRoot, "/usr/include")); +} + +void Serenity::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const { + if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, true)) + CC1Args.push_back("-fno-use-init-array"); +} diff --git a/clang/lib/Lex/InitHeaderSearch.cpp b/clang/lib/Lex/InitHeaderSearch.cpp --- a/clang/lib/Lex/InitHeaderSearch.cpp +++ b/clang/lib/Lex/InitHeaderSearch.cpp @@ -304,6 +304,7 @@ case llvm::Triple::PS4: case llvm::Triple::PS5: case llvm::Triple::RTEMS: + case llvm::Triple::Serenity: case llvm::Triple::Solaris: case llvm::Triple::WASI: case llvm::Triple::ZOS: diff --git a/clang/test/Driver/Inputs/serenity_x86_64_tree/usr/include/c++/v1/.keep b/clang/test/Driver/Inputs/serenity_x86_64_tree/usr/include/c++/v1/.keep new file mode 100644 diff --git a/clang/test/Driver/Inputs/serenity_x86_64_tree/usr/include/x86_64-pc-serenity/c++/v1/.keep b/clang/test/Driver/Inputs/serenity_x86_64_tree/usr/include/x86_64-pc-serenity/c++/v1/.keep new file mode 100644 diff --git a/clang/test/Driver/Inputs/serenity_x86_64_tree/usr/lib/crt0.o b/clang/test/Driver/Inputs/serenity_x86_64_tree/usr/lib/crt0.o new file mode 100644 diff --git a/clang/test/Driver/Inputs/serenity_x86_64_tree/usr/lib/crt0_shared.o b/clang/test/Driver/Inputs/serenity_x86_64_tree/usr/lib/crt0_shared.o new file mode 100644 diff --git a/clang/test/Driver/Inputs/serenity_x86_64_tree/usr/lib/crti.o b/clang/test/Driver/Inputs/serenity_x86_64_tree/usr/lib/crti.o new file mode 100644 diff --git a/clang/test/Driver/Inputs/serenity_x86_64_tree/usr/lib/crtn.o b/clang/test/Driver/Inputs/serenity_x86_64_tree/usr/lib/crtn.o new file mode 100644 diff --git a/clang/test/Driver/Inputs/serenity_x86_64_tree/usr/local/.keep b/clang/test/Driver/Inputs/serenity_x86_64_tree/usr/local/.keep new file mode 100644 diff --git a/clang/test/Driver/serenity.cpp b/clang/test/Driver/serenity.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Driver/serenity.cpp @@ -0,0 +1,36 @@ +// UNSUPPORTED: system-windows + +/// Test a cross compiler. +// RUN: %clang -### %s --target=x86_64-pc-serenity --sysroot=%S/Inputs/serenity_x86_64_tree \ +// RUN: -ccc-install-dir %S/Inputs/serenity_x86_64/usr/local/bin -resource-dir=%S/Inputs/resource_dir \ +// RUN: --stdlib=platform --rtlib=platform --unwindlib=platform 2>&1 | FileCheck %s --check-prefix=SERENITY_x86_64 +// SERENITY_x86_64: "-resource-dir" "[[RESOURCE:[^"]+]]" +// SERENITY_x86_64: "-internal-isystem" +// SERENITY_x86_64-SAME: {{^}} "[[SYSROOT:[^"]+]]/usr/include/x86_64-pc-serenity/c++/v1" +// SERENITY_x86_64-SAME: {{^}} "-internal-isystem" "[[SYSROOT:[^"]+]]/usr/include/c++/v1" +// SERENITY_x86_64-SAME: {{^}} "-internal-isystem" "[[RESOURCE]]/include" +// SERENITY_x86_64-SAME: {{^}} "-internal-isystem" "[[SYSROOT:[^"]+]]/usr/local/include" +// SERENITY_x86_64-SAME: {{^}} "-internal-isystem" "[[SYSROOT:[^"]+]]/usr/include" +// SERENITY_x86_64: "-L +// SERENITY_x86_64-SAME: {{^}}[[SYSROOT]]/usr/lib" + +/// Loader name is the same for all architectures +// RUN: %clang -### %s --target=x86_64-pc-serenity --sysroot= \ +// RUN: --stdlib=platform --rtlib=platform --unwindlib=platform 2>&1 | FileCheck %s --check-prefix=DYNAMIC_LOADER +// RUN: %clang -### %s --target=aarch64-pc-serenity --sysroot= \ +// RUN: --stdlib=platform --rtlib=platform --unwindlib=platform 2>&1 | FileCheck %s --check-prefix=DYNAMIC_LOADER +// RUN: %clang -### %s --target=riscv64-pc-serenity --sysroot= \ +// RUN: --stdlib=platform --rtlib=platform --unwindlib=platform 2>&1 | FileCheck %s --check-prefix=DYNAMIC_LOADER +// DYNAMIC_LOADER: "-dynamic-linker" "/usr/lib/Loader.so" + +/// -r suppresses -dynamic-linker, default -l, and crt*.o like -nostdlib. +// RUN: %clang -### %s --target=x86_64-pc-serenity --sysroot=%S/Inputs/serenity_x86_64_tree \ +// RUN: -ccc-install-dir %S/Inputs/serenity_x86_64_tree/usr/local/bin -resource-dir=%S/Inputs/resource_dir \ +// RUN: --stdlib=platform --rtlib=platform -r 2>&1 | FileCheck %s --check-prefix=RELOCATABLE +// RELOCATABLE-NOT: "-dynamic-linker" +// RELOCATABLE: "-internal-isystem" +// RELOCATABLE-SAME: {{^}} "[[SYSROOT:[^"]+]]/usr/include/x86_64-pc-serenity/c++/v1" +// RELOCATABLE: "-L +// RELOCATABLE-SAME: {{^}}[[SYSROOT]]/usr/lib" +// RELOCATABLE-NOT: "-l +// RELOCATABLE-NOT: crt{{[^./]+}}.o