[clang] [Clang][Hexagon] Use --cstdlib flag to choose Picolibc (PR #183257)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 6 06:18:02 PDT 2026
https://github.com/quic-k updated https://github.com/llvm/llvm-project/pull/183257
>From ef0e8c971cfea0aaf8e70de5cfef417ec12ecf96 Mon Sep 17 00:00:00 2001
From: Kushal Pal <kushpal at qti.qualcomm.com>
Date: Thu, 2 Apr 2026 10:17:23 +0530
Subject: [PATCH] [Clang][Hexagon] Use --cstdlib flag to choose Picolibc
Update the Hexagon toolchain to use --cstdlib flag to allow users to
choose Picolibc as the C library.
This allows proper selection of C library when targeting
Hexagon environments.
Signed-off-by: Kushal Pal <kushpal at qti.qualcomm.com>
---
clang/lib/Driver/ToolChains/Hexagon.cpp | 124 ++++++++++--------
clang/lib/Driver/ToolChains/Hexagon.h | 10 +-
.../test/Driver/hexagon-toolchain-picolibc.c | 112 ++++++++++++++++
3 files changed, 188 insertions(+), 58 deletions(-)
create mode 100644 clang/test/Driver/hexagon-toolchain-picolibc.c
diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp
index 0148e1f9ac22a..4f5645c194986 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.cpp
+++ b/clang/lib/Driver/ToolChains/Hexagon.cpp
@@ -399,18 +399,26 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
if (IncStdLib && IncStartFiles) {
if (!IsShared) {
- if (HasStandalone) {
- SmallString<128> Crt0SA = LibraryDir;
- llvm::sys::path::append(Crt0SA, "crt0_standalone.o");
- CmdArgs.push_back(Args.MakeArgString(Crt0SA));
+ if (HTC.GetCStdlibType(Args) == ToolChain::CST_Picolibc) {
+ SmallString<128> Crt0 = LibraryDir;
+ llvm::sys::path::append(Crt0, "crt0-semihost.o");
+ CmdArgs.push_back(Args.MakeArgString(Crt0));
+ } else {
+ if (HasStandalone) {
+ SmallString<128> Crt0SA = LibraryDir;
+ llvm::sys::path::append(Crt0SA, "crt0_standalone.o");
+ CmdArgs.push_back(Args.MakeArgString(Crt0SA));
+ }
+ SmallString<128> Crt0 = LibraryDir;
+ llvm::sys::path::append(Crt0, "crt0.o");
+ CmdArgs.push_back(Args.MakeArgString(Crt0));
}
- SmallString<128> Crt0 = LibraryDir;
- llvm::sys::path::append(Crt0, "crt0.o");
- CmdArgs.push_back(Args.MakeArgString(Crt0));
}
- SmallString<128> Init = LibraryDir;
- llvm::sys::path::append(Init, UseShared ? "initS.o" : "init.o");
- CmdArgs.push_back(Args.MakeArgString(Init));
+ if (HTC.GetCStdlibType(Args) != ToolChain::CST_Picolibc) {
+ SmallString<128> Init = LibraryDir;
+ llvm::sys::path::append(Init, UseShared ? "initS.o" : "init.o");
+ CmdArgs.push_back(Args.MakeArgString(Init));
+ }
}
//----------------------------------------------------------------------------
@@ -442,12 +450,20 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
CmdArgs.push_back("--start-group");
if (!IsShared) {
- for (StringRef Lib : OsLibs)
- CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
+ if (HTC.GetCStdlibType(Args) == ToolChain::CST_Picolibc) {
+ CmdArgs.push_back("-lsemihost");
+ } else {
+ for (StringRef Lib : OsLibs)
+ CmdArgs.push_back(Args.MakeArgString("-l" + Lib));
+ }
if (!Args.hasArg(options::OPT_nolibc))
CmdArgs.push_back("-lc");
}
- CmdArgs.push_back("-lgcc");
+ if (HTC.GetCStdlibType(Args) == ToolChain::CST_Picolibc) {
+ CmdArgs.push_back("-lclang_rt.builtins");
+ } else {
+ CmdArgs.push_back("-lgcc");
+ }
CmdArgs.push_back("--end-group");
}
@@ -456,9 +472,11 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA,
// End files
//----------------------------------------------------------------------------
if (IncStdLib && IncStartFiles) {
- SmallString<128> Fini = LibraryDir;
- llvm::sys::path::append(Fini, UseShared ? "finiS.o" : "fini.o");
- CmdArgs.push_back(Args.MakeArgString(Fini));
+ if (HTC.GetCStdlibType(Args) != ToolChain::CST_Picolibc) {
+ SmallString<128> Fini = LibraryDir;
+ llvm::sys::path::append(Fini, UseShared ? "finiS.o" : "fini.o");
+ CmdArgs.push_back(Args.MakeArgString(Fini));
+ }
}
}
@@ -498,27 +516,26 @@ std::string HexagonToolChain::getHexagonTargetDir(
return std::string(Dir);
}
-SmallString<128> HexagonToolChain::getEffectiveSysRoot() const {
+SmallString<128>
+HexagonToolChain::getEffectiveSysRoot(const ArgList &Args) const {
const Driver &D = getDriver();
// The user-specified `--sysroot` always takes precedence.
if (!D.SysRoot.empty())
return SmallString<128>(D.SysRoot);
- // Otherwise, pick a path relative to the install directory. Try a triple
- // subdirectory first.
+ // Otherwise, pick a path relative to the install directory.
SmallString<128> Dir(getHexagonTargetDir(D.Dir, D.PrefixDirs));
- llvm::sys::path::append(Dir, getTriple().normalize());
- if (getVFS().exists(Dir))
- return Dir;
- // Otherwise, fall back to "../target/hexagon".
- Dir = getHexagonTargetDir(D.Dir, D.PrefixDirs);
- llvm::sys::path::append(Dir, "hexagon");
+ if (GetCStdlibType(Args) == ToolChain::CST_Picolibc) {
+ llvm::sys::path::append(Dir, "picolibc", getTriple().normalize());
+ } else {
+ llvm::sys::path::append(Dir, "hexagon");
+ }
return Dir;
}
void HexagonToolChain::getLibraryDir(const ArgList &Args,
llvm::SmallString<128> &Dir) const {
bool IsLinuxMusl = getTriple().isMusl() && getTriple().isOSLinux();
- const llvm::SmallString<128> SysRoot = getEffectiveSysRoot();
+ const llvm::SmallString<128> SysRoot = getEffectiveSysRoot(Args);
// Linux toolchain uses "usr/lib" but it also should accept "lib" in case an
// external sysroot is used. Similar logic is for include paths.
if (IsLinuxMusl) {
@@ -540,9 +557,10 @@ void HexagonToolChain::getLibraryDir(const ArgList &Args,
llvm::sys::path::append(Dir, "pic");
}
-void HexagonToolChain::getBaseIncludeDir(llvm::SmallString<128> &Dir) const {
+void HexagonToolChain::getBaseIncludeDir(const ArgList &Args,
+ llvm::SmallString<128> &Dir) const {
bool IsLinuxMusl = getTriple().isMusl() && getTriple().isOSLinux();
- const llvm::SmallString<128> SysRoot = getEffectiveSysRoot();
+ const llvm::SmallString<128> SysRoot = getEffectiveSysRoot(Args);
if (IsLinuxMusl) {
Dir = SysRoot;
llvm::sys::path::append(Dir, "usr", "include");
@@ -596,13 +614,12 @@ void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(),
std::back_inserter(RootDirs));
- std::string SysRoot(getEffectiveSysRoot());
+ std::string SysRoot(getEffectiveSysRoot(Args));
if (!llvm::is_contained(RootDirs, SysRoot))
RootDirs.push_back(SysRoot);
bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC);
- // Assume G0 with -shared.
- bool HasG0 = Args.hasArg(options::OPT_shared);
+ bool HasG0 = false;
if (auto G = getSmallDataThreshold(Args))
HasG0 = *G == 0;
@@ -610,11 +627,10 @@ void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args,
for (auto &Dir : RootDirs) {
std::string LibDir = Dir + "/lib";
std::string LibDirCpu = LibDir + '/' + CpuVer;
- if (HasG0) {
- if (HasPIC)
- LibPaths.push_back(LibDirCpu + "/G0/pic");
+ if (HasPIC)
+ LibPaths.push_back(LibDirCpu + "/G0/pic");
+ if (HasG0)
LibPaths.push_back(LibDirCpu + "/G0");
- }
LibPaths.push_back(LibDirCpu);
LibPaths.push_back(LibDir);
}
@@ -731,11 +747,11 @@ void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
}
if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) {
SmallString<128> CIncludeDir;
- getBaseIncludeDir(CIncludeDir);
+ getBaseIncludeDir(DriverArgs, CIncludeDir);
addExternCSystemInclude(DriverArgs, CC1Args, std::string(CIncludeDir));
bool IsLinuxMusl = getTriple().isMusl() && getTriple().isOSLinux();
if (IsLinuxMusl) {
- SmallString<128> LocalIncludeDir = getEffectiveSysRoot();
+ SmallString<128> LocalIncludeDir = getEffectiveSysRoot(DriverArgs);
llvm::sys::path::append(LocalIncludeDir, "usr", "local", "include");
addSystemInclude(DriverArgs, CC1Args, LocalIncludeDir);
}
@@ -744,29 +760,33 @@ void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
}
}
-void HexagonToolChain::addLibCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
- SmallString<128> Dir;
- getBaseIncludeDir(Dir);
- llvm::sys::path::append(Dir, "c++", "v1");
- addLibStdCXXIncludePaths(Dir, "", "", DriverArgs, CC1Args);
-}
+void HexagonToolChain::AddClangCXXStdlibIncludeArgs(
+ const ArgList &DriverArgs, ArgStringList &CC1Args) const {
+ if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
+ options::OPT_nostdincxx))
+ return;
-void HexagonToolChain::addLibStdCxxIncludePaths(
- const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const {
SmallString<128> Dir;
- getBaseIncludeDir(Dir);
- llvm::sys::path::append(Dir, "c++");
- addLibStdCXXIncludePaths(Dir, "", "", DriverArgs, CC1Args);
+ getBaseIncludeDir(DriverArgs, Dir);
+
+ CXXStdlibType Type = GetCXXStdlibType(DriverArgs);
+ switch (Type) {
+ case ToolChain::CST_Libcxx:
+ llvm::sys::path::append(Dir, "c++", "v1");
+ addSystemInclude(DriverArgs, CC1Args, Dir);
+ break;
+ case ToolChain::CST_Libstdcxx:
+ llvm::sys::path::append(Dir, "c++");
+ addSystemInclude(DriverArgs, CC1Args, Dir);
+ break;
+ }
}
ToolChain::CXXStdlibType
HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const {
Arg *A = Args.getLastArg(options::OPT_stdlib_EQ);
if (!A) {
- if (getTriple().isMusl())
+ if (getTriple().isMusl() || GetCStdlibType(Args) == ToolChain::CST_Picolibc)
return ToolChain::CST_Libcxx;
else
return ToolChain::CST_Libstdcxx;
diff --git a/clang/lib/Driver/ToolChains/Hexagon.h b/clang/lib/Driver/ToolChains/Hexagon.h
index 63dd7d78395e7..6cb66a8c54e60 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.h
+++ b/clang/lib/Driver/ToolChains/Hexagon.h
@@ -81,13 +81,10 @@ class LLVM_LIBRARY_VISIBILITY HexagonToolChain : public Linux {
void
AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
- void addLibStdCxxIncludePaths(
+ void AddClangCXXStdlibIncludeArgs(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
- void addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
- llvm::opt::ArgStringList &CC1Args) const override;
-
const char *getDefaultLinker() const override {
return getTriple().isMusl() ? "ld.lld" : "hexagon-link";
}
@@ -102,8 +99,9 @@ class LLVM_LIBRARY_VISIBILITY HexagonToolChain : public Linux {
std::string getHexagonTargetDir(
const std::string &InstalledDir,
const SmallVectorImpl<std::string> &PrefixDirs) const;
- SmallString<128> getEffectiveSysRoot() const;
- void getBaseIncludeDir(llvm::SmallString<128> &) const;
+ SmallString<128> getEffectiveSysRoot(const llvm::opt::ArgList &Args) const;
+ void getBaseIncludeDir(const llvm::opt::ArgList &Args,
+ llvm::SmallString<128> &) const;
void getLibraryDir(const llvm::opt::ArgList &Args,
llvm::SmallString<128> &) const;
void getHexagonLibraryPaths(const llvm::opt::ArgList &Args,
diff --git a/clang/test/Driver/hexagon-toolchain-picolibc.c b/clang/test/Driver/hexagon-toolchain-picolibc.c
new file mode 100644
index 0000000000000..60b640469941c
--- /dev/null
+++ b/clang/test/Driver/hexagon-toolchain-picolibc.c
@@ -0,0 +1,112 @@
+// REQUIRES: hexagon-registered-target
+
+// -----------------------------------------------------------------------------
+// Test standard include paths
+// -----------------------------------------------------------------------------
+// RUN: %clang -### --target=hexagon-none-elf --cstdlib=picolibc \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin %s 2>&1 | FileCheck -check-prefix=CHECK-C-INCLUDES %s
+// CHECK-C-INCLUDES: "-cc1" {{.*}} "-internal-isystem" "{{.*}}/lib/clang/{{[0-9]+}}/include"
+// CHECK-C-INCLUDES: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/picolibc/hexagon-unknown-none-elf/include"
+
+// RUN: %clangxx -### --target=hexagon-none-elf --cstdlib=picolibc \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin %s 2>&1 | FileCheck -check-prefix=CHECK-CXX-INCLUDES %s
+// CHECK-CXX-INCLUDES: "-cc1" {{.*}} "-internal-isystem" "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/picolibc/hexagon-unknown-none-elf/include/c++/v1"
+// CHECK-CXX-INCLUDES: "-internal-isystem" "{{.*}}/lib/clang/{{[0-9]+}}/include"
+// CHECK-CXX-INCLUDES: "-internal-externc-isystem" "{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/picolibc/hexagon-unknown-none-elf/include"
+// -----------------------------------------------------------------------------
+// Passing start files for Picolibc
+// -----------------------------------------------------------------------------
+// RUN: %clang --target=hexagon-none-elf --cstdlib=picolibc -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-STARTUP
+// CHECK-STARTUP: "{{.*}}crt0-semihost.o"
+//
+// RUN: %clang --target=hexagon-none-elf --cstdlib=picolibc -nostartfiles -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-NOSTART
+// CHECK-NOSTART-NOT: "{{.*}}crt0-semihost.o"
+// -----------------------------------------------------------------------------
+// Passing -nostdlib, -nostartfiles, -nodefaultlibs, -nolibc
+// -----------------------------------------------------------------------------
+// RUN: %clangxx -### --target=hexagon-none-elf --cstdlib=picolibc \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
+// RUN: -nostdlib %s 2>&1 | FileCheck -check-prefix=CHECK-NOSTDLIB %s
+// CHECK-NOSTDLIB: "-cc1"
+// CHECK-NOSTDLIB: {{hexagon-link|ld}}
+// CHECK-NOSTDLIB-NOT: {{.*}}crt0-semihost.o
+// CHECK-NOSTDLIB-NOT: "-lc++"
+// CHECK-NOSTDLIB-NOT: "-lm"
+// CHECK-NOSTDLIB-NOT: "--start-group"
+// CHECK-NOSTDLIB-NOT: "-lsemihost"
+// CHECK-NOSTDLIB-NOT: "-lc"
+// CHECK-NOSTDLIB-NOT: "-l{{(clang_rt\.builtins)}}"
+// CHECK-NOSTDLIB-NOT: "--end-group"
+
+// RUN: %clangxx -### --target=hexagon-none-elf --cstdlib=picolibc \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
+// RUN: -nostartfiles %s 2>&1 | FileCheck -check-prefix=CHECK-NOSTARTFILES %s
+// CHECK-NOSTARTFILES: "-cc1"
+// CHECK-NOSTARTFILES: {{hexagon-link|ld}}
+// CHECK-NOSTARTFILES-NOT: {{.*}}crt0-semihost.o
+// CHECK-NOSTARTFILES: "-lc++" "-lc++abi" "-lunwind" "-lm" "--start-group" "-lsemihost" "-lc" "-lclang_rt.builtins" "--end-group"
+
+// RUN: %clangxx -### --target=hexagon-none-elf --cstdlib=picolibc \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv60 \
+// RUN: -nodefaultlibs %s 2>&1 | FileCheck -check-prefix=CHECK-NODEFAULTLIBS %s
+// CHECK-NODEFAULTLIBS: "-cc1"
+// CHECK-NODEFAULTLIBS: {{hexagon-link|ld}}
+// CHECK-NODEFAULTLIBS: "{{.*}}crt0-semihost.o"
+// CHECK-NODEFAULTLIBS-NOT: "-lc++"
+// CHECK-NODEFAULTLIBS-NOT: "-lm"
+// CHECK-NODEFAULTLIBS-NOT: "--start-group"
+// CHECK-NODEFAULTLIBS-NOT: "-lsemihost"
+// CHECK-NODEFAULTLIBS-NOT: "-lc"
+// CHECK-NODEFAULTLIBS-NOT: "-lclang_rt.builtins"
+// CHECK-NODEFAULTLIBS-NOT: "--end-group"
+
+// RUN: %clangxx -### --target=hexagon-none-elf --cstdlib=picolibc \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin -mcpu=hexagonv60 \
+// RUN: -nolibc %s 2>&1 | FileCheck -check-prefix=CHECK-NOLIBC %s
+// CHECK-NOLIBC: "-cc1"
+// CHECK-NOLIBC: hexagon-link
+// CHECK-NOLIBC-SAME: "{{.*}}crt0-semihost.o"
+// CHECK-NOLIBC-SAME: "-lc++"
+// CHECK-NOLIBC-SAME: "-lm"
+// CHECK-NOLIBC-SAME: "--start-group"
+// CHECK-NOLIBC-SAME: "-lsemihost"
+// CHECK-NOLIBC-NOT: "-lc"
+// CHECK-NOLIBC-SAME: "-lclang_rt.builtins"
+// CHECK-NOLIBC-SAME: "--end-group"
+// -----------------------------------------------------------------------------
+// Force compiler-rt when Picolibc is selected
+// -----------------------------------------------------------------------------
+// RUN: %clang --target=hexagon-none-elf --cstdlib=picolibc -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-RTLIB
+// RUN: %clangxx --target=hexagon-none-elf --cstdlib=picolibc -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-RTLIB
+// CHECK-RTLIB: "-lclang_rt.builtins"
+// -----------------------------------------------------------------------------
+// Force libunwind when Picolibc is selected
+// -----------------------------------------------------------------------------
+// RUN: %clang --target=hexagon-none-elf --cstdlib=picolibc -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-C-UNWIND
+// RUN: %clangxx --target=hexagon-none-elf --cstdlib=picolibc -### %s 2>&1 | FileCheck %s --check-prefix=CHECK-CXX-UNWIND
+// CHECK-C-UNWIND-NOT: "-lunwind"
+// CHECK-CXX-UNWIND: "-lunwind"
+// -----------------------------------------------------------------------------
+// Library search paths
+// -----------------------------------------------------------------------------
+// RUN: %clang --target=hexagon-none-elf --cstdlib=picolibc \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv68 -### %s 2>&1 | FileCheck -check-prefix=CHECK-LIBPATHS %s
+// CHECK-LIBPATHS: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/picolibc/hexagon-unknown-none-elf/lib/v68"
+// CHECK-LIBPATHS-NOT: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/picolibc/hexagon-unknown-none-elf/lib/v68/G0"
+
+// RUN: %clang --target=hexagon-none-elf --cstdlib=picolibc \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv68 -G0 -### %s 2>&1 | FileCheck -check-prefix=CHECK-LIBPATHS-G0 %s
+// CHECK-LIBPATHS-G0: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/picolibc/hexagon-unknown-none-elf/lib/v68/G0"
+// CHECK-LIBPATHS-G0: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/picolibc/hexagon-unknown-none-elf/lib/v68"
+
+// RUN: %clang --target=hexagon-none-elf --cstdlib=picolibc \
+// RUN: -ccc-install-dir %S/Inputs/hexagon_tree/Tools/bin \
+// RUN: -mcpu=hexagonv68 -fpic -### %s 2>&1 | FileCheck -check-prefix=CHECK-LIBPATHS-PIC %s
+// CHECK-LIBPATHS-PIC: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/picolibc/hexagon-unknown-none-elf/lib/v68/G0/pic"
+// CHECK-LIBPATHS-PIC: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/picolibc/hexagon-unknown-none-elf/lib/v68/G0"
+// CHECK-LIBPATHS-PIC: "-L{{.*}}/Inputs/hexagon_tree/Tools/bin/../target/picolibc/hexagon-unknown-none-elf/lib/v68"
More information about the cfe-commits
mailing list