Skip to content

Commit 21b6df1

Browse files
committed
chore: Add Execution
1 parent d226f3a commit 21b6df1

File tree

2 files changed

+345
-0
lines changed

2 files changed

+345
-0
lines changed

source/AST/Execution.cpp

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
//
2+
// This is a derivative work. originally part of the LLVM Project.
3+
// Licensed under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
// Copyright (c) 2023 Vinnie Falco ([email protected])
8+
//
9+
// Official repository: https://github.com/cppalliance/mrdox
10+
//
11+
12+
//===- lib/Tooling/AllTUsExecution.cpp - Execute actions on all TUs. ------===//
13+
//
14+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
15+
// See https://llvm.org/LICENSE.txt for license information.
16+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
17+
//
18+
//===----------------------------------------------------------------------===//
19+
20+
#include "Execution.hpp"
21+
#include <clang/Tooling/ToolExecutorPluginRegistry.h>
22+
#include <llvm/Support/Regex.h>
23+
#include <llvm/Support/ThreadPool.h>
24+
#include <llvm/Support/Threading.h>
25+
#include <llvm/Support/VirtualFileSystem.h>
26+
27+
namespace clang {
28+
namespace mrdox {
29+
30+
const char* Executor::ExecutorName = "MrDoxExecutor";
31+
32+
#if 0
33+
llvm::cl::opt<std::string>
34+
Filter("filter",
35+
llvm::cl::desc("Only process files that match this filter. "
36+
"This flag only applies to all-TUs."),
37+
llvm::cl::init(".*"));
38+
39+
llvm::cl::opt<unsigned> ExecutorConcurrency(
40+
"execute-concurrency",
41+
llvm::cl::desc("The number of threads used to process all files in "
42+
"parallel. Set to 0 for hardware concurrency. "
43+
"This flag only applies to all-TUs."),
44+
llvm::cl::init(0));
45+
#endif
46+
47+
namespace {
48+
49+
llvm::Error
50+
make_string_error(
51+
const llvm::Twine& Message)
52+
{
53+
return llvm::make_error<llvm::StringError>(Message, llvm::inconvertibleErrorCode());
54+
}
55+
56+
tooling::ArgumentsAdjuster
57+
getDefaultArgumentsAdjusters()
58+
{
59+
return tooling::combineAdjusters(
60+
tooling::getClangStripOutputAdjuster(),
61+
tooling::combineAdjusters(
62+
tooling::getClangSyntaxOnlyAdjuster(),
63+
tooling::getClangStripDependencyFileAdjuster()));
64+
}
65+
66+
class ThreadSafeToolResults : public tooling::ToolResults
67+
{
68+
public:
69+
void addResult(StringRef Key, StringRef Value) override
70+
{
71+
std::unique_lock<std::mutex> LockGuard(Mutex);
72+
Results.addResult(Key, Value);
73+
}
74+
75+
std::vector<std::pair<llvm::StringRef, llvm::StringRef>>
76+
AllKVResults() override
77+
{
78+
return Results.AllKVResults();
79+
}
80+
81+
void forEachResult(llvm::function_ref<
82+
void(StringRef Key, StringRef Value)> Callback) override
83+
{
84+
Results.forEachResult(Callback);
85+
}
86+
87+
private:
88+
tooling::InMemoryToolResults Results;
89+
std::mutex Mutex;
90+
};
91+
92+
} // (anon)
93+
94+
Executor::
95+
Executor(
96+
tooling::CompilationDatabase const& Compilations,
97+
llvm::StringRef workingDir,
98+
unsigned ThreadCount,
99+
std::shared_ptr<PCHContainerOperations> PCHContainerOps)
100+
: Compilations(Compilations)
101+
, workingDir_(workingDir)
102+
, Results(new ThreadSafeToolResults)
103+
, Context(Results.get())
104+
, ThreadCount(ThreadCount)
105+
{
106+
}
107+
108+
Executor::
109+
Executor(
110+
tooling::CommonOptionsParser Options,
111+
llvm::StringRef workingDir,
112+
unsigned ThreadCount,
113+
std::shared_ptr<PCHContainerOperations> PCHContainerOps)
114+
: OptionsParser(std::move(Options))
115+
, Compilations(OptionsParser->getCompilations())
116+
, workingDir_(workingDir)
117+
, Results(new ThreadSafeToolResults), Context(Results.get())
118+
, ThreadCount(ThreadCount)
119+
{
120+
}
121+
122+
llvm::Error
123+
Executor::
124+
execute(
125+
llvm::ArrayRef<std::pair<
126+
std::unique_ptr<tooling::FrontendActionFactory>,
127+
tooling::ArgumentsAdjuster>> Actions)
128+
{
129+
if (Actions.empty())
130+
return make_string_error("No action to execute.");
131+
132+
if (Actions.size() != 1)
133+
return make_string_error(
134+
"Only support executing exactly 1 action at this point.");
135+
136+
std::string ErrorMsg;
137+
std::mutex TUMutex;
138+
auto AppendError = [&](llvm::Twine Err)
139+
{
140+
std::unique_lock<std::mutex> LockGuard(TUMutex);
141+
ErrorMsg += Err.str();
142+
};
143+
144+
auto Log = [&](llvm::Twine Msg)
145+
{
146+
std::unique_lock<std::mutex> LockGuard(TUMutex);
147+
llvm::errs() << Msg.str() << "\n";
148+
};
149+
150+
std::vector<std::string> Files;
151+
#if 0
152+
llvm::Regex RegexFilter(Filter);
153+
for (const auto& File : Compilations.getAllFiles())
154+
{
155+
if (RegexFilter.match(File))
156+
Files.push_back(File);
157+
}
158+
#else
159+
Files = Compilations.getAllFiles();
160+
#endif
161+
// Add a counter to track the progress.
162+
const std::string TotalNumStr = std::to_string(Files.size());
163+
unsigned Counter = 0;
164+
auto Count = [&]()
165+
{
166+
std::unique_lock<std::mutex> LockGuard(TUMutex);
167+
return ++Counter;
168+
};
169+
170+
auto& Action = Actions.front();
171+
172+
{
173+
llvm::ThreadPool Pool(llvm::hardware_concurrency(ThreadCount));
174+
for (std::string File : Files) {
175+
Pool.async(
176+
[&](std::string Path) {
177+
Log("[" + std::to_string(Count()) + "/" + TotalNumStr +
178+
"] Processing file " + Path);
179+
// Each thread gets an independent copy of a VFS to allow different
180+
// concurrent working directories.
181+
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
182+
llvm::vfs::createPhysicalFileSystem();
183+
FS->setCurrentWorkingDirectory(workingDir_);
184+
tooling::ClangTool Tool(Compilations, { Path },
185+
std::make_shared<PCHContainerOperations>(), FS);
186+
Tool.appendArgumentsAdjuster(Action.second);
187+
Tool.appendArgumentsAdjuster(getDefaultArgumentsAdjusters());
188+
for (const auto& FileAndContent : OverlayFiles)
189+
Tool.mapVirtualFile(FileAndContent.first(),
190+
FileAndContent.second);
191+
if (Tool.run(Action.first.get()))
192+
AppendError(llvm::Twine("Failed to run action on ") + Path +
193+
"\n");
194+
},
195+
File);
196+
}
197+
// Make sure all tasks have finished before resetting the working directory.
198+
Pool.wait();
199+
}
200+
201+
if (!ErrorMsg.empty())
202+
return make_string_error(ErrorMsg);
203+
204+
return llvm::Error::success();
205+
}
206+
207+
#if 0
208+
class ExecutorPlugin : public tooling::ToolExecutorPlugin {
209+
public:
210+
llvm::Expected<std::unique_ptr<tooling::ToolExecutor>>
211+
create(tooling::CommonOptionsParser& OptionsParser) override
212+
{
213+
if (OptionsParser.getSourcePathList().empty())
214+
return make_string_error(
215+
"[ExecutorPlugin] Please provide a directory/file path in "
216+
"the compilation database.");
217+
return std::make_unique<Executor>(std::move(OptionsParser),
218+
ExecutorConcurrency);
219+
}
220+
};
221+
222+
static tooling::ToolExecutorPluginRegistry::Add<ExecutorPlugin> X(
223+
"all-TUs",
224+
"Runs FrontendActions on all TUs in the compilation database. "
225+
"Tool results are stored in memory.");
226+
227+
// This anchor is used to force the linker to link in the generated object file
228+
// and thus register the plugin.
229+
volatile int ExecutorPluginAnchor = 0;
230+
#endif
231+
232+
} // mrdox
233+
} // clang

source/AST/Execution.hpp

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//
2+
// This is a derivative work. originally part of the LLVM Project.
3+
// Licensed under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
// Copyright (c) 2023 Vinnie Falco ([email protected])
8+
//
9+
// Official repository: https://github.com/cppalliance/mrdox
10+
//
11+
12+
//===--- AllTUsExecution.h - Execute actions on all TUs. -*- C++ --------*-===//
13+
//
14+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
15+
// See https://llvm.org/LICENSE.txt for license information.
16+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
17+
//
18+
//===----------------------------------------------------------------------===//
19+
//
20+
// This file defines a tool executor that runs given actions on all TUs in the
21+
// compilation database. Tool results are deuplicated by the result key.
22+
//
23+
//===----------------------------------------------------------------------===//
24+
25+
#ifndef MRDOX_LIB_AST_EXECUTION_HPP
26+
#define MRDOX_LIB_AST_EXECUTION_HPP
27+
28+
#include <clang/Tooling/ArgumentsAdjusters.h>
29+
#include <clang/Tooling/Execution.h>
30+
#include <llvm/ADT/SmallString.h>
31+
#include <optional>
32+
33+
namespace clang {
34+
namespace mrdox {
35+
36+
/// Executes given frontend actions on all files/TUs in the compilation
37+
/// database.
38+
class Executor : public tooling::ToolExecutor
39+
{
40+
public:
41+
static const char* ExecutorName;
42+
43+
/// Init with \p CompilationDatabase.
44+
/// This uses \p ThreadCount threads to exececute the actions on all files in
45+
/// parallel. If \p ThreadCount is 0, this uses `llvm::hardware_concurrency`.
46+
Executor(
47+
tooling::CompilationDatabase const& Compilations,
48+
llvm::StringRef workingDir,
49+
unsigned ThreadCount,
50+
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
51+
std::make_shared<PCHContainerOperations>());
52+
53+
/// Init with \p CommonOptionsParser. This is expected to be used by
54+
/// `createExecutorFromCommandLineArgs` based on commandline options.
55+
///
56+
/// The executor takes ownership of \p Options.
57+
Executor(
58+
tooling::CommonOptionsParser Options,
59+
llvm::StringRef workingDir,
60+
unsigned ThreadCount,
61+
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
62+
std::make_shared<PCHContainerOperations>());
63+
64+
StringRef getExecutorName() const override
65+
{
66+
return ExecutorName;
67+
}
68+
69+
using ToolExecutor::execute;
70+
71+
llvm::Error
72+
execute(llvm::ArrayRef<std::pair<std::unique_ptr<
73+
tooling::FrontendActionFactory>,
74+
tooling::ArgumentsAdjuster>> Actions) override;
75+
76+
tooling::ExecutionContext*
77+
getExecutionContext() override
78+
{
79+
return &Context;
80+
};
81+
82+
tooling::ToolResults*
83+
getToolResults() override
84+
{
85+
return Results.get();
86+
}
87+
88+
void mapVirtualFile(StringRef FilePath, StringRef Content) override
89+
{
90+
OverlayFiles[FilePath] = std::string(Content);
91+
}
92+
93+
private:
94+
// Used to store the parser when the executor is initialized with parser.
95+
std::optional<tooling::CommonOptionsParser> OptionsParser;
96+
tooling::CompilationDatabase const& Compilations;
97+
llvm::SmallString<240> workingDir_;
98+
std::unique_ptr<tooling::ToolResults> Results;
99+
tooling::ExecutionContext Context;
100+
llvm::StringMap<std::string> OverlayFiles;
101+
unsigned ThreadCount;
102+
};
103+
104+
#if 0
105+
extern llvm::cl::opt<unsigned> ExecutorConcurrency;
106+
extern llvm::cl::opt<std::string> Filter;
107+
#endif
108+
109+
} // mrdox
110+
} // clang
111+
112+
#endif

0 commit comments

Comments
 (0)