diff --git a/.github/actions/5a-android-x86/action.yml b/.github/actions/5a-android-x86/action.yml index 30ac66492f..b83c881e85 100644 --- a/.github/actions/5a-android-x86/action.yml +++ b/.github/actions/5a-android-x86/action.yml @@ -30,5 +30,4 @@ runs: "${flags[@]}" \ ANDROID_ABI="$abi" # override the one in CROSS_CMAKE_FLAGS - # TODO: append default -gcc switch (x86_64-linux-android30-clang, i686-linux-android29-clang) cat install/etc/ldc2.conf/55-target-android-$arch.conf diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bf84849da..f49165a547 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ - ldc2.conf can now be a directory. All the files inside it, ordered naturally, will be concatenated and treated like a big config. (#4954) - Running `ldc-build-runtime --installWithSuffix` now includes installing a target-specific .conf file to that directory. (#4978) - **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) +- When cross-compiling, the fallback value for the (cross) C compiler will be picked based on some heuristics. + The old behavior was to default to `cc`. + As an example, when cross-compiling for `aarch64-linux-gnu` the compilers that are checked are: + - `aarch64-linux-gnu-gcc` + - `aarch64-linux-gnu-clang` + - `clang --target=aarch64-linux-gnu` - 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) #### Platform support diff --git a/driver/cpreprocessor.cpp b/driver/cpreprocessor.cpp index 8307dbca76..fff0e5d223 100644 --- a/driver/cpreprocessor.cpp +++ b/driver/cpreprocessor.cpp @@ -30,33 +30,6 @@ const char *getPathToImportc_h(Loc loc) { return cached; } -const std::string &getCC(bool isMSVC, - std::vector &additional_args) { - static std::string cached_cc; - static std::vector cached_args; - if (cached_cc.empty()) { - std::string fallback = "cc"; - if (isMSVC) { -#ifdef _WIN32 - // by default, prefer clang-cl.exe (if in PATH) over cl.exe - // (e.g., no echoing of source filename being preprocessed to stderr) - auto found = llvm::sys::findProgramByName("clang-cl.exe"); - if (found) { - fallback = found.get(); - } else { - fallback = "cl.exe"; - } -#else - fallback = "clang-cl"; -#endif - } - cached_cc = getGcc(cached_args, fallback.c_str()); - } - - additional_args.insert(additional_args.end(), cached_args.cbegin(), cached_args.cend()); - return cached_cc; -} - FileName getOutputPath(Loc loc, const char *csrcfile) { llvm::SmallString<64> buffer; @@ -96,7 +69,7 @@ FileName runCPreprocessor(FileName csrcfile, Loc loc, OutBuffer &defines) { FileName ipath = getOutputPath(loc, csrcfile.toChars()); std::vector args; - const std::string &cc = getCC(isMSVC, args); + const std::string &cc = getCC(args); args.push_back(isMSVC ? "/std:c11" : "-std=c11"); diff --git a/driver/linker-gcc.cpp b/driver/linker-gcc.cpp index be9ec75b58..d3ad82b346 100644 --- a/driver/linker-gcc.cpp +++ b/driver/linker-gcc.cpp @@ -844,7 +844,7 @@ int linkObjToBinaryGcc(llvm::StringRef outputPath, tool = getProgram("wasm-ld", &opts::linker); } else { argsBuilder = std::make_unique(); - tool = getGcc(argsBuilder->args); + tool = getCC(argsBuilder->args); } // build arguments diff --git a/driver/toobj.cpp b/driver/toobj.cpp index 5b5a5ec169..f9789452f4 100644 --- a/driver/toobj.cpp +++ b/driver/toobj.cpp @@ -156,7 +156,7 @@ void codegenModule(llvm::TargetMachine &Target, llvm::Module &m, static void assemble(const std::string &asmpath, const std::string &objpath) { std::vector args; std::string gcc; - gcc = getGcc(args); + gcc = getCC(args); args.push_back("-O3"); args.push_back("-c"); diff --git a/driver/tool.cpp b/driver/tool.cpp index 6e25c4ce8c..e64ec96cbd 100644 --- a/driver/tool.cpp +++ b/driver/tool.cpp @@ -21,6 +21,12 @@ #include "llvm/Support/Path.h" #include "llvm/Target/TargetMachine.h" +#if LDC_LLVM_VER >= 1600 +#include "llvm/TargetParser/Host.h" +#else +#include "llvm/Support/Host.h" +#endif + #ifdef _WIN32 #include #endif @@ -52,6 +58,69 @@ static std::string findProgramByName(llvm::StringRef name) { ////////////////////////////////////////////////////////////////////////////// +namespace { +llvm::SmallVector findCCFallback() { + const auto &triple = *global.params.targetTriple; + llvm::Triple nativeTriple{ llvm::sys::getDefaultTargetTriple() }; + const auto isNativeBuild = + opts::mTargetTriple.empty() || triple.isCompatibleWith(nativeTriple); + + llvm::SmallVector, 3> choices; + if (triple.isWindowsMSVCEnvironment()) { +#ifdef _WIN32 + // by default, prefer clang-cl.exe (if in PATH) over cl.exe + // (e.g., no echoing of source filename being preprocessed to stderr) + choices = { + { "clang-cl.exe" }, + { "cl.exe" }, + }; +#else + choices = { { "clang-cl" } }; +#endif + } else if (isNativeBuild) { + choices = { { "cc" } }; + } else if (triple.isOSDarwin()) { + // Cross-compiling for Apple is most probably done on an Apple machine + choices = { { "cc" } }; + } else { + const auto tripleString = triple.getTriple(); + choices = { + { tripleString + "-gcc" }, + { tripleString + "-clang" }, + { "clang", "--target=" + tripleString }, + }; + } + + + const auto verbose = global.params.v.verbose; + const auto logCross = verbose && !isNativeBuild; + if (logCross) message("Trying to find a C cross-compiler"); + + for (auto &choice : choices) { + auto fullPath = findProgramByName(choice[0]); + if (fullPath.empty()) { + if (logCross) message("Did not find C cross-compiler: `%s`", choice[0].c_str()); + continue; + } + + if (logCross) message("Found C cross-compiler: `%s`", fullPath.c_str()); + choice[0] = fullPath; + return choice; + } + + if (isNativeBuild) { + error(Loc(), "could not find C compiler `%s`", choices[0][0].c_str()); + } else { + error(Loc(), "could not find a C cross-compiler for this cross-compilation"); + tip("make sure you have a compiler like `%s` installed and set $CC or pass -gcc accordingly", choices[0][0].c_str()); + } + + fatal(); +} +} // anonymous namespace + +//////////////////////////////////////////////////////////////////////////////// + std::string getProgram(const char *fallbackName, const llvm::cl::opt *opt, const char *envVar) { @@ -76,19 +145,24 @@ std::string getProgram(const char *fallbackName, //////////////////////////////////////////////////////////////////////////////// -std::string getGcc(std::vector &additional_args, - const char *fallback) { +namespace { +std::string getCCImpl(std::vector &additional_args) { + if (!gcc.empty()) + return getProgram(nullptr, &gcc); + + std::string cc = env::get("CC"); + if (cc.empty()) { + auto fallback = findCCFallback(); + additional_args.insert(additional_args.end(), fallback.begin() + 1, fallback.end()); + return fallback[0]; + } + #ifdef _WIN32 // spaces in $CC are to be expected on Windows // (e.g., `C:\Program Files\LLVM\bin\clang-cl.exe`) - return getProgram(fallback, &gcc, "CC"); + return getProgram(cc.c_str(), &gcc); #else // Posix: in case $CC contains spaces split it into a command and arguments - std::string cc = env::get("CC"); - if (cc.empty()) - return getProgram(fallback, &gcc); - - // $CC is set so fallback doesn't matter anymore. if (cc.find(' ') == cc.npos) return getProgram(cc.c_str(), &gcc); @@ -103,6 +177,18 @@ std::string getGcc(std::vector &additional_args, return getProgram(args[0].str().c_str(), &gcc); #endif } +} // anonymous namespace + +std::string getCC(std::vector &additional_args) { + static std::string cachedResult; + static std::vector cachedArgs; + + if (cachedResult.empty()) + cachedResult = getCCImpl(cachedArgs); + + additional_args.insert(additional_args.end(), cachedArgs.begin(), cachedArgs.end()); + return cachedResult; +} //////////////////////////////////////////////////////////////////////////////// diff --git a/driver/tool.h b/driver/tool.h index e06124e716..a3b0b3fcc1 100644 --- a/driver/tool.h +++ b/driver/tool.h @@ -25,8 +25,7 @@ namespace opts { extern llvm::cl::opt linker; } -std::string getGcc(std::vector &additional_args, - const char *fallback = "cc"); +std::string getCC(std::vector &additional_args); void appendTargetArgsForGcc(std::vector &args); std::string getProgram(const char *fallbackName, diff --git a/tests/driver/cross_cc_fallback.d b/tests/driver/cross_cc_fallback.d new file mode 100644 index 0000000000..a76aaa4ee5 --- /dev/null +++ b/tests/driver/cross_cc_fallback.d @@ -0,0 +1,8 @@ +// RUN: env PATH= CC= not %ldc -mtriple aarch64-unknown-linux-gnut64 -v -defaultlib= %s 2>&1 | FileCheck %s + +// CHECK-DAG: aarch64-unknown-linux-gnut64-gcc +// CHECK-DAG: aarch64-unknown-linux-gnut64-clang + +// UNSUPPORTED: Windows + +extern(C) void main () {}