Index: cfe/trunk/test/Driver/parse-progname.c =================================================================== --- cfe/trunk/test/Driver/parse-progname.c +++ cfe/trunk/test/Driver/parse-progname.c @@ -0,0 +1,56 @@ +// REQUIRES: shell, arm-registered-target + + + +// RUN: ln -fs %clang %T/clang++ +// RUN: ln -fs %clang %T/clang++3.5.0 +// RUN: ln -fs %clang %T/clang++-3.5 +// RUN: ln -fs %clang %T/clang++-tot +// RUN: ln -fs %clang %T/clang-c++ +// RUN: ln -fs %clang %T/clang-g++ +// RUN: ln -fs %clang %T/c++ +// RUN: ln -fs %clang %T/foo-clang++ +// RUN: ln -fs %clang %T/foo-clang++-3.5 +// RUN: ln -fs %clang %T/foo-clang++3.5 +// RUN: %T/clang++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s +// RUN: %T/clang++3.5.0 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s +// RUN: %T/clang++-3.5 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s +// RUN: %T/clang++-tot -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s +// RUN: %T/clang-c++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s +// RUN: %T/clang-g++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s +// RUN: %T/c++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s +// RUN: %T/foo-clang++ -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s +// RUN: %T/foo-clang++-3.5 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s +// RUN: %T/foo-clang++3.5 -### %s 2>&1 | FileCheck -check-prefix=CXXMODE %s +// CXXMODE: "-x" "c++" + + +// RUN: ln -fs %clang %T/clang-cl +// RUN: ln -fs %clang %T/cl +// RUN: ln -fs %clang %T/cl.exe +// RUN: ln -fs %clang %T/clang-cl3.5 +// RUN: ln -fs %clang %T/clang-cl-3.5 +// RUN: %T/clang-cl -### %s 2>&1 | FileCheck -check-prefix=CLMODE %s +// RUN: %T/cl -### %s 2>&1 | FileCheck -check-prefix=CLMODE %s +// RUN: %T/cl.exe -### %s 2>&1 | FileCheck -check-prefix=CLMODE %s +// RUN: %T/clang-cl3.5 -### %s 2>&1 | FileCheck -check-prefix=CLMODE %s +// RUN: %T/clang-cl-3.5 -### %s 2>&1 | FileCheck -check-prefix=CLMODE %s +// CLMODE: "-fdiagnostics-format" "msvc" + + +// RUN: ln -fs %clang %T/clang-cpp +// RUN: ln -fs %clang %T/cpp +// RUN: %T/clang-cpp -### %s 2>&1 | FileCheck -check-prefix=CPPMODE %s +// RUN: %T/cpp -### %s 2>&1 | FileCheck -check-prefix=CPPMODE %s +// CPPMODE: "-E" + + +// RUN: ln -fs %clang %T/cl-clang +// RUN: %T/cl-clang -### %s 2>&1 | FileCheck -check-prefix=CMODE %s +// CMODE: "-x" "c" +// CMODE-NOT: "-fdiagnostics-format" "msvc" + + +// RUN: ln -fs %clang %T/arm-linux-gnueabi-clang +// RUN: %T/arm-linux-gnueabi-clang -### %s 2>&1 | FileCheck -check-prefix=TARGET %s +// TARGET: Target: arm--linux-gnueabi Index: cfe/trunk/tools/driver/driver.cpp =================================================================== --- cfe/trunk/tools/driver/driver.cpp +++ cfe/trunk/tools/driver/driver.cpp @@ -198,88 +198,93 @@ extern int cc1as_main(ArrayRef Argv, const char *Argv0, void *MainAddr); -static void ParseProgName(SmallVectorImpl &ArgVector, - std::set &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 -target as implicit first argument. - static const struct { - const char *Suffix; - const char *ModeFlag; - } suffixes [] = { - { "clang", nullptr }, - { "clang++", "--driver-mode=g++" }, - { "clang-c++", "--driver-mode=g++" }, - { "clang-cc", nullptr }, - { "clang-cpp", "--driver-mode=cpp" }, - { "clang-g++", "--driver-mode=g++" }, - { "clang-gcc", nullptr }, - { "clang-cl", "--driver-mode=cl" }, - { "cc", nullptr }, - { "cpp", "--driver-mode=cpp" }, - { "cl" , "--driver-mode=cl" }, - { "++", "--driver-mode=g++" }, +struct DriverSuffix { + const char *Suffix; + const char *ModeFlag; +}; + +static const DriverSuffix *FindDriverSuffix(StringRef ProgName) { + // A list of known driver suffixes. Suffixes are compared against the + // program name in order. If there is a match, the frontend type if updated as + // necessary by applying the ModeFlag. + static const DriverSuffix DriverSuffixes[] = { + {"clang", nullptr}, + {"clang++", "--driver-mode=g++"}, + {"clang-c++", "--driver-mode=g++"}, + {"clang-cc", nullptr}, + {"clang-cpp", "--driver-mode=cpp"}, + {"clang-g++", "--driver-mode=g++"}, + {"clang-gcc", nullptr}, + {"clang-cl", "--driver-mode=cl"}, + {"cc", nullptr}, + {"cpp", "--driver-mode=cpp"}, + {"cl", "--driver-mode=cl"}, + {"++", "--driver-mode=g++"}, }; - std::string ProgName(llvm::sys::path::stem(ArgVector[0])); + + for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) + if (ProgName.endswith(DriverSuffixes[i].Suffix)) + return &DriverSuffixes[i]; + return nullptr; +} + +static void ParseProgName(SmallVectorImpl &ArgVector, + std::set &SavedStrings) { + // Try to infer frontend type and default target from the program name by + // comparing it against DriverSuffixes in order. + + // If there is a match, 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 + // -target as implicit first argument. + + std::string ProgName =llvm::sys::path::stem(ArgVector[0]); #ifdef LLVM_ON_WIN32 // Transform to lowercase for case insensitive file systems. - std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(), - toLowercase); + ProgName = StringRef(ProgName).lower(); #endif - StringRef ProgNameRef(ProgName); - StringRef Prefix; - for (int Components = 2; Components; --Components) { - auto I = std::find_if(std::begin(suffixes), std::end(suffixes), - [&](decltype(suffixes[0]) &suffix) { - return ProgNameRef.endswith(suffix.Suffix); - }); - - if (I != std::end(suffixes)) { - if (I->ModeFlag) { - auto it = ArgVector.begin(); - if (it != ArgVector.end()) - ++it; - ArgVector.insert(it, I->ModeFlag); - } - StringRef::size_type LastComponent = ProgNameRef.rfind('-', - ProgNameRef.size() - strlen(I->Suffix)); - if (LastComponent != StringRef::npos) - Prefix = ProgNameRef.slice(0, LastComponent); - break; + StringRef ProgNameRef = ProgName; + const DriverSuffix *DS = FindDriverSuffix(ProgNameRef); + + if (!DS) { + // Try again after stripping any trailing version number: + // clang++3.5 -> clang++ + ProgNameRef = ProgNameRef.rtrim("0123456789."); + DS = FindDriverSuffix(ProgNameRef); + } + + if (!DS) { + // Try again after stripping trailing -component. + // clang++-tot -> clang++ + ProgNameRef = ProgNameRef.slice(0, ProgNameRef.rfind('-')); + DS = FindDriverSuffix(ProgNameRef); + } + + if (DS) { + if (const char *Flag = DS->ModeFlag) { + // Add Flag to the arguments. + auto it = ArgVector.begin(); + if (it != ArgVector.end()) + ++it; + ArgVector.insert(it, Flag); } - StringRef::size_type LastComponent = ProgNameRef.rfind('-'); + StringRef::size_type LastComponent = ProgNameRef.rfind( + '-', ProgNameRef.size() - strlen(DS->Suffix)); if (LastComponent == StringRef::npos) - break; - ProgNameRef = ProgNameRef.slice(0, LastComponent); - } - - if (Prefix.empty()) - return; + return; - std::string IgnoredError; - if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) { - auto it = ArgVector.begin(); - if (it != ArgVector.end()) - ++it; - const char* Strings[] = - { GetStableCStr(SavedStrings, std::string("-target")), - GetStableCStr(SavedStrings, Prefix) }; - ArgVector.insert(it, std::begin(Strings), std::end(Strings)); + // Infer target from the prefix. + StringRef Prefix = ProgNameRef.slice(0, LastComponent); + std::string IgnoredError; + if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) { + auto it = ArgVector.begin(); + if (it != ArgVector.end()) + ++it; + const char *arr[] = { "-target", GetStableCStr(SavedStrings, Prefix) }; + ArgVector.insert(it, std::begin(arr), std::end(arr)); + } } } @@ -446,7 +451,7 @@ SetInstallDir(argv, TheDriver); llvm::InitializeAllTargets(); - ParseProgName(argv, SavedStrings, TheDriver); + ParseProgName(argv, SavedStrings); SetBackdoorDriverOutputsFromEnvVars(TheDriver);