Author: klimek Date: Tue Oct 6 05:45:03 2015 New Revision: 249391 URL: http://llvm.org/viewvc/llvm-project?rev=249391&view=rev Log: 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. Modified: cfe/trunk/include/clang/Tooling/Tooling.h cfe/trunk/lib/Tooling/Tooling.cpp cfe/trunk/unittests/Tooling/CMakeLists.txt cfe/trunk/unittests/Tooling/ToolingTest.cpp Modified: cfe/trunk/include/clang/Tooling/Tooling.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Tooling.h?rev=249391&r1=249390&r2=249391&view=diff ============================================================================== --- cfe/trunk/include/clang/Tooling/Tooling.h (original) +++ cfe/trunk/include/clang/Tooling/Tooling.h Tue Oct 6 05:45:03 2015 @@ -417,6 +417,29 @@ inline std::unique_ptr<FrontendActionFac /// \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, Modified: cfe/trunk/lib/Tooling/Tooling.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Tooling.cpp?rev=249391&r1=249390&r2=249391&view=diff ============================================================================== --- cfe/trunk/lib/Tooling/Tooling.cpp (original) +++ cfe/trunk/lib/Tooling/Tooling.cpp Tue Oct 6 05:45:03 2015 @@ -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 Fi 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 { Modified: cfe/trunk/unittests/Tooling/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/CMakeLists.txt?rev=249391&r1=249390&r2=249391&view=diff ============================================================================== --- cfe/trunk/unittests/Tooling/CMakeLists.txt (original) +++ cfe/trunk/unittests/Tooling/CMakeLists.txt Tue Oct 6 05:45:03 2015 @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + ${LLVM_TARGETS_TO_BUILD} Support ) Modified: cfe/trunk/unittests/Tooling/ToolingTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/ToolingTest.cpp?rev=249391&r1=249390&r2=249391&view=diff ============================================================================== --- cfe/trunk/unittests/Tooling/ToolingTest.cpp (original) +++ cfe/trunk/unittests/Tooling/ToolingTest.cpp Tue Oct 6 05:45:03 2015 @@ -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>()); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits