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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions clang/lib/Driver/ToolChains/Gnu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2224,6 +2224,12 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
const llvm::Triple &TargetTriple, SmallVectorImpl<std::string> &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
Expand Down
129 changes: 124 additions & 5 deletions clang/lib/Driver/ToolChains/Haiku.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,141 @@
#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<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.

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");
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));).

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");

assert((Output.isFilename() || Output.isNothing()) && "Invalid output.");
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
}

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() && 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");
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.

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, 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<Command>(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,
Expand Down Expand Up @@ -128,8 +249,6 @@ void Haiku::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
concat(getDriver().SysRoot, "/boot/system/develop/headers/c++/v1"));
}

void Haiku::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
addLibStdCXXIncludePaths(concat(getDriver().SysRoot, "/boot/system/develop/headers/c++"),
getTriple().str(), "", DriverArgs, CC1Args);
}
Tool *Haiku::buildLinker() const { return new tools::haiku::Linker(*this); }

bool Haiku::HasNativeLLVMSupport() const { return true; }
29 changes: 26 additions & 3 deletions clang/lib/Driver/ToolChains/Haiku.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,53 @@

namespace clang {
namespace driver {
namespace tools {

/// Directly call GNU Binutils assembler and linker
namespace haiku {
class LLVM_LIBRARY_VISIBILITY Linker final : 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 {
public:
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;
void addLibCxxIncludePaths(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
void addLibStdCxxIncludePaths(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;

unsigned GetDefaultDwarfVersion() const override { return 4; }

bool GetDefaultStandaloneDebug() const override { return true; }

protected:
Tool *buildLinker() const override;
};

} // end namespace toolchains
Expand Down
29 changes: 29 additions & 0 deletions clang/test/Driver/haiku.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,32 @@
// 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" "--push-state" "--as-needed" "-lgcc_s" "--no-as-needed" "--pop-state"
// CHECK-LD-X86_64-SAME: {{^}} "-lroot"
// CHECK-LD-X86_64-SAME: {{^}} "-lgcc" "--push-state" "--as-needed" "-lgcc_s" "--no-as-needed" "--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"
3 changes: 2 additions & 1 deletion clang/test/Driver/haiku.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
// RUN: %clangxx --target=x86_64-unknown-haiku --stdlib=libstdc++ -### %s 2>&1 \
// RUN: --sysroot=%S/Inputs/haiku_x86_64_tree \
// RUN: | FileCheck --check-prefix=CHECK-LIBSTDCXX-HEADER-PATH %s
// CHECK-LIBSTDCXX-HEADER-PATH: "-internal-isystem" "[[SYSROOT:[^"]+]]/boot/system/develop/headers/c++"
// CHECK-LIBSTDCXX-HEADER-PATH: "-internal-isystem" "[[SYSROOT:[^"]+]]/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/../../../gcc/x86_64-unknown-haiku/13.2.0/include/c++/"
// CHECK-LIBSTDCXX-HEADER-PATH-SAME: "-internal-isystem" "[[SYSROOT:[^"]+]]/boot/system/develop/tools/lib/gcc/x86_64-unknown-haiku/13.2.0/../../../gcc/x86_64-unknown-haiku/13.2.0/include/c++//backward"

// Check the C++ header path (when using libc++)
// RUN: %clangxx --target=x86_64-unknown-haiku --stdlib=libc++ -### %s 2>&1 \
Expand Down