đ
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
QualTypestructure 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.natvisandclang/utils/ClangVisualizers/clang.natvisprovide 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\Visualizersor 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
DebugBreaksystem function or placing the__debugbreakintrinsic into the code. - See if changing
clang_mainsuch 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_configandclang_site_configare absent. I might be missing something, butlitseems 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 oflitinllvm-project\llvm\utils\lit.- The value of
build_modeis used to form the path to the Clang executable under test. E.g.,vs-2022-1/Debug/bin/clang.exeforbuild_mode=Debug; orvs-2022-1/RelWithDebInfo/bin/clang.exeforbuild_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, andsearch1fromgetTestSuiteinllvm-project\llvm\utils\lit\lit\discovery.pywork 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.pytest 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
cdcommands are intended to indicate the location for executing subsequent commands. If you’ve already navigated there, ignore them, of cousre :) ↩︎