123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- //===- lib/Tooling/AllTUsExecution.cpp - Execute actions on all TUs. ------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "clang/Tooling/AllTUsExecution.h"
- #include "clang/Tooling/ToolExecutorPluginRegistry.h"
- #include "llvm/Support/Regex.h"
- #include "llvm/Support/ThreadPool.h"
- #include "llvm/Support/Threading.h"
- #include "llvm/Support/VirtualFileSystem.h"
- namespace clang {
- namespace tooling {
- const char *AllTUsToolExecutor::ExecutorName = "AllTUsToolExecutor";
- namespace {
- llvm::Error make_string_error(const llvm::Twine &Message) {
- return llvm::make_error<llvm::StringError>(Message,
- llvm::inconvertibleErrorCode());
- }
- ArgumentsAdjuster getDefaultArgumentsAdjusters() {
- return combineAdjusters(
- getClangStripOutputAdjuster(),
- combineAdjusters(getClangSyntaxOnlyAdjuster(),
- getClangStripDependencyFileAdjuster()));
- }
- class ThreadSafeToolResults : public ToolResults {
- public:
- void addResult(StringRef Key, StringRef Value) override {
- std::unique_lock<std::mutex> LockGuard(Mutex);
- Results.addResult(Key, Value);
- }
- std::vector<std::pair<llvm::StringRef, llvm::StringRef>>
- AllKVResults() override {
- return Results.AllKVResults();
- }
- void forEachResult(llvm::function_ref<void(StringRef Key, StringRef Value)>
- Callback) override {
- Results.forEachResult(Callback);
- }
- private:
- InMemoryToolResults Results;
- std::mutex Mutex;
- };
- } // namespace
- llvm::cl::opt<std::string>
- Filter("filter",
- llvm::cl::desc("Only process files that match this filter. "
- "This flag only applies to all-TUs."),
- llvm::cl::init(".*"));
- AllTUsToolExecutor::AllTUsToolExecutor(
- const CompilationDatabase &Compilations, unsigned ThreadCount,
- std::shared_ptr<PCHContainerOperations> PCHContainerOps)
- : Compilations(Compilations), Results(new ThreadSafeToolResults),
- Context(Results.get()), ThreadCount(ThreadCount) {}
- AllTUsToolExecutor::AllTUsToolExecutor(
- CommonOptionsParser Options, unsigned ThreadCount,
- std::shared_ptr<PCHContainerOperations> PCHContainerOps)
- : OptionsParser(std::move(Options)),
- Compilations(OptionsParser->getCompilations()),
- Results(new ThreadSafeToolResults), Context(Results.get()),
- ThreadCount(ThreadCount) {}
- llvm::Error AllTUsToolExecutor::execute(
- llvm::ArrayRef<
- std::pair<std::unique_ptr<FrontendActionFactory>, ArgumentsAdjuster>>
- Actions) {
- if (Actions.empty())
- return make_string_error("No action to execute.");
- if (Actions.size() != 1)
- return make_string_error(
- "Only support executing exactly 1 action at this point.");
- std::string ErrorMsg;
- std::mutex TUMutex;
- auto AppendError = [&](llvm::Twine Err) {
- std::unique_lock<std::mutex> LockGuard(TUMutex);
- ErrorMsg += Err.str();
- };
- auto Log = [&](llvm::Twine Msg) {
- std::unique_lock<std::mutex> LockGuard(TUMutex);
- llvm::errs() << Msg.str() << "\n";
- };
- std::vector<std::string> Files;
- llvm::Regex RegexFilter(Filter);
- for (const auto& File : Compilations.getAllFiles()) {
- if (RegexFilter.match(File))
- Files.push_back(File);
- }
- // Add a counter to track the progress.
- const std::string TotalNumStr = std::to_string(Files.size());
- unsigned Counter = 0;
- auto Count = [&]() {
- std::unique_lock<std::mutex> LockGuard(TUMutex);
- return ++Counter;
- };
- auto &Action = Actions.front();
- {
- llvm::ThreadPool Pool(llvm::hardware_concurrency(ThreadCount));
- for (std::string File : Files) {
- Pool.async(
- [&](std::string Path) {
- Log("[" + std::to_string(Count()) + "/" + TotalNumStr +
- "] Processing file " + Path);
- // Each thread gets an indepent copy of a VFS to allow different
- // concurrent working directories.
- IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
- llvm::vfs::createPhysicalFileSystem();
- ClangTool Tool(Compilations, {Path},
- std::make_shared<PCHContainerOperations>(), FS);
- Tool.appendArgumentsAdjuster(Action.second);
- Tool.appendArgumentsAdjuster(getDefaultArgumentsAdjusters());
- for (const auto &FileAndContent : OverlayFiles)
- Tool.mapVirtualFile(FileAndContent.first(),
- FileAndContent.second);
- if (Tool.run(Action.first.get()))
- AppendError(llvm::Twine("Failed to run action on ") + Path +
- "\n");
- },
- File);
- }
- // Make sure all tasks have finished before resetting the working directory.
- Pool.wait();
- }
- if (!ErrorMsg.empty())
- return make_string_error(ErrorMsg);
- return llvm::Error::success();
- }
- llvm::cl::opt<unsigned> ExecutorConcurrency(
- "execute-concurrency",
- llvm::cl::desc("The number of threads used to process all files in "
- "parallel. Set to 0 for hardware concurrency. "
- "This flag only applies to all-TUs."),
- llvm::cl::init(0));
- class AllTUsToolExecutorPlugin : public ToolExecutorPlugin {
- public:
- llvm::Expected<std::unique_ptr<ToolExecutor>>
- create(CommonOptionsParser &OptionsParser) override {
- if (OptionsParser.getSourcePathList().empty())
- return make_string_error(
- "[AllTUsToolExecutorPlugin] Please provide a directory/file path in "
- "the compilation database.");
- return std::make_unique<AllTUsToolExecutor>(std::move(OptionsParser),
- ExecutorConcurrency);
- }
- };
- static ToolExecutorPluginRegistry::Add<AllTUsToolExecutorPlugin>
- X("all-TUs", "Runs FrontendActions on all TUs in the compilation database. "
- "Tool results are stored in memory.");
- // This anchor is used to force the linker to link in the generated object file
- // and thus register the plugin.
- volatile int AllTUsToolExecutorAnchorSource = 0;
- } // end namespace tooling
- } // end namespace clang
|