Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Driver] Implement ToolChain on Haiku #66038

Merged
merged 1 commit into from
Sep 22, 2023
Merged

Conversation

brad0
Copy link
Contributor

@brad0 brad0 commented Sep 12, 2023

Instead of passing everything off to GCC, add a ToolChain for Haiku to allow Clang to properly link things on its own.

@brad0 brad0 requested a review from a team as a code owner September 12, 2023 02:12
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' labels Sep 12, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Sep 12, 2023

@llvm/pr-subscribers-clang

Changes

Instead of passing everything off to GCC, add a ToolChain for Haiku to allow Clang to properly link things on its own.

Full diff: https://github.com/llvm/llvm-project/pull/66038.diff

12 Files Affected:

  • (modified) clang/lib/Driver/ToolChains/Gnu.cpp (+31)
  • (modified) clang/lib/Driver/ToolChains/Haiku.cpp (+137)
  • (modified) clang/lib/Driver/ToolChains/Haiku.h (+31)
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/crti.o ()
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/crtn.o ()
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/init_term_dyn.o ()
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/start_dyn.o ()
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtbegin.o ()
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtbeginS.o ()
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtend.o ()
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtendS.o ()
  • (modified) clang/test/Driver/haiku.c (+44)
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index 7aeb8e29ebc5574..cd6713ab52d926d 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -2224,6 +2224,12 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
 void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
     const llvm::Triple &TargetTriple, SmallVectorImpl &Prefixes,
     StringRef SysRoot) {
+
+  if (TargetTriple.isOSHaiku()) {
+    Prefixes.push_back(concat(SysRoot, "/boot/system/develop/tools"));
+    return;
+  }
+
   if (TargetTriple.isOSSolaris()) {
     // Solaris is a special case.
     // The GCC installation is under
@@ -2426,6 +2432,31 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
   using std::begin;
   using std::end;
 
+  if (TargetTriple.isOSHaiku()) {
+    static const char *const HaikuLibDirs[] = {"/lib"};
+    static const char *const HaikuAArch64Triples[] = {"aarch64-unknown-haiku"};
+    static const char *const HaikuRISCV64Triples[] = {"riscv64-unknown-haiku"};
+    static const char *const HaikuX86Triples[] = {"i586-unknown-haiku"};
+    static const char *const HaikuX86_64Triples[] = {"x86_64-unknown-haiku"};
+    LibDirs.append(begin(HaikuLibDirs), end(HaikuLibDirs));
+    switch (TargetTriple.getArch()) {
+    case llvm::Triple::aarch64:
+      TripleAliases.append(begin(HaikuAArch64Triples), end(HaikuAArch64Triples));
+      break;
+    case llvm::Triple::riscv64:
+      TripleAliases.append(begin(HaikuRISCV64Triples), end(HaikuRISCV64Triples));
+      break;
+    case llvm::Triple::x86:
+      TripleAliases.append(begin(HaikuX86Triples), end(HaikuX86Triples));
+      break;
+    case llvm::Triple::x86_64:
+      TripleAliases.append(begin(HaikuX86_64Triples), end(HaikuX86_64Triples));
+      break;
+    default:
+      break;
+    }
+  }
+
   if (TargetTriple.isOSSolaris()) {
     static const char *const SolarisLibDirs[] = {"/lib"};
     static const char *const SolarisSparcV8Triples[] = {
diff --git a/clang/lib/Driver/ToolChains/Haiku.cpp b/clang/lib/Driver/ToolChains/Haiku.cpp
index 55fc0533f699fab..3def1c7b67a30a9 100644
--- a/clang/lib/Driver/ToolChains/Haiku.cpp
+++ b/clang/lib/Driver/ToolChains/Haiku.cpp
@@ -9,20 +9,145 @@
 #include "Haiku.h"
 #include "CommonArgs.h"
 #include "clang/Config/config.h"
+#include "clang/Driver/Compilation.h"
 #include "llvm/Support/Path.h"
 
 using namespace clang::driver;
+using namespace clang::driver::tools;
 using namespace clang::driver::toolchains;
 using namespace clang;
 using namespace llvm::opt;
 
+void haiku::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+                                   const InputInfo &Output,
+                                   const InputInfoList &Inputs,
+                                   const ArgList &Args,
+                                   const char *LinkingOutput) const {
+  const toolchains::Haiku &ToolChain =
+      static_cast(getToolChain());
+  const Driver &D = ToolChain.getDriver();
+  const llvm::Triple::ArchType Arch = ToolChain.getArch();
+  const bool Static = Args.hasArg(options::OPT_static);
+  const bool Shared = Args.hasArg(options::OPT_shared);
+  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);
+
+  // Silence warning for "clang -pie foo.o -o foo"
+  Args.ClaimAllArgs(options::OPT_pie);
+
+  if (!D.SysRoot.empty())
+    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+  CmdArgs.push_back("--eh-frame-hdr");
+  if (Static) {
+    CmdArgs.push_back("-Bstatic");
+  } else {
+    if (Args.hasArg(options::OPT_rdynamic))
+      CmdArgs.push_back("-export-dynamic");
+    if (Shared)
+      CmdArgs.push_back("-shared");
+    CmdArgs.push_back("--enable-new-dtags");
+  }
+
+  CmdArgs.push_back("-shared");
+
+  if (!Shared)
+    CmdArgs.push_back("--no-undefined");
+
+  if (Arch == llvm::Triple::riscv64)
+    CmdArgs.push_back("-X");
+
+  if (Output.isFilename()) {
+    CmdArgs.push_back("-o");
+    CmdArgs.push_back(Output.getFilename());
+  } else {
+    assert(Output.isNothing() && "Invalid output.");
+  }
+
+  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
+                   options::OPT_r)) {
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o")));
+    if (!Shared)
+      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("start_dyn.o")));
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("init_term_dyn.o")));
+  }
+
+  Args.AddAllArgs(CmdArgs,
+                  {options::OPT_L, options::OPT_T_Group, options::OPT_s,
+                   options::OPT_t, options::OPT_Z_Flag, options::OPT_r});
+  ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+
+  addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs);
+  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
+                   options::OPT_r)) {
+    // Use the static OpenMP runtime with -static-openmp
+    bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static;
+    addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP);
+
+    if (D.CCCIsCXX()) {
+      if (ToolChain.ShouldLinkCXXStdlib(Args))
+        ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+    }
+
+    CmdArgs.push_back("-lgcc");
+
+    CmdArgs.push_back("--push-state");
+    CmdArgs.push_back("--as-needed");
+    CmdArgs.push_back("-lgcc_s");
+    CmdArgs.push_back("--no-as-needed");
+    CmdArgs.push_back("--pop-state");
+
+    CmdArgs.push_back("-lroot");
+
+    CmdArgs.push_back("-lgcc");
+
+    CmdArgs.push_back("--push-state");
+    CmdArgs.push_back("--as-needed");
+    CmdArgs.push_back("-lgcc_s");
+    CmdArgs.push_back("--no-as-needed");
+    CmdArgs.push_back("--pop-state");
+  }
+
+  // No need to do anything for pthreads. Claim argument to avoid warning.
+  Args.ClaimAllArgs(options::OPT_pthread);
+  Args.ClaimAllArgs(options::OPT_pthreads);
+
+  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
+                   options::OPT_r)) {
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
+  }
+
+  ToolChain.addProfileRTLibs(Args, CmdArgs);
+
+  const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
+  C.addCommand(std::make_unique(JA, *this,
+                                         ResponseFileSupport::AtFileCurCP(),
+                                         Exec, CmdArgs, Inputs, Output));
+}
+
 /// Haiku - Haiku tool chain which can call as(1) and ld(1) directly.
 
 Haiku::Haiku(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
   : Generic_ELF(D, Triple, Args) {
 
+  GCCInstallation.init(Triple, Args);
+
   getFilePaths().push_back(concat(getDriver().SysRoot, "/boot/system/lib"));
   getFilePaths().push_back(concat(getDriver().SysRoot, "/boot/system/develop/lib"));
+
+  if (GCCInstallation.isValid())
+    getFilePaths().push_back(GCCInstallation.getInstallPath().str());
 }
 
 void Haiku::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
@@ -133,3 +258,15 @@ void Haiku::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
   addLibStdCXXIncludePaths(concat(getDriver().SysRoot, "/boot/system/develop/headers/c++"),
                            getTriple().str(), "", DriverArgs, CC1Args);
 }
+
+void Haiku::addClangTargetOptions(const ArgList &DriverArgs,
+                                    ArgStringList &CC1Args,
+                                    Action::OffloadKind) const {
+  if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
+                          options::OPT_fno_use_init_array, false))
+    CC1Args.push_back("-fno-use-init-array");
+}
+
+Tool *Haiku::buildLinker() const { return new tools::haiku::Linker(*this); }
+
+bool Haiku::HasNativeLLVMSupport() const { return true; }
diff --git a/clang/lib/Driver/ToolChains/Haiku.h b/clang/lib/Driver/ToolChains/Haiku.h
index 4b5f21f7ba66bec..941d35e7bfbbf28 100644
--- a/clang/lib/Driver/ToolChains/Haiku.h
+++ b/clang/lib/Driver/ToolChains/Haiku.h
@@ -15,6 +15,25 @@
 
 namespace clang {
 namespace driver {
+namespace tools {
+
+/// haiku -- Directly call GNU Binutils assembler and linker
+namespace haiku {
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+public:
+  Linker(const ToolChain &TC) : Tool("haiku::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 haiku
+} // end namespace tools
+
 namespace toolchains {
 
 class LLVM_LIBRARY_VISIBILITY Haiku : public Generic_ELF {
@@ -22,10 +41,14 @@ class LLVM_LIBRARY_VISIBILITY Haiku : public Generic_ELF {
   Haiku(const Driver &D, const llvm::Triple &Triple,
           const llvm::opt::ArgList &Args);
 
+  bool HasNativeLLVMSupport() const override;
+
   bool IsMathErrnoDefault() const override { return false; }
   bool IsObjCNonFragileABIDefault() const override { return true; }
   bool isPICDefault() const override { return true; }
 
+  const char *getDefaultLinker() const override { return "ld.lld"; }
+
   void AddClangSystemIncludeArgs(
       const llvm::opt::ArgList &DriverArgs,
       llvm::opt::ArgStringList &CC1Args) const override;
@@ -39,6 +62,14 @@ class LLVM_LIBRARY_VISIBILITY Haiku : public Generic_ELF {
   unsigned GetDefaultDwarfVersion() const override { return 4; }
 
   bool GetDefaultStandaloneDebug() const override { return true; }
+
+  void
+  addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+                        llvm::opt::ArgStringList &CC1Args,
+                        Action::OffloadKind DeviceOffloadKind) const override;
+
+protected:
+  Tool *buildLinker() const override;
 };
 
 } // end namespace toolchains
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/crti.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/crti.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/crtn.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/crtn.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/init_term_dyn.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/init_term_dyn.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/start_dyn.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/start_dyn.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtbegin.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtbegin.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtbeginS.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtbeginS.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtend.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtend.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtendS.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtendS.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/haiku.c b/clang/test/Driver/haiku.c
index 728173a78ccf960..53cd69f2c605db0 100644
--- a/clang/test/Driver/haiku.c
+++ b/clang/test/Driver/haiku.c
@@ -36,3 +36,47 @@
 // CHECK-C-HEADER-PATH: "-internal-isystem" "/boot/system/develop/headers/gnu"
 // CHECK-C-HEADER-PATH: "-internal-isystem" "/boot/system/develop/headers/posix"
 // CHECK-C-HEADER-PATH: "-internal-isystem" "/boot/system/develop/headers"
+
+// Check x86_64-unknown-haiku, X86_64
+// RUN: %clang -### %s 2>&1 --target=x86_64-unknown-haiku \
+// RUN:     --gcc-toolchain="" \
+// RUN:     --sysroot=%S/Inputs/haiku_x86_64_tree \
+// RUN:   | FileCheck --check-prefix=CHECK-LD-X86_64 %s
+// CHECK-LD-X86_64: "-cc1" "-triple" "x86_64-unknown-haiku"
+// CHECK-LD-X86_64-SAME: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-LD-X86_64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-LD-X86_64-SAME: "--no-undefined"
+// CHECK-LD-X86_64-SAME: "[[SYSROOT]]/boot/system/develop/lib/crti.o"
+// CHECK-LD-X86_64-SAME: "[[SYSROOT]]/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtbeginS.o"
+// CHECK-LD-X86_64-SAME: "[[SYSROOT]]/boot/system/develop/lib/start_dyn.o"
+// CHECK-LD-X86_64-SAME: "[[SYSROOT]]/boot/system/develop/lib/init_term_dyn.o"
+// CHECK-LD-X86_64-SAME: "-lgcc"
+// CHECK-LD-X86_64-SAME: "--push-state"
+// CHECK-LD-X86_64-SAME: "--as-needed"
+// CHECK-LD-X86_64-SAME: "-lgcc_s"
+// CHECK-LD-X86_64-SAME: "--no-as-needed"
+// CHECK-LD-X86_64-SAME: "--pop-state"
+// CHECK-LD-X86_64-SAME: "-lroot"
+// CHECK-LD-X86_64-SAME: "-lgcc"
+// CHECK-LD-X86_64-SAME: "--push-state"
+// CHECK-LD-X86_64-SAME: "--as-needed"
+// CHECK-LD-X86_64-SAME: "-lgcc_s"
+// CHECK-LD-X86_64-SAME: "--no-as-needed"
+// CHECK-LD-X86_64-SAME: "--pop-state"
+// CHECK-LD-X86_64-SAME: "[[SYSROOT]]/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtendS.o"
+// CHECK-LD-X86_64-SAME: "[[SYSROOT]]/boot/system/develop/lib/crtn.o"
+
+// Check the right flags are present with -shared
+// RUN: %clang -### %s -shared 2>&1 --target=x86_64-unknown-haiku \
+// RUN:     --gcc-toolchain="" \
+// RUN:     --sysroot=%S/Inputs/haiku_x86_64_tree \
+// RUN:   | FileCheck --check-prefix=CHECK-X86_64-SHARED %s
+// CHECK-X86_64-SHARED: "-cc1" "-triple" "x86_64-unknown-haiku"
+// CHECK-X86_64-SHARED-SAME: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-X86_64-SHARED: "{{.*}}ld{{(.exe)?}}"
+// CHECK-X86_64-SHARED-NOT: "[[SYSROOT]]/boot/system/develop/lib/start_dyn.o"
+
+// Check -fno-init-array
+// RUN: %clang -target x86_64-unknown-haiku %s -### 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-CTORS %s
+// CHECK-CTORS: "-fno-use-init-array"

@llvmbot
Copy link
Collaborator

llvmbot commented Sep 12, 2023

@llvm/pr-subscribers-clang-driver

Changes

Instead of passing everything off to GCC, add a ToolChain for Haiku to allow Clang to properly link things on its own.

Full diff: https://github.com/llvm/llvm-project/pull/66038.diff

12 Files Affected:

  • (modified) clang/lib/Driver/ToolChains/Gnu.cpp (+31)
  • (modified) clang/lib/Driver/ToolChains/Haiku.cpp (+137)
  • (modified) clang/lib/Driver/ToolChains/Haiku.h (+31)
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/crti.o ()
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/crtn.o ()
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/init_term_dyn.o ()
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/start_dyn.o ()
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtbegin.o ()
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtbeginS.o ()
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtend.o ()
  • (added) clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtendS.o ()
  • (modified) clang/test/Driver/haiku.c (+44)
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index 7aeb8e29ebc5574..cd6713ab52d926d 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -2224,6 +2224,12 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
 void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
     const llvm::Triple &TargetTriple, SmallVectorImpl &Prefixes,
     StringRef SysRoot) {
+
+  if (TargetTriple.isOSHaiku()) {
+    Prefixes.push_back(concat(SysRoot, "/boot/system/develop/tools"));
+    return;
+  }
+
   if (TargetTriple.isOSSolaris()) {
     // Solaris is a special case.
     // The GCC installation is under
@@ -2426,6 +2432,31 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
   using std::begin;
   using std::end;
 
+  if (TargetTriple.isOSHaiku()) {
+    static const char *const HaikuLibDirs[] = {"/lib"};
+    static const char *const HaikuAArch64Triples[] = {"aarch64-unknown-haiku"};
+    static const char *const HaikuRISCV64Triples[] = {"riscv64-unknown-haiku"};
+    static const char *const HaikuX86Triples[] = {"i586-unknown-haiku"};
+    static const char *const HaikuX86_64Triples[] = {"x86_64-unknown-haiku"};
+    LibDirs.append(begin(HaikuLibDirs), end(HaikuLibDirs));
+    switch (TargetTriple.getArch()) {
+    case llvm::Triple::aarch64:
+      TripleAliases.append(begin(HaikuAArch64Triples), end(HaikuAArch64Triples));
+      break;
+    case llvm::Triple::riscv64:
+      TripleAliases.append(begin(HaikuRISCV64Triples), end(HaikuRISCV64Triples));
+      break;
+    case llvm::Triple::x86:
+      TripleAliases.append(begin(HaikuX86Triples), end(HaikuX86Triples));
+      break;
+    case llvm::Triple::x86_64:
+      TripleAliases.append(begin(HaikuX86_64Triples), end(HaikuX86_64Triples));
+      break;
+    default:
+      break;
+    }
+  }
+
   if (TargetTriple.isOSSolaris()) {
     static const char *const SolarisLibDirs[] = {"/lib"};
     static const char *const SolarisSparcV8Triples[] = {
diff --git a/clang/lib/Driver/ToolChains/Haiku.cpp b/clang/lib/Driver/ToolChains/Haiku.cpp
index 55fc0533f699fab..3def1c7b67a30a9 100644
--- a/clang/lib/Driver/ToolChains/Haiku.cpp
+++ b/clang/lib/Driver/ToolChains/Haiku.cpp
@@ -9,20 +9,145 @@
 #include "Haiku.h"
 #include "CommonArgs.h"
 #include "clang/Config/config.h"
+#include "clang/Driver/Compilation.h"
 #include "llvm/Support/Path.h"
 
 using namespace clang::driver;
+using namespace clang::driver::tools;
 using namespace clang::driver::toolchains;
 using namespace clang;
 using namespace llvm::opt;
 
+void haiku::Linker::ConstructJob(Compilation &C, const JobAction &JA,
+                                   const InputInfo &Output,
+                                   const InputInfoList &Inputs,
+                                   const ArgList &Args,
+                                   const char *LinkingOutput) const {
+  const toolchains::Haiku &ToolChain =
+      static_cast(getToolChain());
+  const Driver &D = ToolChain.getDriver();
+  const llvm::Triple::ArchType Arch = ToolChain.getArch();
+  const bool Static = Args.hasArg(options::OPT_static);
+  const bool Shared = Args.hasArg(options::OPT_shared);
+  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);
+
+  // Silence warning for "clang -pie foo.o -o foo"
+  Args.ClaimAllArgs(options::OPT_pie);
+
+  if (!D.SysRoot.empty())
+    CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
+
+  CmdArgs.push_back("--eh-frame-hdr");
+  if (Static) {
+    CmdArgs.push_back("-Bstatic");
+  } else {
+    if (Args.hasArg(options::OPT_rdynamic))
+      CmdArgs.push_back("-export-dynamic");
+    if (Shared)
+      CmdArgs.push_back("-shared");
+    CmdArgs.push_back("--enable-new-dtags");
+  }
+
+  CmdArgs.push_back("-shared");
+
+  if (!Shared)
+    CmdArgs.push_back("--no-undefined");
+
+  if (Arch == llvm::Triple::riscv64)
+    CmdArgs.push_back("-X");
+
+  if (Output.isFilename()) {
+    CmdArgs.push_back("-o");
+    CmdArgs.push_back(Output.getFilename());
+  } else {
+    assert(Output.isNothing() && "Invalid output.");
+  }
+
+  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
+                   options::OPT_r)) {
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbeginS.o")));
+    if (!Shared)
+      CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("start_dyn.o")));
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("init_term_dyn.o")));
+  }
+
+  Args.AddAllArgs(CmdArgs,
+                  {options::OPT_L, options::OPT_T_Group, options::OPT_s,
+                   options::OPT_t, options::OPT_Z_Flag, options::OPT_r});
+  ToolChain.AddFilePathLibArgs(Args, CmdArgs);
+
+  addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs);
+  AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
+
+  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
+                   options::OPT_r)) {
+    // Use the static OpenMP runtime with -static-openmp
+    bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static;
+    addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP);
+
+    if (D.CCCIsCXX()) {
+      if (ToolChain.ShouldLinkCXXStdlib(Args))
+        ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+    }
+
+    CmdArgs.push_back("-lgcc");
+
+    CmdArgs.push_back("--push-state");
+    CmdArgs.push_back("--as-needed");
+    CmdArgs.push_back("-lgcc_s");
+    CmdArgs.push_back("--no-as-needed");
+    CmdArgs.push_back("--pop-state");
+
+    CmdArgs.push_back("-lroot");
+
+    CmdArgs.push_back("-lgcc");
+
+    CmdArgs.push_back("--push-state");
+    CmdArgs.push_back("--as-needed");
+    CmdArgs.push_back("-lgcc_s");
+    CmdArgs.push_back("--no-as-needed");
+    CmdArgs.push_back("--pop-state");
+  }
+
+  // No need to do anything for pthreads. Claim argument to avoid warning.
+  Args.ClaimAllArgs(options::OPT_pthread);
+  Args.ClaimAllArgs(options::OPT_pthreads);
+
+  if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
+                   options::OPT_r)) {
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
+    CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
+  }
+
+  ToolChain.addProfileRTLibs(Args, CmdArgs);
+
+  const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
+  C.addCommand(std::make_unique(JA, *this,
+                                         ResponseFileSupport::AtFileCurCP(),
+                                         Exec, CmdArgs, Inputs, Output));
+}
+
 /// Haiku - Haiku tool chain which can call as(1) and ld(1) directly.
 
 Haiku::Haiku(const Driver &D, const llvm::Triple& Triple, const ArgList &Args)
   : Generic_ELF(D, Triple, Args) {
 
+  GCCInstallation.init(Triple, Args);
+
   getFilePaths().push_back(concat(getDriver().SysRoot, "/boot/system/lib"));
   getFilePaths().push_back(concat(getDriver().SysRoot, "/boot/system/develop/lib"));
+
+  if (GCCInstallation.isValid())
+    getFilePaths().push_back(GCCInstallation.getInstallPath().str());
 }
 
 void Haiku::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
@@ -133,3 +258,15 @@ void Haiku::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
   addLibStdCXXIncludePaths(concat(getDriver().SysRoot, "/boot/system/develop/headers/c++"),
                            getTriple().str(), "", DriverArgs, CC1Args);
 }
+
+void Haiku::addClangTargetOptions(const ArgList &DriverArgs,
+                                    ArgStringList &CC1Args,
+                                    Action::OffloadKind) const {
+  if (!DriverArgs.hasFlag(options::OPT_fuse_init_array,
+                          options::OPT_fno_use_init_array, false))
+    CC1Args.push_back("-fno-use-init-array");
+}
+
+Tool *Haiku::buildLinker() const { return new tools::haiku::Linker(*this); }
+
+bool Haiku::HasNativeLLVMSupport() const { return true; }
diff --git a/clang/lib/Driver/ToolChains/Haiku.h b/clang/lib/Driver/ToolChains/Haiku.h
index 4b5f21f7ba66bec..941d35e7bfbbf28 100644
--- a/clang/lib/Driver/ToolChains/Haiku.h
+++ b/clang/lib/Driver/ToolChains/Haiku.h
@@ -15,6 +15,25 @@
 
 namespace clang {
 namespace driver {
+namespace tools {
+
+/// haiku -- Directly call GNU Binutils assembler and linker
+namespace haiku {
+class LLVM_LIBRARY_VISIBILITY Linker : public Tool {
+public:
+  Linker(const ToolChain &TC) : Tool("haiku::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 haiku
+} // end namespace tools
+
 namespace toolchains {
 
 class LLVM_LIBRARY_VISIBILITY Haiku : public Generic_ELF {
@@ -22,10 +41,14 @@ class LLVM_LIBRARY_VISIBILITY Haiku : public Generic_ELF {
   Haiku(const Driver &D, const llvm::Triple &Triple,
           const llvm::opt::ArgList &Args);
 
+  bool HasNativeLLVMSupport() const override;
+
   bool IsMathErrnoDefault() const override { return false; }
   bool IsObjCNonFragileABIDefault() const override { return true; }
   bool isPICDefault() const override { return true; }
 
+  const char *getDefaultLinker() const override { return "ld.lld"; }
+
   void AddClangSystemIncludeArgs(
       const llvm::opt::ArgList &DriverArgs,
       llvm::opt::ArgStringList &CC1Args) const override;
@@ -39,6 +62,14 @@ class LLVM_LIBRARY_VISIBILITY Haiku : public Generic_ELF {
   unsigned GetDefaultDwarfVersion() const override { return 4; }
 
   bool GetDefaultStandaloneDebug() const override { return true; }
+
+  void
+  addClangTargetOptions(const llvm::opt::ArgList &DriverArgs,
+                        llvm::opt::ArgStringList &CC1Args,
+                        Action::OffloadKind DeviceOffloadKind) const override;
+
+protected:
+  Tool *buildLinker() const override;
 };
 
 } // end namespace toolchains
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/crti.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/crti.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/crtn.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/crtn.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/init_term_dyn.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/init_term_dyn.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/start_dyn.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/lib/start_dyn.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtbegin.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtbegin.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtbeginS.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtbeginS.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtend.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtend.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtendS.o b/clang/test/Driver/Inputs/haiku_x86_64_tree/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtendS.o
new file mode 100644
index 000000000000000..e69de29bb2d1d64
diff --git a/clang/test/Driver/haiku.c b/clang/test/Driver/haiku.c
index 728173a78ccf960..53cd69f2c605db0 100644
--- a/clang/test/Driver/haiku.c
+++ b/clang/test/Driver/haiku.c
@@ -36,3 +36,47 @@
 // CHECK-C-HEADER-PATH: "-internal-isystem" "/boot/system/develop/headers/gnu"
 // CHECK-C-HEADER-PATH: "-internal-isystem" "/boot/system/develop/headers/posix"
 // CHECK-C-HEADER-PATH: "-internal-isystem" "/boot/system/develop/headers"
+
+// Check x86_64-unknown-haiku, X86_64
+// RUN: %clang -### %s 2>&1 --target=x86_64-unknown-haiku \
+// RUN:     --gcc-toolchain="" \
+// RUN:     --sysroot=%S/Inputs/haiku_x86_64_tree \
+// RUN:   | FileCheck --check-prefix=CHECK-LD-X86_64 %s
+// CHECK-LD-X86_64: "-cc1" "-triple" "x86_64-unknown-haiku"
+// CHECK-LD-X86_64-SAME: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-LD-X86_64: "{{.*}}ld{{(.exe)?}}"
+// CHECK-LD-X86_64-SAME: "--no-undefined"
+// CHECK-LD-X86_64-SAME: "[[SYSROOT]]/boot/system/develop/lib/crti.o"
+// CHECK-LD-X86_64-SAME: "[[SYSROOT]]/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtbeginS.o"
+// CHECK-LD-X86_64-SAME: "[[SYSROOT]]/boot/system/develop/lib/start_dyn.o"
+// CHECK-LD-X86_64-SAME: "[[SYSROOT]]/boot/system/develop/lib/init_term_dyn.o"
+// CHECK-LD-X86_64-SAME: "-lgcc"
+// CHECK-LD-X86_64-SAME: "--push-state"
+// CHECK-LD-X86_64-SAME: "--as-needed"
+// CHECK-LD-X86_64-SAME: "-lgcc_s"
+// CHECK-LD-X86_64-SAME: "--no-as-needed"
+// CHECK-LD-X86_64-SAME: "--pop-state"
+// CHECK-LD-X86_64-SAME: "-lroot"
+// CHECK-LD-X86_64-SAME: "-lgcc"
+// CHECK-LD-X86_64-SAME: "--push-state"
+// CHECK-LD-X86_64-SAME: "--as-needed"
+// CHECK-LD-X86_64-SAME: "-lgcc_s"
+// CHECK-LD-X86_64-SAME: "--no-as-needed"
+// CHECK-LD-X86_64-SAME: "--pop-state"
+// CHECK-LD-X86_64-SAME: "[[SYSROOT]]/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/crtendS.o"
+// CHECK-LD-X86_64-SAME: "[[SYSROOT]]/boot/system/develop/lib/crtn.o"
+
+// Check the right flags are present with -shared
+// RUN: %clang -### %s -shared 2>&1 --target=x86_64-unknown-haiku \
+// RUN:     --gcc-toolchain="" \
+// RUN:     --sysroot=%S/Inputs/haiku_x86_64_tree \
+// RUN:   | FileCheck --check-prefix=CHECK-X86_64-SHARED %s
+// CHECK-X86_64-SHARED: "-cc1" "-triple" "x86_64-unknown-haiku"
+// CHECK-X86_64-SHARED-SAME: "-isysroot" "[[SYSROOT:[^"]+]]"
+// CHECK-X86_64-SHARED: "{{.*}}ld{{(.exe)?}}"
+// CHECK-X86_64-SHARED-NOT: "[[SYSROOT]]/boot/system/develop/lib/start_dyn.o"
+
+// Check -fno-init-array
+// RUN: %clang -target x86_64-unknown-haiku %s -### 2>&1 \
+// RUN:   | FileCheck --check-prefix=CHECK-CTORS %s
+// CHECK-CTORS: "-fno-use-init-array"

@brad0 brad0 force-pushed the clang_driver_haiku branch 3 times, most recently from ac7c355 to 0210654 Compare September 15, 2023 09:30
@brad0 brad0 requested a review from MaskRay September 20, 2023 03:21
clang/lib/Driver/ToolChains/Haiku.cpp Outdated Show resolved Hide resolved
clang/lib/Driver/ToolChains/Haiku.cpp Outdated Show resolved Hide resolved

CmdArgs.push_back("--push-state");
CmdArgs.push_back("--as-needed");
CmdArgs.push_back("-lgcc_s");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can AddRunTimeLibs be used?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not 100% certain, but I think it might be possible. But I'd like to keep that separate.

clang/lib/Driver/ToolChains/Haiku.cpp Outdated Show resolved Hide resolved
clang/lib/Driver/ToolChains/Haiku.h Outdated Show resolved Hide resolved
Copy link
Member

@MaskRay MaskRay left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can a Haiku developer confirm that these changes work on Haiku?

clang/lib/Driver/ToolChains/Haiku.cpp Outdated Show resolved Hide resolved
clang/lib/Driver/ToolChains/Haiku.h Outdated Show resolved Hide resolved
clang/test/Driver/haiku.c Show resolved Hide resolved
Co-authored-by: David Karoly <david.karoly@outlook.com>
Co-authored-by: Brad Smith <brad@comstyle.com>
@brad0
Copy link
Contributor Author

brad0 commented Sep 22, 2023

Can a Haiku developer confirm that these changes work on Haiku?

I built a few random Haiku apps. Look to be all C++ code. They worked fine. Same results for both GCC and Clang.

@brad0 brad0 merged commit 8ea7430 into llvm:main Sep 22, 2023
2 checks passed
@brad0 brad0 deleted the clang_driver_haiku branch September 24, 2023 20:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:driver 'clang' and 'clang++' user-facing binaries. Not 'clang-cl' clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants