1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>LibTooling</title>
<link type="text/css" rel="stylesheet" href="../menu.css">
<link type="text/css" rel="stylesheet" href="../content.css">
</head>
<body>
<div id="content">
<h1>LibTooling</h1>
<p>LibTooling is a library to support writing standalone tools based on
Clang. This document will provide a basic walkthrough of how to write
a tool using LibTooling.</p>
<!-- ======================================================================= -->
<h2 id="intro">Introduction</h2>
<!-- ======================================================================= -->
<p>Tools built with LibTooling, like Clang Plugins, run FrontendActions over
code. <!-- See FIXME for a tutorial on how to write FrontendActions. -->
In this tutorial, we'll demonstrate the different ways of running clang's
SyntaxOnlyAction, which runs a quick syntax check, over a bunch of
code.</p>
<!-- ======================================================================= -->
<h2 id="runoncode">Parsing a code snippet in memory.</h2>
<!-- ======================================================================= -->
<p>If you ever wanted to run a FrontendAction over some sample code, for example
to unit test parts of the Clang AST, runToolOnCode is what you looked for. Let
me give you an example:
<pre>
#include "clang/Tooling/Tooling.h"
TEST(runToolOnCode, CanSyntaxCheckCode) {
// runToolOnCode returns whether the action was correctly run over the
// given code.
EXPECT_TRUE(runToolOnCode(new clang::SyntaxOnlyAction, "class X {};"));
}
</pre>
<!-- ======================================================================= -->
<h2 id="standalonetool">Writing a standalone tool.</h2>
<!-- ======================================================================= -->
<p>Once you unit tested your FrontendAction to the point where it cannot
possibly break, it's time to create a standalone tool. For a standalone tool
to run clang, it first needs to figure out what command line arguments to use
for a specified file. To that end we create a CompilationDatabase.</p>
<h3 id="compilationdb">Creating a compilation database.</h3>
<p>CompilationDatabase provides static factory functions to help with parsing
compile commands from a build directory or the command line. The following code
allows for both explicit specification of a compile command line, as well as
retrieving the compile commands lines from a database.
<pre>
int main(int argc, const char **argv) {
// First, try to create a fixed compile command database from the command line
// arguments.
llvm::OwningPtr<CompilationDatabase> Compilations(
FixedCompilationDatabase::loadFromCommandLine(argc, argv));
// Next, use normal llvm command line parsing to get the tool specific
// parameters.
cl::ParseCommandLineOptions(argc, argv);
if (!Compilations) {
// In case the user did not specify the compile command line via positional
// command line arguments after "--", try to load the compile commands from
// a database in the specified build directory.
std::string ErrorMessage;
Compilations.reset(CompilationDatabase::loadFromDirectory(BuildPath,
ErrorMessage));
// If there is still no valid compile command database, we don't know how
// to run the tool.
if (!Compilations)
llvm::report_fatal_error(ErrorMessage);
}
...
}
</pre>
</p>
<h3 id="tool">Creating and running a ClangTool.</h3>
<p>Once we have a CompilationDatabase, we can create a ClangTool and run our
FrontendAction over some code. For example, to run the SyntaxOnlyAction over
the files "a.cc" and "b.cc" one would write:
<pre>
// A clang tool can run over a number of sources in the same process...
std::vector<std::string> Sources;
Sources.push_back("a.cc");
Sources.push_back("b.cc");
// We hand the CompilationDatabase we created and the sources to run over into
// the tool constructor.
ClangTool Tool(*Compilations, Sources);
// The ClangTool needs a new FrontendAction for each translation unit we run
// on. Thus, it takes a FrontendActionFactory as parameter. To create a
// FrontendActionFactory from a given FrontendAction type, we call
// newFrontendActionFactory<clang::SyntaxOnlyAction>().
int result = Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
</pre>
</p>
<h3 id="main">Putting it together - the first tool.</h3>
<p>Now we combine the two previous steps into our first real tool. This example
tool is also checked into the clang tree at tools/clang-check/ClangCheck.cpp.
<pre>
#include "llvm/Support/CommandLine.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/Tooling.h"
using namespace clang::tooling;
using namespace llvm;
cl::opt<std::string> BuildPath(
cl::Positional,
cl::desc("<build-path>"));
cl::list<std::string> SourcePaths(
cl::Positional,
cl::desc("<source0> [... <sourceN>]"),
cl::OneOrMore);
int main(int argc, const char **argv) {
llvm::OwningPtr<CompilationDatabase> Compilations(
FixedCompilationDatabase::loadFromCommandLine(argc, argv));
cl::ParseCommandLineOptions(argc, argv);
if (!Compilations) {
std::string ErrorMessage;
Compilations.reset(CompilationDatabase::loadFromDirectory(BuildPath,
ErrorMessage));
if (!Compilations)
llvm::report_fatal_error(ErrorMessage);
}
ClangTool Tool(*Compilations, SourcePaths);
return Tool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>());
}
</pre>
</p>
<h3 id="running">Running the tool on some code.</h3>
<p>When you check out and build clang, clang-check is already built and
available to you in bin/clang-check inside your build directory.</p>
<p>You can run clang-check on a file in the llvm repository by specifying
all the needed parameters after a "--" separator:
<pre>
$ cd /path/to/source/llvm
$ export BD=/path/to/build/llvm
$ $BD/bin/clang-check . tools/clang/tools/clang-check/ClangCheck.cpp -- \
clang++ -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS \
-Itools/clang/include -I$BD/include -Iinclude -Itools/clang/lib/Headers -c
</pre>
</p>
<p>As an alternative, you can also configure cmake to output a compile command
database into its build directory:
<pre>
# Alternatively to calling cmake, use ccmake, toggle to advanced mode and
# set the parameter CMAKE_EXPORT_COMPILE_COMMANDS from the UI.
$ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .
</pre>
</p>
<p>
This creates a file called compile_commands.json in the build directory. Now
you can run clang-check over files in the project by specifying the build path
as first argument and some source files as further positional arguments:
<pre>
$ cd /path/to/source/llvm
$ export BD=/path/to/build/llvm
$ $BD/bin/clang-check $BD tools/clang/tools/clang-check/ClangCheck.cpp
</pre>
</p>
</div>
</body>
</html>
|