đ
Yours truly is not an expert in compilers, but does enjoy diving into this topic and learning something new from time to time.
This post is split up into 3 pages.
- Part 1. Installing Clang’s build dependencies
- Part 2. Generating a solution and building it.
- Part 3. Running tests, debugging Clang’s source code. <– You are here.
Working with the codebase
Clang/LLVM’s codebase includes a lot of .inc
and .def
files. These are just normal C++ code. But by default VS doesn’t recognize them as such. Addressing this is really easy. Navigate to Tools > Options > Text Editor > File Extensions. Type in .inc
into the Extension: filed, pick Microsoft Visual C++ from the Editor dropdown, click the Add button. Repeat for .def
. To complete the configuration click OK. Done.
Debugging
Inspecting data structures
Make sure you didn’t miss these portions of Hacking on Clang
Dump
- Many LLVM and Clang data structures provide a
dump()
method which will print a description of the data structure tostderr
.- The
QualType
structure is used pervasively. This is a simple value class for wrapping types with qualifiers; you can use theisConstQualified()
, for example, to get one of the qualifiers, and thegetTypePtr()
method to get the wrappedType*
which you can thendump
.â Debugging
Let’s see an example of using dump()
.
Hitting a breakpoint and invoking dump()
from Immediate Window looks similar to this.
Visualizers
The files
llvm/utils/LLVMVisualizers/llvm.natvis
andclang/utils/ClangVisualizers/clang.natvis
provide debugger visualizers that make debugging of more complex data types much easier.For Visual Studio 2013 only, put the files into
%USERPROFILE%\Documents\Visual Studio 2013\Visualizers
or create a symbolic link so they update automatically.For later versions of Visual Studio, no installation is required. Note also that later versions of Visual Studio also display better visualizations.
Attaching to a child process
Clang used to always start a child process to carry out actual compilation. This has changed, now whenever possible everything happens in the same process. Look for the following portion of code of clang_main
in llvm-project/clang/tools/driver/driver.cpp
:
if (!UseNewCC1Process) {
TheDriver.CC1Main = [ToolContext](SmallVectorImpl<const char *> &ArgV) {
return ExecuteCC1Tool(ArgV, ToolContext);
};
// Ensure the CC1Command actually catches cc1 crashes
llvm::CrashRecoveryContext::Enable();
}
That said, there are compilation scenarios a child process has to be started for â translating source code into an executable is an example of one, actually. Or you may simply be working with an older codebase, where always starting a child process is still a thing.
Breakpoints placed in the code executed by child process aren’t going to be hit. So, here are a couple approaches to make VS actually stop at such breakpoints.
- Install the extension Microsoft Child Process Debugging Power Tool that makes VS automatically attach to any child process spawned from a process you’re already debugging.
- Look into calling the
DebugBreak
system function or placing the__debugbreak
intrinsic into the code. - See if changing
clang_main
such that it does not spawn a new process is possible and is an option for you.
Running tests
Hacking on Clang gives hints on running Clang’s test suite on Windows from Visual Studio or the command line.
Visual Studio
As the guide explains, a number of VS projects generated by CMake is configured to run tests. Building such a project results in running its group of tests. To run Clang’s test suite from VS, right-click the check-clang
project under Clang tests
and pick Build from the context menu. (Notice, Hacking on Clang says building clang-test
triggers the execution of test suite. But that project doesn’t start any tests for me.) One thing to keep in mind is testing a Debug
build of clang.exe
with the full test suite takes hours, at least on my machine â I actually didn’t manage to wait through to its completion. Testing a Release
build takes about 9 minutes though.
Command line
Clang/LLVM’s codebase includes a testing tool written in Python called LLVM Integrated Tester or lit
. We can use lit
to run a single or multiple tests from the command line. A command to run the entire Clang’s test suite looks like this1:
PS > cd llvm-pod/vs-2022-1
PS > python ../llvm-project/llvm/utils/lit/lit.py -sv --param=build_mode=Release ./tools/clang/test
It departs from the command line given in the Hacking on Clang page in a couple of ways.
PS > python (path to llvm)\llvm\utils\lit\lit.py -sv `
--param=build_mode=Win32 --param=build_config=Debug `
--param=clang_site_config=(build dir)\tools\clang\test\lit.site.cfg `
(path to llvm)\llvm\tools\clang\test
Let’s quickly go over the differences.
- It factors in the folder structure discussed earlier.
build_config
andclang_site_config
are absent. I might be missing something, butlit
seems to ignore these parameters as their values a) don’t affect test executions in any way and b) I could not find any traces of them in the source code oflit
inllvm-project\llvm\utils\lit
.- The value of
build_mode
is used to form the path to the Clang executable under test. E.g.,vs-2022-1/Debug/bin/clang.exe
forbuild_mode=Debug
; orvs-2022-1/RelWithDebInfo/bin/clang.exe
forbuild_mode=RelWithDebInfo
, etc. - The path to the test suite (
./tools/clang/test
) points to the build tree (llvm-pod/llvm-project
) in contrast to pointing to the source tree â(path to llvm)\llvm\tools\clang\test
. The inner functionssearch
, andsearch1
fromgetTestSuite
inllvm-project\llvm\utils\lit\lit\discovery.py
work their way upwards through the supplied path in the build tree from a child folder to its parent folder until they discover alit.site.cfg.py
test config file. Then they switch to the “symmetrical” path in the source tree (llvm-pod/llvm-project/...
) and collect test cases there.
A command to run an individual test is:
PS > cd llvm-pod/vs-2022-1
PS > python ../llvm-project/llvm/utils/lit/lit.py -sv --param=build_mode=Debug ./tools/clang/test/Sema/wchar.c
It again differs from the documentation’s command line. The reasons for changes are the same as discussed above.
Conclusion
That’s it, and that’s all. Happy hacking!
The
cd
commands are intended to indicate the location for executing subsequent commands. If you’ve already navigated there, ignore them, of cousre :) ↩︎