forked from OSchip/llvm-project
Adds a way for tools to deduce the target config from a compiler name.
Adds `addTargetAndModeForProgramName`, a utility function that will add appropriate `-target foo` and `--driver-mode=g++` tokens to a command line for driver invocations of the form `a/b/foo-g++`. It is intended to support tooling: for example, should a compilation database record some invocation of `foo-g++` without these implicit flags, a Clang tool may use this function to add them back. Patch by Luke Zarko. llvm-svn: 249391
This commit is contained in:
parent
40f59e4466
commit
9b30e2b50b
|
@ -417,6 +417,29 @@ inline std::unique_ptr<FrontendActionFactory> newFrontendActionFactory(
|
|||
/// \param File Either an absolute or relative path.
|
||||
std::string getAbsolutePath(StringRef File);
|
||||
|
||||
/// \brief Changes CommandLine to contain implicit flags that would have been
|
||||
/// defined had the compiler driver been invoked through the path InvokedAs.
|
||||
///
|
||||
/// For example, when called with \c InvokedAs set to `i686-linux-android-g++`,
|
||||
/// the arguments '-target', 'i686-linux-android`, `--driver-mode=g++` will
|
||||
/// be inserted after the first argument in \c CommandLine.
|
||||
///
|
||||
/// This function will not add new `-target` or `--driver-mode` flags if they
|
||||
/// are already present in `CommandLine` (even if they have different settings
|
||||
/// than would have been inserted).
|
||||
///
|
||||
/// \pre `llvm::InitializeAllTargets()` has been called.
|
||||
///
|
||||
/// \param CommandLine the command line used to invoke the compiler driver or
|
||||
/// Clang tool, including the path to the executable as \c CommandLine[0].
|
||||
/// \param InvokedAs the path to the driver used to infer implicit flags.
|
||||
///
|
||||
/// \note This will not set \c CommandLine[0] to \c InvokedAs. The tooling
|
||||
/// infrastructure expects that CommandLine[0] is a tool path relative to which
|
||||
/// the builtin headers can be found.
|
||||
void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine,
|
||||
StringRef InvokedAs);
|
||||
|
||||
/// \brief Creates a \c CompilerInvocation.
|
||||
clang::CompilerInvocation *newInvocation(
|
||||
clang::DiagnosticsEngine *Diagnostics,
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "clang/Driver/Compilation.h"
|
||||
#include "clang/Driver/Driver.h"
|
||||
#include "clang/Driver/Tool.h"
|
||||
#include "clang/Driver/ToolChain.h"
|
||||
#include "clang/Frontend/ASTUnit.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
|
@ -162,6 +163,31 @@ std::string getAbsolutePath(StringRef File) {
|
|||
return AbsolutePath.str();
|
||||
}
|
||||
|
||||
void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine,
|
||||
StringRef InvokedAs) {
|
||||
if (!CommandLine.empty() && !InvokedAs.empty()) {
|
||||
bool AlreadyHasTarget = false;
|
||||
bool AlreadyHasMode = false;
|
||||
// Skip CommandLine[0].
|
||||
for (auto Token = ++CommandLine.begin(); Token != CommandLine.end();
|
||||
++Token) {
|
||||
StringRef TokenRef(*Token);
|
||||
AlreadyHasTarget |=
|
||||
(TokenRef == "-target" || TokenRef.startswith("-target="));
|
||||
AlreadyHasMode |= (TokenRef == "--driver-mode" ||
|
||||
TokenRef.startswith("--driver-mode="));
|
||||
}
|
||||
auto TargetMode =
|
||||
clang::driver::ToolChain::getTargetAndModeFromProgramName(InvokedAs);
|
||||
if (!AlreadyHasMode && !TargetMode.second.empty()) {
|
||||
CommandLine.insert(++CommandLine.begin(), TargetMode.second);
|
||||
}
|
||||
if (!AlreadyHasTarget && !TargetMode.first.empty()) {
|
||||
CommandLine.insert(++CommandLine.begin(), {"-target", TargetMode.first});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class SingleFrontendActionFactory : public FrontendActionFactory {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
set(LLVM_LINK_COMPONENTS
|
||||
${LLVM_TARGETS_TO_BUILD}
|
||||
Support
|
||||
)
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include "clang/Tooling/Tooling.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
@ -291,6 +293,84 @@ TEST(ClangToolTest, ArgumentAdjusters) {
|
|||
EXPECT_FALSE(Found);
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// Find a target name such that looking for it in TargetRegistry by that name
|
||||
/// returns the same target. We expect that there is at least one target
|
||||
/// configured with this property.
|
||||
std::string getAnyTarget() {
|
||||
llvm::InitializeAllTargets();
|
||||
for (const auto &Target : llvm::TargetRegistry::targets()) {
|
||||
std::string Error;
|
||||
if (llvm::TargetRegistry::lookupTarget(Target.getName(), Error) ==
|
||||
&Target) {
|
||||
return Target.getName();
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
TEST(addTargetAndModeForProgramName, AddsTargetAndMode) {
|
||||
std::string Target = getAnyTarget();
|
||||
ASSERT_FALSE(Target.empty());
|
||||
|
||||
std::vector<std::string> Args = {"clang", "-foo"};
|
||||
addTargetAndModeForProgramName(Args, "");
|
||||
EXPECT_EQ((std::vector<std::string>{"clang", "-foo"}), Args);
|
||||
addTargetAndModeForProgramName(Args, Target + "-g++");
|
||||
EXPECT_EQ((std::vector<std::string>{"clang", "-target", Target,
|
||||
"--driver-mode=g++", "-foo"}),
|
||||
Args);
|
||||
}
|
||||
|
||||
TEST(addTargetAndModeForProgramName, PathIgnored) {
|
||||
std::string Target = getAnyTarget();
|
||||
ASSERT_FALSE(Target.empty());
|
||||
|
||||
SmallString<32> ToolPath;
|
||||
llvm::sys::path::append(ToolPath, "foo", "bar", Target + "-g++");
|
||||
|
||||
std::vector<std::string> Args = {"clang", "-foo"};
|
||||
addTargetAndModeForProgramName(Args, ToolPath);
|
||||
EXPECT_EQ((std::vector<std::string>{"clang", "-target", Target,
|
||||
"--driver-mode=g++", "-foo"}),
|
||||
Args);
|
||||
}
|
||||
|
||||
TEST(addTargetAndModeForProgramName, IgnoresExistingTarget) {
|
||||
std::string Target = getAnyTarget();
|
||||
ASSERT_FALSE(Target.empty());
|
||||
|
||||
std::vector<std::string> Args = {"clang", "-foo", "-target", "something"};
|
||||
addTargetAndModeForProgramName(Args, Target + "-g++");
|
||||
EXPECT_EQ((std::vector<std::string>{"clang", "--driver-mode=g++", "-foo",
|
||||
"-target", "something"}),
|
||||
Args);
|
||||
|
||||
std::vector<std::string> ArgsAlt = {"clang", "-foo", "-target=something"};
|
||||
addTargetAndModeForProgramName(ArgsAlt, Target + "-g++");
|
||||
EXPECT_EQ((std::vector<std::string>{"clang", "--driver-mode=g++", "-foo",
|
||||
"-target=something"}),
|
||||
ArgsAlt);
|
||||
}
|
||||
|
||||
TEST(addTargetAndModeForProgramName, IgnoresExistingMode) {
|
||||
std::string Target = getAnyTarget();
|
||||
ASSERT_FALSE(Target.empty());
|
||||
|
||||
std::vector<std::string> Args = {"clang", "-foo", "--driver-mode=abc"};
|
||||
addTargetAndModeForProgramName(Args, Target + "-g++");
|
||||
EXPECT_EQ((std::vector<std::string>{"clang", "-target", Target, "-foo",
|
||||
"--driver-mode=abc"}),
|
||||
Args);
|
||||
|
||||
std::vector<std::string> ArgsAlt = {"clang", "-foo", "--driver-mode", "abc"};
|
||||
addTargetAndModeForProgramName(ArgsAlt, Target + "-g++");
|
||||
EXPECT_EQ((std::vector<std::string>{"clang", "-target", Target, "-foo",
|
||||
"--driver-mode", "abc"}),
|
||||
ArgsAlt);
|
||||
}
|
||||
|
||||
#ifndef LLVM_ON_WIN32
|
||||
TEST(ClangToolTest, BuildASTs) {
|
||||
FixedCompilationDatabase Compilations("/", std::vector<std::string>());
|
||||
|
|
Loading…
Reference in New Issue