I achieved a poorly documented thing where showing the commit to people actually helps them. To be more helpful, I now write a blog about it. May it serve as some documentation.
Our work will be in the clang and llvm project only, though you might want to add support to libc++.
LLVM only needs minor changes, 3 additional lines for LF OS. You have to add the OS to the
llvm/include/llvm/ADT/Triple.h) and detection + toString code for it in
For clang we write a new
TargetInfo (this one sets the default preprocessor definitions) and a
(this sets default flags, which linker to use, …). We also add some Code in the
Driver to use our new
Be aware of the long compile time of clang! You want to use
ccache. Also: a clang debug build is quite large.
50GB kind of large with a 2GB clang binary (
dynamically linked! not sure, maybe it was actually statically
linked). You probably want to use the release config.
The changes in llvm are pretty boring and described in the overview already. If the instructions are not enough, the rest of the process might be over your current abilities. Learn some more stuff an come back :)
Creating our new
Target means creating a new template in
clang/lib/Basic/Targets/OSTargets.h. I suggest to
copy an existing one and modify it for your needs. The most important stuff are the preprocessor definitions
you definitely need for building real stuff for your OS.
When your new
Target is added, you have to tell clang to use it in
clang/lib/Basic/Targets.cpp. Look for
the correct place in the switch-case-cascade to add your OS Triple and return your target (templated with the
You added your target? Great! Now to the bigger chunk of code, the
ToolChain. A ToolChain in clang is a
combination of compiler, assembler, linker and stuff… the toolchain ¯\_(ツ)_/¯
To create your own ToolChain, create a new class in
clang/lib/Driver/ToolChains (I called mine LFOS). You
.h and a
.cpp file. You can copy an existing one that matches your OS a bit (I used Fuchsia a lot)
or use the LF OS commit linked below as a reference.
The basic idea is to set the correct flags to find headers and libraries, add some static libraries if required, select a runtime (libgcc or compiler-rt), select a C++ stdlib implementation (libstdc++ or libc++) and so on.
After you have created your
ToolChain, you have to tell clang when to use it. Go into
clang/lib/Driver/Driver.cpp and add an include for your toolchain header. Also add a new case in
for your OS.
For LF OS I had to add some more cases in
tell clang not to use random additional default directories. I just added LF OS whereever I found Fuchsia
Side note: if you have problems with a dash in your OS name which you have replaced by an underscore in the
triple and clang not finding the compiler-rt or something: add a case to
clang/lib/Driver/ToolChain.cpp:getOSLibName. See the LF OS commit for reference.
Define your OS triple. I use
x86_64-pc-lf_os. Make LLVM know about the OS component. Add a target in
OSTarget.h and a Toolchain in
clang/lib/Driver/ToolChains. Make the
Driver know about your toolchain.
Maybe tweak some more random things.
I was surprised how fast I was able to find the things I have to change. The codebase is very clean, way cleaner than I expected for a compiler. The community is friendly, a fix in libc++ was appreciated and merged, the discussion helped me learn things (having my code reviewed by a member of the C++ standards committee was a bit intimidating ^^’).
A great new feature for clang would be to load a new operating system from a config file, maybe from sysroot. You’d never have to change clang for a hobby OS then as you could just write that config (clang is always able to cross-compiler to whatever target you may find).
Feel free to copy, remix, share. Attribution would be nice but is not required.