#include "llvm/Support/Program.h"
#include "llvm/Support/Signals.h"
#include "llvm/Support/system_error.h"
+#include "llvm/Target/TargetRegistry.h"
+#include "llvm/Target/TargetSelect.h"
#include <cctype>
using namespace clang;
using namespace clang::driver;
}
}
+static void ParseProgName(llvm::SmallVectorImpl<const char *> &ArgVector,
+ std::set<std::string> &SavedStrings,
+ Driver &TheDriver)
+{
+ // Try to infer frontend type and default target from the program name.
+
+ // suffixes[] contains the list of known driver suffixes.
+ // Suffixes are compared against the program name in order.
+ // If there is a match, the frontend type is updated as necessary (CPP/C++).
+ // If there is no match, a second round is done after stripping the last
+ // hyphen and everything following it. This allows using something like
+ // "clang++-2.9".
+
+ // If there is a match in either the first or second round,
+ // the function tries to identify a target as prefix. E.g.
+ // "x86_64-linux-clang" as interpreted as suffix "clang" with
+ // target prefix "x86_64-linux". If such a target prefix is found,
+ // is gets added via -ccc-host-triple as implicit first argument.
+ static const struct {
+ const char *Suffix;
+ bool IsCXX;
+ bool IsCPP;
+ } suffixes [] = {
+ { "clang", false, false },
+ { "clang++", true, false },
+ { "clang-c++", true, false },
+ { "clang-cc", false, false },
+ { "clang-cpp", false, true },
+ { "clang-g++", true, false },
+ { "clang-gcc", false, false },
+ { "cc", false, false },
+ { "cpp", false, true },
+ { "++", true, false },
+ };
+ std::string ProgName(llvm::sys::path::stem(ArgVector[0]));
+ llvm::StringRef ProgNameRef(ProgName);
+ llvm::StringRef Prefix;
+
+ for (int Components = 2; Components; --Components) {
+ bool FoundMatch = false;
+ size_t i;
+
+ for (i = 0; i < sizeof(suffixes) / sizeof(suffixes[0]); ++i) {
+ if (ProgNameRef.endswith(suffixes[i].Suffix)) {
+ FoundMatch = true;
+ if (suffixes[i].IsCXX)
+ TheDriver.CCCIsCXX = true;
+ if (suffixes[i].IsCPP)
+ TheDriver.CCCIsCPP = true;
+ break;
+ }
+ }
+
+ if (FoundMatch) {
+ llvm::StringRef::size_type LastComponent = ProgNameRef.rfind('-',
+ ProgNameRef.size() - strlen(suffixes[i].Suffix));
+ if (LastComponent != llvm::StringRef::npos)
+ Prefix = ProgNameRef.slice(0, LastComponent);
+ break;
+ }
+
+ llvm::StringRef::size_type LastComponent = ProgNameRef.rfind('-');
+ if (LastComponent == llvm::StringRef::npos)
+ break;
+ ProgNameRef = ProgNameRef.slice(0, LastComponent);
+ }
+
+ if (Prefix.empty())
+ return;
+
+ std::string IgnoredError;
+ if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) {
+ ArgVector.insert(&ArgVector[1],
+ SaveStringInSet(SavedStrings, Prefix));
+ ArgVector.insert(&ArgVector[1],
+ SaveStringInSet(SavedStrings, std::string("-ccc-host-triple")));
+ }
+}
+
int main(int argc_, const char **argv_) {
llvm::sys::PrintStackTraceOnErrorSignal();
llvm::PrettyStackTraceProgram X(argc_, argv_);
TheDriver.setInstalledDir(InstalledPath);
}
- // Check for ".*++" or ".*++-[^-]*" to determine if we are a C++
- // compiler. This matches things like "c++", "clang++", and "clang++-1.1".
- //
- // Note that we intentionally want to use argv[0] here, to support "clang++"
- // being a symlink.
- //
- // We use *argv instead of argv[0] to work around a bogus g++ warning.
- const char *progname = argv_[0];
- std::string ProgName(llvm::sys::path::stem(progname));
- if (llvm::StringRef(ProgName).endswith("++") ||
- llvm::StringRef(ProgName).rsplit('-').first.endswith("++")) {
- TheDriver.CCCIsCXX = true;
- }
-
- if (llvm::StringRef(ProgName).endswith("cpp") ||
- llvm::StringRef(ProgName).rsplit('-').first.endswith("cpp")) {
- TheDriver.CCCIsCPP = true;
- }
+ llvm::InitializeAllTargets();
+ ParseProgName(argv, SavedStrings, TheDriver);
// Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE.
TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS");