summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerge Pavlov <sepavloff@gmail.com>2017-08-29 05:22:26 +0000
committerSerge Pavlov <sepavloff@gmail.com>2017-08-29 05:22:26 +0000
commit918910d6e53db4b620ae1167dc59e83f3031750e (patch)
tree3032d01f1921543d80710c794778c3a45e8d8dd2
parente4f522b72db73d13283c35e18992f96cd082b596 (diff)
downloadclang-918910d6e53db4b620ae1167dc59e83f3031750e.tar.gz
Use class to pass information about executable name
Information about clang executable name components, such as target and driver mode, was passes in std::pair. With this change it is passed in a special structure. It improves readability and makes access to this information more convenient. NFC. Differential Revision: https://reviews.llvm.org/D36057 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@311981 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Driver/Driver.h5
-rw-r--r--include/clang/Driver/ToolChain.h33
-rw-r--r--lib/Driver/Driver.cpp5
-rw-r--r--lib/Driver/ToolChain.cpp41
-rw-r--r--lib/Tooling/Tooling.cpp9
-rw-r--r--tools/driver/driver.cpp30
-rw-r--r--unittests/Driver/CMakeLists.txt1
-rw-r--r--unittests/Driver/ToolChainTest.cpp96
8 files changed, 172 insertions, 48 deletions
diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h
index 86b785ef53..e81fe4635f 100644
--- a/include/clang/Driver/Driver.h
+++ b/include/clang/Driver/Driver.h
@@ -129,6 +129,9 @@ public:
/// The original path to the clang executable.
std::string ClangExecutable;
+ /// Target and driver mode components extracted from clang executable name.
+ ParsedClangName ClangNameParts;
+
/// The path to the installed clang directory, if any.
std::string InstalledDir;
@@ -284,6 +287,8 @@ public:
void setCheckInputsExist(bool Value) { CheckInputsExist = Value; }
+ void setTargetAndMode(const ParsedClangName &TM) { ClangNameParts = TM; }
+
const std::string &getTitle() { return DriverTitle; }
void setTitle(std::string Value) { DriverTitle = std::move(Value); }
diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h
index e354acb6d0..ff08911813 100644
--- a/include/clang/Driver/ToolChain.h
+++ b/include/clang/Driver/ToolChain.h
@@ -46,6 +46,28 @@ namespace driver {
class Tool;
class XRayArgs;
+/// Helper structure used to pass information extracted from clang executable
+/// name such as `i686-linux-android-g++`.
+///
+struct ParsedClangName {
+ /// Target part of the executable name, as `i686-linux-android`.
+ std::string TargetPrefix;
+ /// Driver mode part of the executable name, as `g++`.
+ std::string ModeSuffix;
+ /// Corresponding driver mode argument, as '--driver-mode=g++'
+ const char *DriverMode;
+ /// True if TargetPrefix is recognized as a registered target name.
+ bool TargetIsValid;
+
+ ParsedClangName() : DriverMode(nullptr), TargetIsValid(false) {}
+ ParsedClangName(std::string Suffix, const char *Mode)
+ : ModeSuffix(Suffix), DriverMode(Mode), TargetIsValid(false) {}
+ ParsedClangName(std::string Target, std::string Suffix, const char *Mode,
+ bool IsRegistered)
+ : TargetPrefix(Target), ModeSuffix(Suffix), DriverMode(Mode),
+ TargetIsValid(IsRegistered) {}
+};
+
/// ToolChain - Access to tools for a single platform.
class ToolChain {
public:
@@ -193,13 +215,16 @@ public:
/// For example, when called with i686-linux-android-g++, the first element
/// of the return value will be set to `"i686-linux-android"` and the second
/// will be set to "--driver-mode=g++"`.
+ /// It is OK if the target name is not registered. In this case the return
+ /// value contains false in the field TargetIsValid.
///
/// \pre `llvm::InitializeAllTargets()` has been called.
/// \param ProgName The name the Clang driver was invoked with (from,
- /// e.g., argv[0])
- /// \return A pair of (`target`, `mode-flag`), where one or both may be empty.
- static std::pair<std::string, std::string>
- getTargetAndModeFromProgramName(StringRef ProgName);
+ /// e.g., argv[0]).
+ /// \return A structure of type ParsedClangName that contains the executable
+ /// name parts.
+ ///
+ static ParsedClangName getTargetAndModeFromProgramName(StringRef ProgName);
// Tool access.
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index 6b275c52d0..5340d8abe1 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -119,9 +119,8 @@ Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple,
void Driver::ParseDriverMode(StringRef ProgramName,
ArrayRef<const char *> Args) {
- auto Default = ToolChain::getTargetAndModeFromProgramName(ProgramName);
- StringRef DefaultMode(Default.second);
- setDriverModeFromOption(DefaultMode);
+ ClangNameParts = ToolChain::getTargetAndModeFromProgramName(ProgramName);
+ setDriverModeFromOption(ClangNameParts.DriverMode);
for (const char *ArgPtr : Args) {
// Ingore nullptrs, they are response file's EOL markers
diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp
index 2660c5a2c0..384481b3ea 100644
--- a/lib/Driver/ToolChain.cpp
+++ b/lib/Driver/ToolChain.cpp
@@ -113,7 +113,7 @@ struct DriverSuffix {
const char *ModeFlag;
};
-const DriverSuffix *FindDriverSuffix(StringRef ProgName) {
+const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) {
// A 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 by applying the ModeFlag.
@@ -132,9 +132,13 @@ const DriverSuffix *FindDriverSuffix(StringRef ProgName) {
{"++", "--driver-mode=g++"},
};
- for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i)
- if (ProgName.endswith(DriverSuffixes[i].Suffix))
+ for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) {
+ StringRef Suffix(DriverSuffixes[i].Suffix);
+ if (ProgName.endswith(Suffix)) {
+ Pos = ProgName.size() - Suffix.size();
return &DriverSuffixes[i];
+ }
+ }
return nullptr;
}
@@ -149,7 +153,7 @@ std::string normalizeProgramName(llvm::StringRef Argv0) {
return ProgName;
}
-const DriverSuffix *parseDriverSuffix(StringRef ProgName) {
+const DriverSuffix *parseDriverSuffix(StringRef ProgName, size_t &Pos) {
// Try to infer frontend type and default target from the program name by
// comparing it against DriverSuffixes in order.
@@ -157,47 +161,46 @@ const DriverSuffix *parseDriverSuffix(StringRef ProgName) {
// E.g. "x86_64-linux-clang" as interpreted as suffix "clang" with target
// prefix "x86_64-linux". If such a target prefix is found, it may be
// added via -target as implicit first argument.
- const DriverSuffix *DS = FindDriverSuffix(ProgName);
+ const DriverSuffix *DS = FindDriverSuffix(ProgName, Pos);
if (!DS) {
// Try again after stripping any trailing version number:
// clang++3.5 -> clang++
ProgName = ProgName.rtrim("0123456789.");
- DS = FindDriverSuffix(ProgName);
+ DS = FindDriverSuffix(ProgName, Pos);
}
if (!DS) {
// Try again after stripping trailing -component.
// clang++-tot -> clang++
ProgName = ProgName.slice(0, ProgName.rfind('-'));
- DS = FindDriverSuffix(ProgName);
+ DS = FindDriverSuffix(ProgName, Pos);
}
return DS;
}
} // anonymous namespace
-std::pair<std::string, std::string>
+ParsedClangName
ToolChain::getTargetAndModeFromProgramName(StringRef PN) {
std::string ProgName = normalizeProgramName(PN);
- const DriverSuffix *DS = parseDriverSuffix(ProgName);
+ size_t SuffixPos;
+ const DriverSuffix *DS = parseDriverSuffix(ProgName, SuffixPos);
if (!DS)
- return std::make_pair("", "");
- std::string ModeFlag = DS->ModeFlag == nullptr ? "" : DS->ModeFlag;
+ return ParsedClangName();
+ size_t SuffixEnd = SuffixPos + strlen(DS->Suffix);
- std::string::size_type LastComponent =
- ProgName.rfind('-', ProgName.size() - strlen(DS->Suffix));
+ size_t LastComponent = ProgName.rfind('-', SuffixPos);
if (LastComponent == std::string::npos)
- return std::make_pair("", ModeFlag);
+ return ParsedClangName(ProgName.substr(0, SuffixEnd), DS->ModeFlag);
+ std::string ModeSuffix = ProgName.substr(LastComponent + 1,
+ SuffixEnd - LastComponent - 1);
// Infer target from the prefix.
StringRef Prefix(ProgName);
Prefix = Prefix.slice(0, LastComponent);
std::string IgnoredError;
- std::string Target;
- if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) {
- Target = Prefix;
- }
- return std::make_pair(Target, ModeFlag);
+ bool IsRegistered = llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError);
+ return ParsedClangName{Prefix, ModeSuffix, DS->ModeFlag, IsRegistered};
}
StringRef ToolChain::getDefaultUniversalArchName() const {
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index 662f02dca2..df9d7df694 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -190,11 +190,12 @@ void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine,
}
auto TargetMode =
clang::driver::ToolChain::getTargetAndModeFromProgramName(InvokedAs);
- if (!AlreadyHasMode && !TargetMode.second.empty()) {
- CommandLine.insert(++CommandLine.begin(), TargetMode.second);
+ if (!AlreadyHasMode && TargetMode.DriverMode) {
+ CommandLine.insert(++CommandLine.begin(), TargetMode.DriverMode);
}
- if (!AlreadyHasTarget && !TargetMode.first.empty()) {
- CommandLine.insert(++CommandLine.begin(), {"-target", TargetMode.first});
+ if (!AlreadyHasTarget && TargetMode.TargetIsValid) {
+ CommandLine.insert(++CommandLine.begin(), {"-target",
+ TargetMode.TargetPrefix});
}
}
}
diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp
index 9f37c428ff..e1461f112b 100644
--- a/tools/driver/driver.cpp
+++ b/tools/driver/driver.cpp
@@ -206,23 +206,19 @@ extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
void *MainAddr);
-static void insertTargetAndModeArgs(StringRef Target, StringRef Mode,
+static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
SmallVectorImpl<const char *> &ArgVector,
std::set<std::string> &SavedStrings) {
- if (!Mode.empty()) {
+ if (NameParts.DriverMode) {
// Add the mode flag to the arguments.
- auto it = ArgVector.begin();
- if (it != ArgVector.end())
- ++it;
- ArgVector.insert(it, GetStableCStr(SavedStrings, Mode));
+ ArgVector.insert(ArgVector.end(),
+ GetStableCStr(SavedStrings, NameParts.DriverMode));
}
- if (!Target.empty()) {
- auto it = ArgVector.begin();
- if (it != ArgVector.end())
- ++it;
- const char *arr[] = {"-target", GetStableCStr(SavedStrings, Target)};
- ArgVector.insert(it, std::begin(arr), std::end(arr));
+ if (NameParts.TargetIsValid) {
+ const char *arr[] = {"-target", GetStableCStr(SavedStrings,
+ NameParts.TargetPrefix)};
+ ArgVector.insert(ArgVector.end(), std::begin(arr), std::end(arr));
}
}
@@ -330,9 +326,7 @@ int main(int argc_, const char **argv_) {
}
llvm::InitializeAllTargets();
- std::string ProgName = argv[0];
- std::pair<std::string, std::string> TargetAndMode =
- ToolChain::getTargetAndModeFromProgramName(ProgName);
+ auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(argv[0]);
llvm::BumpPtrAllocator A;
llvm::StringSaver Saver(A);
@@ -345,7 +339,7 @@ int main(int argc_, const char **argv_) {
// Finally, our -cc1 tools don't care which tokenization mode we use because
// response files written by clang will tokenize the same way in either mode.
bool ClangCLMode = false;
- if (TargetAndMode.second == "--driver-mode=cl" ||
+ if (StringRef(TargetAndMode.DriverMode).equals("--driver-mode=cl") ||
std::find_if(argv.begin(), argv.end(), [](const char *F) {
return F && strcmp(F, "--driver-mode=cl") == 0;
}) != argv.end()) {
@@ -454,9 +448,9 @@ int main(int argc_, const char **argv_) {
Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
SetInstallDir(argv, TheDriver, CanonicalPrefixes);
+ TheDriver.setTargetAndMode(TargetAndMode);
- insertTargetAndModeArgs(TargetAndMode.first, TargetAndMode.second, argv,
- SavedStrings);
+ insertTargetAndModeArgs(TargetAndMode, argv, SavedStrings);
SetBackdoorDriverOutputsFromEnvVars(TheDriver);
diff --git a/unittests/Driver/CMakeLists.txt b/unittests/Driver/CMakeLists.txt
index a4f75d26f6..2a3f41d63b 100644
--- a/unittests/Driver/CMakeLists.txt
+++ b/unittests/Driver/CMakeLists.txt
@@ -1,4 +1,5 @@
set(LLVM_LINK_COMPONENTS
+ ${LLVM_TARGETS_TO_BUILD}
Support
Option
)
diff --git a/unittests/Driver/ToolChainTest.cpp b/unittests/Driver/ToolChainTest.cpp
index ec50560b20..93cf12b3c2 100644
--- a/unittests/Driver/ToolChainTest.cpp
+++ b/unittests/Driver/ToolChainTest.cpp
@@ -18,6 +18,8 @@
#include "clang/Basic/VirtualFileSystem.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include "gtest/gtest.h"
using namespace clang;
@@ -164,4 +166,98 @@ TEST(ToolChainTest, InvalidArgument) {
EXPECT_TRUE(C->containsError());
}
+TEST(ToolChainTest, ParsedClangName) {
+ ParsedClangName Empty;
+ EXPECT_TRUE(Empty.TargetPrefix.empty());
+ EXPECT_TRUE(Empty.ModeSuffix.empty());
+ EXPECT_TRUE(Empty.DriverMode == nullptr);
+ EXPECT_FALSE(Empty.TargetIsValid);
+
+ ParsedClangName DriverOnly("clang", nullptr);
+ EXPECT_TRUE(DriverOnly.TargetPrefix.empty());
+ EXPECT_TRUE(DriverOnly.ModeSuffix == "clang");
+ EXPECT_TRUE(DriverOnly.DriverMode == nullptr);
+ EXPECT_FALSE(DriverOnly.TargetIsValid);
+
+ ParsedClangName DriverOnly2("clang++", "--driver-mode=g++");
+ EXPECT_TRUE(DriverOnly2.TargetPrefix.empty());
+ EXPECT_TRUE(DriverOnly2.ModeSuffix == "clang++");
+ EXPECT_STREQ(DriverOnly2.DriverMode, "--driver-mode=g++");
+ EXPECT_FALSE(DriverOnly2.TargetIsValid);
+
+ ParsedClangName TargetAndMode("i386", "clang-g++", "--driver-mode=g++", true);
+ EXPECT_TRUE(TargetAndMode.TargetPrefix == "i386");
+ EXPECT_TRUE(TargetAndMode.ModeSuffix == "clang-g++");
+ EXPECT_STREQ(TargetAndMode.DriverMode, "--driver-mode=g++");
+ EXPECT_TRUE(TargetAndMode.TargetIsValid);
+}
+
+TEST(ToolChainTest, GetTargetAndMode) {
+ llvm::InitializeAllTargets();
+ std::string IgnoredError;
+ if (!llvm::TargetRegistry::lookupTarget("x86_64", IgnoredError))
+ return;
+
+ ParsedClangName Res = ToolChain::getTargetAndModeFromProgramName("clang");
+ EXPECT_TRUE(Res.TargetPrefix.empty());
+ EXPECT_TRUE(Res.ModeSuffix == "clang");
+ EXPECT_TRUE(Res.DriverMode == nullptr);
+ EXPECT_FALSE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName("clang++");
+ EXPECT_TRUE(Res.TargetPrefix.empty());
+ EXPECT_TRUE(Res.ModeSuffix == "clang++");
+ EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
+ EXPECT_FALSE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName("clang++6.0");
+ EXPECT_TRUE(Res.TargetPrefix.empty());
+ EXPECT_TRUE(Res.ModeSuffix == "clang++");
+ EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
+ EXPECT_FALSE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName("clang++-release");
+ EXPECT_TRUE(Res.TargetPrefix.empty());
+ EXPECT_TRUE(Res.ModeSuffix == "clang++");
+ EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
+ EXPECT_FALSE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName("x86_64-clang++");
+ EXPECT_TRUE(Res.TargetPrefix == "x86_64");
+ EXPECT_TRUE(Res.ModeSuffix == "clang++");
+ EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
+ EXPECT_TRUE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName(
+ "x86_64-linux-gnu-clang-c++");
+ EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu");
+ EXPECT_TRUE(Res.ModeSuffix == "clang-c++");
+ EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
+ EXPECT_TRUE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName(
+ "x86_64-linux-gnu-clang-c++-tot");
+ EXPECT_TRUE(Res.TargetPrefix == "x86_64-linux-gnu");
+ EXPECT_TRUE(Res.ModeSuffix == "clang-c++");
+ EXPECT_STREQ(Res.DriverMode, "--driver-mode=g++");
+ EXPECT_TRUE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName("qqq");
+ EXPECT_TRUE(Res.TargetPrefix.empty());
+ EXPECT_TRUE(Res.ModeSuffix.empty());
+ EXPECT_TRUE(Res.DriverMode == nullptr);
+ EXPECT_FALSE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName("x86_64-qqq");
+ EXPECT_TRUE(Res.TargetPrefix.empty());
+ EXPECT_TRUE(Res.ModeSuffix.empty());
+ EXPECT_TRUE(Res.DriverMode == nullptr);
+ EXPECT_FALSE(Res.TargetIsValid);
+
+ Res = ToolChain::getTargetAndModeFromProgramName("qqq-clang-cl");
+ EXPECT_TRUE(Res.TargetPrefix == "qqq");
+ EXPECT_TRUE(Res.ModeSuffix == "clang-cl");
+ EXPECT_STREQ(Res.DriverMode, "--driver-mode=cl");
+ EXPECT_FALSE(Res.TargetIsValid);
+}
} // end anonymous namespace.