-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[clang][Driver][Darwin] Handle modern gcc/libstdc++ in Darwin toolchain #155219
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
base: main
Are you sure you want to change the base?
Conversation
A cross compiling gcc is generally installed outside of the sysroot, so we should always search the root system for our desired triple.
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-driver Author: Pierre Ossman (ThinLinc team) (CendioOssman) ChangesVarious fixes to make sure clang can find libstdc++ headers and library for current versions of gcc. Tested with a cross-compiler setup, but should hopefully work correctly for a native setup as well. Also adds support for statically linking libstdc++ and libgcc_s. Full diff: https://github.com/llvm/llvm-project/pull/155219.diff 4 Files Affected:
diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp
index 234683f2f4882..f71b875d08c11 100644
--- a/clang/lib/Driver/ToolChains/Darwin.cpp
+++ b/clang/lib/Driver/ToolChains/Darwin.cpp
@@ -681,6 +681,8 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_L);
+ getToolChain().AddFilePathLibArgs(Args, CmdArgs);
+
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
// Build the input file for -filelist (list of linker input files) in case we
// need it later
@@ -1177,7 +1179,31 @@ Tool *MachO::buildAssembler() const {
DarwinClang::DarwinClang(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
- : Darwin(D, Triple, Args) {}
+ : Darwin(D, Triple, Args), GCCInstallation(D) {
+ GCCInstallation.init(Triple, Args);
+ if (GCCInstallation.isValid()) {
+ StringRef LibDir = GCCInstallation.getParentLibPath();
+ StringRef TripleStr = GCCInstallation.getTriple().str();
+ const Generic_GCC::GCCVersion &Version = GCCInstallation.getVersion();
+
+ std::string Path;
+
+ // Try /gcc/$triple/$version/
+ Path = LibDir.str() + "/gcc/" + TripleStr.str() + "/" + Version.Text;
+ if (getVFS().exists(Path))
+ getFilePaths().push_back(Path);
+
+ // Try /gcc/$triple/lib/
+ Path = LibDir.str() + "/gcc/" + TripleStr.str() + "/lib";
+ if (getVFS().exists(Path))
+ getFilePaths().push_back(Path);
+
+ // Try /../$triple/lib/
+ Path = LibDir.str() + "/../" + TripleStr.str() + "/lib";
+ if (getVFS().exists(Path))
+ getFilePaths().push_back(Path);
+ }
+}
void DarwinClang::addClangWarningOptions(ArgStringList &CC1Args) const {
// Always error about undefined 'TARGET_OS_*' macros.
@@ -1547,14 +1573,6 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
return;
}
- // Reject -static-libgcc for now, we can deal with this when and if someone
- // cares. This is useful in situations where someone wants to statically link
- // something like libstdc++, and needs its runtime support routines.
- if (const Arg *A = Args.getLastArg(options::OPT_static_libgcc)) {
- getDriver().Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args);
- return;
- }
-
const SanitizerArgs &Sanitize = getSanitizerArgs(Args);
if (!Sanitize.needsSharedRt()) {
@@ -2793,9 +2811,52 @@ void AppleMachO::AddGnuCPlusPlusIncludePaths(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {}
+bool DarwinClang::addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple,
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ if (!getVFS().exists(IncludeDir))
+ return false;
+
+ // GPLUSPLUS_INCLUDE_DIR
+ addSystemInclude(DriverArgs, CC1Args, IncludeDir);
+ // GPLUSPLUS_TOOL_INCLUDE_DIR
+ addSystemInclude(DriverArgs, CC1Args, IncludeDir + "/" + Triple);
+ // GPLUSPLUS_BACKWARD_INCLUDE_DIR
+ addSystemInclude(DriverArgs, CC1Args, IncludeDir + "/backward");
+
+ return true;
+}
+
void DarwinClang::AddGnuCPlusPlusIncludePaths(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
+ if (GCCInstallation.isValid()) {
+ // This is a stripped down version of Generic_GCC::addGCCLibStdCxxIncludePaths.
+ StringRef LibDir = GCCInstallation.getParentLibPath();
+ StringRef TripleStr = GCCInstallation.getTriple().str();
+ const Generic_GCC::GCCVersion &Version = GCCInstallation.getVersion();
+
+ // Try /../$triple/include/c++/$version
+ if (addLibStdCXXIncludePaths(
+ LibDir.str() + "/../" + TripleStr + "/include/c++/" + Version.Text,
+ TripleStr, DriverArgs, CC1Args))
+ return;
+
+ // Try /gcc/$triple/$version/include/c++/
+ if (addLibStdCXXIncludePaths(LibDir.str() + "/gcc/" + TripleStr + "/" +
+ Version.Text + "/include/c++/",
+ TripleStr, DriverArgs, CC1Args))
+ return;
+
+ // Try /../include/c++/$version
+ if (addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text,
+ TripleStr, DriverArgs, CC1Args))
+ return;
+
+ getDriver().Diag(diag::warn_drv_libstdcxx_not_found);
+ return;
+ }
+
llvm::SmallString<128> UsrIncludeCxx = GetEffectiveSysroot(DriverArgs);
llvm::sys::path::append(UsrIncludeCxx, "usr", "include", "c++");
@@ -2848,39 +2909,57 @@ void AppleMachO::AddCXXStdlibLibArgs(const ArgList &Args,
break;
case ToolChain::CST_Libstdcxx:
- // Unfortunately, -lstdc++ doesn't always exist in the standard search path;
- // it was previously found in the gcc lib dir. However, for all the Darwin
- // platforms we care about it was -lstdc++.6, so we search for that
- // explicitly if we can't see an obvious -lstdc++ candidate.
+ AddGnuCPlusPlusStdlibLibArgs(Args, CmdArgs);
+ break;
+ }
+}
- // Check in the sysroot first.
- if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
- SmallString<128> P(A->getValue());
- llvm::sys::path::append(P, "usr", "lib", "libstdc++.dylib");
+void AppleMachO::AddGnuCPlusPlusStdlibLibArgs(
+ const ArgList &Args, ArgStringList &CmdArgs) const {
+ CmdArgs.push_back("-lstdc++");
+}
- if (!getVFS().exists(P)) {
- llvm::sys::path::remove_filename(P);
- llvm::sys::path::append(P, "libstdc++.6.dylib");
- if (getVFS().exists(P)) {
- CmdArgs.push_back(Args.MakeArgString(P));
+void DarwinClang::AddGnuCPlusPlusStdlibLibArgs(
+ const ArgList &Args, ArgStringList &CmdArgs) const {
+ if (GCCInstallation.isValid()) {
+ if (Args.hasArg(options::OPT_static_libstdcxx)) {
+ // ld64 doesn't support -Bstatic, so we need to find the actual library
+ for (const auto &Path : getFilePaths()) {
+ llvm::SmallString<128> UsrLibStdCxx(Path);
+ llvm::sys::path::append(UsrLibStdCxx, "libstdc++.a");
+ if (getVFS().exists(UsrLibStdCxx)) {
+ CmdArgs.push_back(Args.MakeArgString(UsrLibStdCxx));
+ // libstdcxx++ needs symbols from here
+ if (Args.hasArg(options::OPT_static_libgcc))
+ CmdArgs.push_back("-lgcc_eh");
+ else
+ CmdArgs.push_back("-lgcc_s.1");
return;
}
}
}
+ } else {
+ // Unfortunately, -lstdc++ doesn't always exist in the standard search path;
+ // it was previously found in the gcc lib dir. However, for all the Darwin
+ // platforms we care about it was -lstdc++.6, so we search for that
+ // explicitly if we can't see an obvious -lstdc++ candidate.
+
+ llvm::SmallString<128> UsrLibStdCxx = GetEffectiveSysroot(Args);
+ llvm::sys::path::append(UsrLibStdCxx, "usr", "lib", "libstdc++.dylib");
- // Otherwise, look in the root.
// FIXME: This should be removed someday when we don't have to care about
// 10.6 and earlier, where /usr/lib/libstdc++.dylib does not exist.
- if (!getVFS().exists("/usr/lib/libstdc++.dylib") &&
- getVFS().exists("/usr/lib/libstdc++.6.dylib")) {
- CmdArgs.push_back("/usr/lib/libstdc++.6.dylib");
- return;
+ if (!getVFS().exists(UsrLibStdCxx)) {
+ llvm::sys::path::remove_filename(UsrLibStdCxx);
+ llvm::sys::path::append(UsrLibStdCxx, "libstdc++.6.dylib");
+ if (getVFS().exists(UsrLibStdCxx)) {
+ CmdArgs.push_back(Args.MakeArgString(UsrLibStdCxx));
+ return;
+ }
}
-
- // Otherwise, let the linker search.
- CmdArgs.push_back("-lstdc++");
- break;
}
+
+ CmdArgs.push_back("-lstdc++");
}
void DarwinClang::AddCCKextLibArgs(const ArgList &Args,
@@ -3785,3 +3864,9 @@ void AppleMachO::printVerboseInfo(raw_ostream &OS) const {
CudaInstallation->print(OS);
RocmInstallation->print(OS);
}
+
+void DarwinClang::printVerboseInfo(raw_ostream &OS) const {
+ // Print the information about how we detected the GCC installation.
+ GCCInstallation.print(OS);
+ Darwin::printVerboseInfo(OS);
+}
diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h
index d1cfb6f4a5bf7..06990df8f7bbe 100644
--- a/clang/lib/Driver/ToolChains/Darwin.h
+++ b/clang/lib/Driver/ToolChains/Darwin.h
@@ -9,6 +9,7 @@
#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H
#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H
+#include "Gnu.h"
#include "clang/Basic/DarwinSDKInfo.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Driver/CudaInstallationDetector.h"
@@ -338,6 +339,9 @@ class LLVM_LIBRARY_VISIBILITY AppleMachO : public MachO {
virtual void
AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const;
+ virtual void
+ AddGnuCPlusPlusStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const;
};
/// Darwin - The base Darwin tool chain.
@@ -640,6 +644,9 @@ class LLVM_LIBRARY_VISIBILITY Darwin : public AppleMachO {
/// DarwinClang - The Darwin toolchain used by Clang.
class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin {
+protected:
+ Generic_GCC::GCCInstallationDetector GCCInstallation;
+
public:
DarwinClang(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args);
@@ -670,6 +677,8 @@ class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin {
void AddLinkARCArgs(const llvm::opt::ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) const override;
+ void printVerboseInfo(raw_ostream &OS) const override;
+
unsigned GetDefaultDwarfVersion() const override;
// Until dtrace (via CTF) and LLDB can deal with distributed debug info,
// Darwin defaults to standalone/full debug info.
@@ -686,9 +695,17 @@ class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin {
StringRef Sanitizer,
bool shared = true) const;
+ bool
+ addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple,
+ const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const;
+
void
AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const override;
+ void
+ AddGnuCPlusPlusStdlibLibArgs(const llvm::opt::ArgList &Args,
+ llvm::opt::ArgStringList &CmdArgs) const override;
bool AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args,
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index 01b146db24f3e..1d17fb6753bd9 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -1864,9 +1864,11 @@ static bool findBiarchMultilibs(const Driver &D,
.flag("-m64", /*Disallow=*/true)
.makeMultilib();
- // GCC toolchain for IAMCU doesn't have crtbegin.o, so look for libgcc.a.
+ // GCC toolchain for IAMCU and Darwin doesn't have crtbegin.o, so look for libgcc.a.
FilterNonExistent NonExistent(
- Path, TargetTriple.isOSIAMCU() ? "/libgcc.a" : "/crtbegin.o", D.getVFS());
+ Path,
+ (TargetTriple.isOSIAMCU() || TargetTriple.isOSDarwin()) ? "/libgcc.a" : "/crtbegin.o",
+ D.getVFS());
// Determine default multilib from: 32, 64, x32
// Also handle cases such as 64 on 32, 32 on 64, etc.
@@ -2161,10 +2163,8 @@ void Generic_GCC::GCCInstallationDetector::init(
// Next, look for prefix(es) that correspond to distribution-supplied gcc
// installations.
- if (D.SysRoot.empty()) {
- // Typically /usr.
- AddDefaultGCCPrefixes(TargetTriple, Prefixes, D.SysRoot);
- }
+ // Typically /usr.
+ AddDefaultGCCPrefixes(TargetTriple, Prefixes, "");
// Try to respect gcc-config on Gentoo if --gcc-toolchain is not provided.
// This avoids accidentally enforcing the system GCC version when using a
@@ -2556,6 +2556,11 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
return;
}
+ if (TargetTriple.isOSDarwin()) {
+ LibDirs.push_back("/lib");
+ return;
+ }
+
switch (TargetTriple.getArch()) {
case llvm::Triple::aarch64:
LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs));
diff --git a/clang/test/Driver/pic.c b/clang/test/Driver/pic.c
index f5d0745422790..24bc26937dda3 100644
--- a/clang/test/Driver/pic.c
+++ b/clang/test/Driver/pic.c
@@ -26,8 +26,8 @@
//
// CHECK-PIE-LD: "{{.*}}ld{{(.exe)?}}"
// CHECK-PIE-LD: "-pie"
-// CHECK-PIE-LD: "Scrt1.o" "crti.o" "crtbeginS.o"
-// CHECK-PIE-LD: "crtendS.o" "crtn.o"
+// CHECK-PIE-LD: "Scrt1.o" "crti.o" "{{.*}}crtbeginS.o"
+// CHECK-PIE-LD: "{{.*}}crtendS.o" "crtn.o"
//
// CHECK-NOPIE-LD: "-nopie"
//
|
Various fixes to make sure clang can find libstdc++ headers and library for current versions of gcc.
Tested with a cross-compiler setup, but should hopefully work correctly for a native setup as well.
Also adds support for statically linking libstdc++ and libgcc_s.