Skip to content

[Driver] Implement ToolChain on Haiku #66038

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

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
Member

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
Member

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

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.

@brad0 brad0 force-pushed the clang_driver_haiku branch from 0210654 to b34a9d0 Compare September 20, 2023 07:15
@brad0 brad0 requested a review from MaskRay September 20, 2023 08:07
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?

@brad0 brad0 force-pushed the clang_driver_haiku branch from b34a9d0 to d40ff6e Compare September 22, 2023 01:10
Co-authored-by: David Karoly <[email protected]>
Co-authored-by: Brad Smith <[email protected]>
@brad0 brad0 force-pushed the clang_driver_haiku branch from d40ff6e to 55445ca Compare September 22, 2023 02:52
@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
@brad0 brad0 deleted the clang_driver_haiku branch September 24, 2023 20:30
@X547
Copy link
Contributor

X547 commented Aug 24, 2024

Hello, one of this code authors here. Why I am seeing this patch only now?

static_cast<const toolchains::Haiku &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple::ArchType Arch = ToolChain.getArch();
const bool Static = Args.hasArg(options::OPT_static);
Copy link
Contributor

Choose a reason for hiding this comment

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

Haiku do not support fully statically linked executables like in Linux for reasons similar to Windows. Haiku do not have stable syscall interface, so applications must dynamically link to system libc (libroot.so), otherwise it may break after minor system update when some new syscall will be added or arguments will be changed. The same with GUI toolkit libraries. Protocol between application and GUI server is private and unstable, the only stable interface is dynamic library symbols.

Maybe static flag cab be used for 3rd-party libraries, but I am not sure.

if (Args.hasArg(options::OPT_rdynamic))
CmdArgs.push_back("-export-dynamic");
if (Shared)
CmdArgs.push_back("-shared");
Copy link
Contributor

Choose a reason for hiding this comment

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

-shared flag is already added below.

Haiku applications must be always linked with -shared flag, both runnable executables and shared libraries. PIE executables and executable TLS modes are not supported and may trigger wield crashes.

Haiku executable loading and startup sequence significantly differs from Linux. First Haiku kernel loads runtime_loader (program interpreter in Linux terminology) into newely created process and pass argv/environ arguments to it. Kernel itself do not load or even touch target executable to be executed, it only pass path to in in haiku_loader entry point.

Then haiku_loader loads target executable with something like dlopen(), get entry point from ELF header and run it (exit(entryPoint(argc, argv, environ));).

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.

4 participants