Skip to content

Commit 9b65296

Browse files
authored
driver: Pick a better default C cross compiler on non-Apple Posix (#4983)
Try to pick a better default instead of `cc` when cross-compiling. When targeting Linux on a non-Linux build machine, for example, try to pick `cc` from: - `<triple>-gcc` - `<triple>-clang` - `clang --target=<triple>` This should be a better UX when cross-compiling with simpler build systems like `dub` or even without one at all, offering a out-of-the-box functional setup, on most systems. The advantage to performing this check in the compiler code as opposed to hardcoding a default value in the config file is that: 1. Multiple programs can be searched, instead of just one 2. The `$CC` value continues to be respected, which keeps more advanced cross-compiling setups working (for example Meson) Signed-off-by: Andrei Horodniceanu <[email protected]>
1 parent d49d748 commit 9b65296

File tree

8 files changed

+112
-41
lines changed

8 files changed

+112
-41
lines changed

.github/actions/5a-android-x86/action.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,4 @@ runs:
3030
"${flags[@]}" \
3131
ANDROID_ABI="$abi" # override the one in CROSS_CMAKE_FLAGS
3232
33-
# TODO: append default -gcc switch (x86_64-linux-android30-clang, i686-linux-android29-clang)
3433
cat install/etc/ldc2.conf/55-target-android-$arch.conf

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
- ldc2.conf can now be a directory. All the files inside it, ordered naturally, will be concatenated and treated like a big config. (#4954)
77
- Running `ldc-build-runtime --installWithSuffix` now includes installing a target-specific .conf file to that directory. (#4978)
88
- **Breaking change for ldc2.conf cmake generation**: The `cmake` build process now generates the `ldc2.conf` and `ldc2_install.conf` as directories. `ldc2*.conf.in` and `ADDITIONAL_DEFAULT_LDC_SWITCHES` have been removed, if you need to add switches check out `makeConfSection` in `LdcConfig.cmake`. (#4954)
9+
- When cross-compiling, the fallback value for the (cross) C compiler will be picked based on some heuristics.
10+
The old behavior was to default to `cc`.
11+
As an example, when cross-compiling for `aarch64-linux-gnu` the compilers that are checked are:
12+
- `aarch64-linux-gnu-gcc`
13+
- `aarch64-linux-gnu-clang`
14+
- `clang --target=aarch64-linux-gnu`
915
- The prebuilt arm64/universal macOS packages additionally bundle the arm64 iOS-*simulator* libraries, for out-of-the-box cross-compilation support via e.g. `-mtriple=arm64-apple-ios12.0-simulator`. (#4974)
1016

1117
#### Platform support

driver/cpreprocessor.cpp

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -30,33 +30,6 @@ const char *getPathToImportc_h(Loc loc) {
3030
return cached;
3131
}
3232

33-
const std::string &getCC(bool isMSVC,
34-
std::vector<std::string> &additional_args) {
35-
static std::string cached_cc;
36-
static std::vector<std::string> cached_args;
37-
if (cached_cc.empty()) {
38-
std::string fallback = "cc";
39-
if (isMSVC) {
40-
#ifdef _WIN32
41-
// by default, prefer clang-cl.exe (if in PATH) over cl.exe
42-
// (e.g., no echoing of source filename being preprocessed to stderr)
43-
auto found = llvm::sys::findProgramByName("clang-cl.exe");
44-
if (found) {
45-
fallback = found.get();
46-
} else {
47-
fallback = "cl.exe";
48-
}
49-
#else
50-
fallback = "clang-cl";
51-
#endif
52-
}
53-
cached_cc = getGcc(cached_args, fallback.c_str());
54-
}
55-
56-
additional_args.insert(additional_args.end(), cached_args.cbegin(), cached_args.cend());
57-
return cached_cc;
58-
}
59-
6033
FileName getOutputPath(Loc loc, const char *csrcfile) {
6134
llvm::SmallString<64> buffer;
6235

@@ -96,7 +69,7 @@ FileName runCPreprocessor(FileName csrcfile, Loc loc, OutBuffer &defines) {
9669
FileName ipath = getOutputPath(loc, csrcfile.toChars());
9770

9871
std::vector<std::string> args;
99-
const std::string &cc = getCC(isMSVC, args);
72+
const std::string &cc = getCC(args);
10073

10174
args.push_back(isMSVC ? "/std:c11" : "-std=c11");
10275

driver/linker-gcc.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,7 @@ int linkObjToBinaryGcc(llvm::StringRef outputPath,
844844
tool = getProgram("wasm-ld", &opts::linker);
845845
} else {
846846
argsBuilder = std::make_unique<ArgsBuilder>();
847-
tool = getGcc(argsBuilder->args);
847+
tool = getCC(argsBuilder->args);
848848
}
849849

850850
// build arguments

driver/toobj.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ void codegenModule(llvm::TargetMachine &Target, llvm::Module &m,
156156
static void assemble(const std::string &asmpath, const std::string &objpath) {
157157
std::vector<std::string> args;
158158
std::string gcc;
159-
gcc = getGcc(args);
159+
gcc = getCC(args);
160160

161161
args.push_back("-O3");
162162
args.push_back("-c");

driver/tool.cpp

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121
#include "llvm/Support/Path.h"
2222
#include "llvm/Target/TargetMachine.h"
2323

24+
#if LDC_LLVM_VER >= 1600
25+
#include "llvm/TargetParser/Host.h"
26+
#else
27+
#include "llvm/Support/Host.h"
28+
#endif
29+
2430
#ifdef _WIN32
2531
#include <Windows.h>
2632
#endif
@@ -52,6 +58,69 @@ static std::string findProgramByName(llvm::StringRef name) {
5258

5359
//////////////////////////////////////////////////////////////////////////////
5460

61+
namespace {
62+
llvm::SmallVector<std::string, 2> findCCFallback() {
63+
const auto &triple = *global.params.targetTriple;
64+
llvm::Triple nativeTriple{ llvm::sys::getDefaultTargetTriple() };
65+
const auto isNativeBuild =
66+
opts::mTargetTriple.empty() || triple.isCompatibleWith(nativeTriple);
67+
68+
llvm::SmallVector<llvm::SmallVector<std::string, 2>, 3> choices;
69+
if (triple.isWindowsMSVCEnvironment()) {
70+
#ifdef _WIN32
71+
// by default, prefer clang-cl.exe (if in PATH) over cl.exe
72+
// (e.g., no echoing of source filename being preprocessed to stderr)
73+
choices = {
74+
{ "clang-cl.exe" },
75+
{ "cl.exe" },
76+
};
77+
#else
78+
choices = { { "clang-cl" } };
79+
#endif
80+
} else if (isNativeBuild) {
81+
choices = { { "cc" } };
82+
} else if (triple.isOSDarwin()) {
83+
// Cross-compiling for Apple is most probably done on an Apple machine
84+
choices = { { "cc" } };
85+
} else {
86+
const auto tripleString = triple.getTriple();
87+
choices = {
88+
{ tripleString + "-gcc" },
89+
{ tripleString + "-clang" },
90+
{ "clang", "--target=" + tripleString },
91+
};
92+
}
93+
94+
95+
const auto verbose = global.params.v.verbose;
96+
const auto logCross = verbose && !isNativeBuild;
97+
if (logCross) message("Trying to find a C cross-compiler");
98+
99+
for (auto &choice : choices) {
100+
auto fullPath = findProgramByName(choice[0]);
101+
if (fullPath.empty()) {
102+
if (logCross) message("Did not find C cross-compiler: `%s`", choice[0].c_str());
103+
continue;
104+
}
105+
106+
if (logCross) message("Found C cross-compiler: `%s`", fullPath.c_str());
107+
choice[0] = fullPath;
108+
return choice;
109+
}
110+
111+
if (isNativeBuild) {
112+
error(Loc(), "could not find C compiler `%s`", choices[0][0].c_str());
113+
} else {
114+
error(Loc(), "could not find a C cross-compiler for this cross-compilation");
115+
tip("make sure you have a compiler like `%s` installed and set $CC or pass -gcc accordingly", choices[0][0].c_str());
116+
}
117+
118+
fatal();
119+
}
120+
} // anonymous namespace
121+
122+
////////////////////////////////////////////////////////////////////////////////
123+
55124
std::string getProgram(const char *fallbackName,
56125
const llvm::cl::opt<std::string> *opt,
57126
const char *envVar) {
@@ -76,19 +145,24 @@ std::string getProgram(const char *fallbackName,
76145

77146
////////////////////////////////////////////////////////////////////////////////
78147

79-
std::string getGcc(std::vector<std::string> &additional_args,
80-
const char *fallback) {
148+
namespace {
149+
std::string getCCImpl(std::vector<std::string> &additional_args) {
150+
if (!gcc.empty())
151+
return getProgram(nullptr, &gcc);
152+
153+
std::string cc = env::get("CC");
154+
if (cc.empty()) {
155+
auto fallback = findCCFallback();
156+
additional_args.insert(additional_args.end(), fallback.begin() + 1, fallback.end());
157+
return fallback[0];
158+
}
159+
81160
#ifdef _WIN32
82161
// spaces in $CC are to be expected on Windows
83162
// (e.g., `C:\Program Files\LLVM\bin\clang-cl.exe`)
84-
return getProgram(fallback, &gcc, "CC");
163+
return getProgram(cc.c_str(), &gcc);
85164
#else
86165
// Posix: in case $CC contains spaces split it into a command and arguments
87-
std::string cc = env::get("CC");
88-
if (cc.empty())
89-
return getProgram(fallback, &gcc);
90-
91-
// $CC is set so fallback doesn't matter anymore.
92166
if (cc.find(' ') == cc.npos)
93167
return getProgram(cc.c_str(), &gcc);
94168

@@ -103,6 +177,18 @@ std::string getGcc(std::vector<std::string> &additional_args,
103177
return getProgram(args[0].str().c_str(), &gcc);
104178
#endif
105179
}
180+
} // anonymous namespace
181+
182+
std::string getCC(std::vector<std::string> &additional_args) {
183+
static std::string cachedResult;
184+
static std::vector<std::string> cachedArgs;
185+
186+
if (cachedResult.empty())
187+
cachedResult = getCCImpl(cachedArgs);
188+
189+
additional_args.insert(additional_args.end(), cachedArgs.begin(), cachedArgs.end());
190+
return cachedResult;
191+
}
106192

107193
////////////////////////////////////////////////////////////////////////////////
108194

driver/tool.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ namespace opts {
2525
extern llvm::cl::opt<std::string> linker;
2626
}
2727

28-
std::string getGcc(std::vector<std::string> &additional_args,
29-
const char *fallback = "cc");
28+
std::string getCC(std::vector<std::string> &additional_args);
3029
void appendTargetArgsForGcc(std::vector<std::string> &args);
3130

3231
std::string getProgram(const char *fallbackName,

tests/driver/cross_cc_fallback.d

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: env PATH= CC= not %ldc -mtriple aarch64-unknown-linux-gnut64 -v -defaultlib= %s 2>&1 | FileCheck %s
2+
3+
// CHECK-DAG: aarch64-unknown-linux-gnut64-gcc
4+
// CHECK-DAG: aarch64-unknown-linux-gnut64-clang
5+
6+
// UNSUPPORTED: Windows
7+
8+
extern(C) void main () {}

0 commit comments

Comments
 (0)