ROllerozxa
Screenshot of the top of CCC's readme that says: 'A C compiler written entirely from scratch in Rust, targeting x86-64, i686, AArch64, and RISC-V 64. Zero compiler-specific dependencies - the frontend, SSA-based IR, optimizer, code generator, peephole optimizers, assembler, linker, and DWARF debug info generation are all implemented from scratch. Claude's C Compiler produces ELF executables without any external toolchain.'

Trying Out Claude's C Compiler

On the 5th of February Anthrophic published an article on their engineering blog detailing the creation of a C compiler using a team of parallel Claude agents over the course of two weeks. The compiler in question is called Claude’s C Compiler (ccc for short) and is a ~180k line Rust codebase that they published onto GitHub.

Of course, this announcement raised a lot of questions about the accuracy of their claims and the usability of the compiler, as well as the implications of a swarm of AI agents allegedly being able to write a full C compiler. It claims to be able to compile the Linux kernel, along with many other high profile C projects, but does it actually work? I became intrigued, and decided to try compiling a Hello World program, my game Tensy, ClassiCube, and finally the Linux kernel.

Technical details

The compiler is written exclusively in Rust and is about 186k lines of code when running wc -l on the source directory. Some of the bulk of the codebase can be attributed to containing four different backends for x86_64, i686, ARM64 and 64-bit RISC-V, each backend’s directory being around 20k lines of code on average.

Gource visualisation of the directory structure for the src folder. Labels are the names of each directory.
Gource visualisation of the directory structure for the src folder. Labels are the names of each directory.

It probably goes without saying that having such a massive codebase solely generated by AI with just a little bit of human assistance is completely unmaintainable, and it sits at the very extreme end of throwaway vibe coded pet projects. While some people seem to have peaked their interest in it and are now opening pull requests to the repository, I assume they will be completely ignored from Anthropic’s side going forward. (…Unless they task a Claude bot to maintain the repository and review PRs…)

I don’t know enough Rust to make any assessment on how good the code quality is, but there are undoubtedly issues that likely slipped in throughout the process that do not surface simply by compiling existing well-formed C projects that are known to compile. Just one thing I noticed while testing it out was that line numbers displayed in compiler error messages were seemingly off by one. It’s one of those kinds of logic issues that you are not safe from even if you are using a memory safe language such as Rust.

Screenshot of a terminal and a text editor open side-by-side with some SDL code. Two error messages that reference a line 557 are actually situated on line 558 in the text editor, and an error that references line 561 is actually on line 562.

However, I could not find a single place in the codebase where it uses unsafe, and it is completely self-contained with no third-party Rust library dependencies making it relatively quick to build for Rust standards (40 seconds on my machine). I guess it has that going for it.

While it does claim to be dependency-free, it does of course rely on a Rust compiler to be built, and it also relies on both glibc and GCC headers to build. And while it does claim to have its own assembler and linker, it’s buggy and recommends using GNU’s assembler and linker instead. Which is probably for the better.

The compiler’s main claim to fame in terms of capability is that it claims to be able to compile the Linux kernel, which is by no means a small feat due to it being a very large codebase with a lot of GCC-specific extensions being used. However a general purpose compiler needs to be able to compile more than one specific program, and AI code agents tend to have a brute force kind of approach that may make one program work, while other programs remain broken. Let’s start with something simple.

Can it compile Hello World?

Yes it can, actually.

When the source code for it was originally published, the first issue that was opened on the repository was about how it could not compile a simple hello world program with the instructions provided in the README, which was mildly amusing and was my first experience with the compiler as well.

// hello.c
#include <stdio.h>
int main(void) {
    printf("Hello from CCC!\n");
    return 0;
}
>>> ./target/release/ccc hello.c -o hello
/usr/include/stdio.h:34:10: error: stddef.h: No such file or directory
/usr/include/stdio.h:37:10: error: stdarg.h: No such file or directory
ccc: error: 2 preprocessor error(s) in hello.c

However, if you’re a bit more familiar with the composition of standard C headers, you would probably recognise that stddef.h and stdarg.h are headers that are generally not provided by the C standard library. Instead they are specific to the compiler and typically bundled with it. Indeed, ccc does have a list of hardcoded paths it checks for to make use of GCC’s headers, but it only goes up to GCC 14. I’m using GCC 15, and so was the person who tried to build the Hello World example, explaining why it could not find the headers.

I searched for where GCC’s headers were installed on my system, and located them at /usr/lib/gcc/x86_64-pc-linux-gnu/15.2.1/include. You can also find it by running the following command with GCC:

>>> gcc -print-file-name=include
/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.1/include

Passing that path as another include directory with -I then made it work:

>>> ./target/release/ccc -I/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.1/include hello.c -o hello
>>> ./hello
Hello from CCC!

Great, now this monstrosity can generate a program, allowing it to execute arbitrary code on my computer. Not at all concerning.

Building Tensy

Tensy is a rather simple puzzle game I worked on last year. It is entirely written in C and primarily only has SDL3 as its main dependency, making it very portable. Will that include different compilers? Well, I have managed to compile it with slimcc in the past, but more on that later…

First of all trying to run the CMake configuration just by pointing at the compiler executable will not work, because of the beforementioned issue with headers. We’ll need to both specify the path to the compiler, as well as the path to the GCC headers:

cmake .. \
    -DCMAKE_C_COMPILER=/home/rollerozxa/temp/claudes-c-compiler/target/release/ccc \
    -DCMAKE_C_FLAGS="-I/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.1/include" \
    -G Ninja

The CMake configuration is successful, but when it comes to building SDL it absolutely vomits out errors related to intrinsics functions in headers included by SDL as well a strange backtrace with endless lines of including SDL_internal.h over and over again.

'warning: implicit declaration of function [so-and-so]' 3x, then a backtrace that ends up repeating SDL_internal.h:1 over and over again.

If you check the source repository of ccc, you’ll see that there is an include directory containing some headers for intrinsics that are compatible with the compiler. Putting that path as an additional include directory before GCC’s, overriding its intrinsics headers gets things a bit further along:

cmake .. \
    -DCMAKE_C_FLAGS="-I/home/rollerozxa/temp/claudes-c-compiler/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.1/include"

…Then it once again throws errors about other things. I assume there is some kind of incompatibility between ccc and the glibc headers that makes the relevant things not be defined, leading to these errors and warnings about things being undeclared.

In the end, I decided to not go further into trying to get SDL built with the compiler and instead made a change in the CMakeLists to link against the version of SDL3 I have on my system. Now it is able to build an executable, which at least shows that all of my own code builds, as well as other vendored libraries I use such as SDL3_mixer and libxmp.

>>> ninja
[0/2] Re-checking globbed directories...
[70/71] Linking C executable tensy

And the resulting binary… works!

Screenshot of Tensy running from a terminal visible on the left. The toast message in the main menu says 'Built by GCC 14.2'

Pressing the platform name in the bottom-left of Tensy’s main menu shows a toast message with the compiler and version used to build it. The compiler seems to pretend to be GCC 14.2.0, and it unfortunately does not define any specific macro to distinguish it from GCC.

Looking at the binary produced (I also set FORCE_LOOSE_ASSET_LOADING=1 to make Tensy not embed its assets into the binary), the size of it is 1.7 MiB. Tensy is a bad game to try to benchmark the runtime performance from optimisations (it’s really not a demanding game), but just comparing the binary filesize against an equivalent release build of Tensy with GCC (linked to system SDL, and loose asset loading), the binary is 823 KiB in size. I have no idea what optimisations the compiler is doing, but I assume it is not doing much at all.

ClassiCube

After getting Tensy to build with ccc but with some caveats, I was thinking of some other kind of C project I could try building with it.

I then came to think of ClassiCube, which nowadays is a Minecraft Classic clone written from the ground up in C. The ClassiCube codebase is unfathomably portable, and has been ported to dozens of platforms including many game consoles, as well as supporting a lot of different compilers. This should be pretty straightforward.

I cloned the source code and threw in all the stuff I’ve previously used above into a make call to build the game:

make CC=/home/rollerozxa/temp/claudes-c-compiler/target/release/ccc \
    CFLAGS="-I/home/rollerozxa/temp/claudes-c-compiler/include -I/usr/lib/gcc/x86_64-pc-linux-gnu/15.2.1/include"

And… yes, of course it builds. I’m not really surprised.

Screenshot of ClassiCube running, on top of a terminal showing the build output.

ClassiCube is really not a demanding game either, so it’s difficult to say anything about performance here. I enabled the few fancy graphics options it had and it still runs at four digit frame rates if I disable the frame rate cap. Utterly ridiculous.

Okay, now what about the Linux kernel?

I didn’t actually intend to do this, but after looking at the BUILDING_LINUX.txt file containing instructions for how to build the Linux kernel with ccc I just felt like I had to try out the final boss of this slopfest when I had all the commands laid out in front of me. Building the Linux kernel, for RISC-V specifically.

The instructions are for cross-compiling a Linux kernel for 64-bit RISC-V and then running it in QEMU, so you’ll need to have a RISC-V toolchain installed for the linker and other things, as well as QEMU’s RISC-V system emulator. On Arch these were the packages I had to install:

sudo pacman -S riscv64-linux-gnu-binutils riscv64-linux-gnu-gcc qemu-system-riscv bc

First off, we’re building Linux 6.9, which is a bit old now but I assume it is the last version of the kernel that can be built without a Rust compiler, or some other reason. Of course, we have a Rust compiler to build ccc, but I guess they wanted to keep things simple.

wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.9.tar.xz
tar -xf linux-6.9.tar.xz && cd linux-6.9/

Then build it, replacing the path to where you’ve got your built ccc compilers.

export CCC=/home/rollerozxa/temp/claudes-c-compiler/target/release

make ARCH=riscv CC=$CCC/ccc-riscv HOSTCC=$CCC/ccc-x86 CROSS_COMPILE=riscv64-linux-gnu- defconfig
make ARCH=riscv CC=$CCC/ccc-riscv HOSTCC=$CCC/ccc-x86 CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc) Image

This should result in a bootable Linux kernel image at arch/riscv/boot/Image.

Then download and build BusyBox for a minimal userland:

wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar xf busybox-1.36.1.tar.bz2 && cd busybox-1.36.1

make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- defconfig
sed -i 's/# CONFIG_STATIC is not set/CONFIG_STATIC=y/' .config
sed -i 's/CONFIG_TC=y/# CONFIG_TC is not set/' .config

make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -j$(nproc)

…I’m following the instructions here exactly like they were written, which means building BusyBox with a regular RISC-V GCC toolchain, not with ccc. I don’t know if ccc can build BusyBox or not, but I wasn’t particularly interested in going down that detour at this point. The Linux kernel is what is important!

Once that is all built, grab the contents for the basic-init and initramfs.list files from the BUILDING_LINUX.txt file, and then build the initramfs image:

usr/gen_init_cpio initramfs.list | gzip -9 > initramfs.cpio.gz

Now after all that is done, boot it with QEMU:

qemu-system-riscv64 -M virt -m 512 \
    -kernel arch/riscv/boot/Image \
    -initrd ./initramfs.cpio.gz \
    -append "console=ttyS0" \
    -nographic -no-reboot

The terminal should become the console for the VM, and you’ll see the Linux kernel’s log output as it boots up.

Linux version 6.9.0 (rollerozxa@archbox) (ccc (Claude's C Compiler, GCC-compatible) 14.2.0, GNU ld (GNU Binutils) 2.44) #1 SMP Fri Feb  6 19:53:07 CET 2026

Success! Then after letting it boot, the BusyBox shell prompt appears.

Running uname -a in the BusyBox shell

I’ve uploaded my resulting build of the Linux kernel along with the initramfs image to the Internet Archive if you just want to boot it up. You could also build more stuff for RISC-V and add it to the initramfs image if you want to do more with it, but I think that’s enough for me.

Closing thoughts

Overall it’s an interesting experiment, and shows the current bleeding edge of Claude’s Opus 4.6 model. However the resulting product is also a clear example of the throwaway nature of projects generated almost entirely by AI code agents with little human oversight. The prototype is really impressive, but there is no real path forward for it to be further developed.

It can build the Linux kernel, which is impressive. It can also build other things… if you are lucky, but you really cannot rely on it to work. It is a neat party trick. In fact, I wonder how much the compute for the full development cost?

Over nearly 2,000 Claude Code sessions across two weeks, Opus 4.6 consumed 2 billion input tokens and generated 140 million output tokens, a total cost just under $20,000.

…It was a very expensive party trick.

The fact it managed to spit out 185k lines of functioning Rust code that can compile C code also raises some questions about how it managed to write all of that code. Due to how it was provided GCC as a compiler oracle to compare against when the new compiler had errors compiling code, it is not unlikely that it ended up being architectured in a way similar to GCC, not too dissimilar to a clean room implementation. This does not take into account what it may have learned from the datasets of source code it was originally trained on however.

Some people have described this as a form of code laundering, now being able to rewrite a GPL licensed software into a new more permissively licensed codebase at scale with AI code agents, negating the freedoms that the GPL was designed to provide. When it comes to C compilers, the permissively licensed Clang already exists, but there may be other parts of the GNU stack that would be at risk — the permissive MIT license of the Rust coreutils project has already been a point of contention compared to the GPL licensed GNU coreutils or BusyBox.

And of course, the blog post also goes over some of the limitations of the compiler, some of which I’ve briefly touched on above as well:

  • It lacks the 16-bit x86 compiler that is necessary to boot Linux out of real mode. For this, it calls out to GCC (the x86_32 and x86_64 compilers are its own).
  • It does not have its own assembler and linker; these are the very last bits that Claude started automating and are still somewhat buggy. The demo video was produced with a GCC assembler and linker.
  • The compiler successfully builds many projects, but not all. It’s not yet a drop-in replacement for a real compiler.
  • The generated code is not very efficient. Even with all optimizations enabled, it outputs less efficient code than GCC with all optimizations disabled.
  • The Rust code quality is reasonable, but is nowhere near the quality of what an expert Rust programmer might produce.

It’s not gonna replace GCC or Clang anytime soon, it will simply just be another project stored in the archives of GitHub. But at least it was a fun thing to play around with.

A note about slimcc

I mentioned this earlier that I had successfully gotten Tensy to build with slimcc in the past. slimcc is a very minimal C compiler (forked from chibicc), but it still has support for a lot of C features (including C2Y drafts!). It is only about 20k lines of C code yet can boast about being able to build a big number of various C projects, which gets tested in CI so you just don’t have to take the word of an AI generated README file for it.

I don’t know whether it can compile the Linux kernel, but from the huge amounts of programs and libraries that they compile in CI using it, I would say it seems pretty reliable at compiling anything else you may throw at it. But of course, being a minimal C compiler, it has the same limitations when it comes to optimised code generation, and the difference in compile speeds for unoptimised debug builds between it and GCC or Clang are negligible in my experience.

However you don’t need to be a compiler engineer to build something with it, just set it as the C compiler and build after you’ve compiled it:

cmake .. -DCMAKE_C_COMPILER=/home/rollerozxa/temp/slimcc/slimcc
make -j12

I tried building Tensy again with the latest version of slimcc for this blog post and it still works without any issues, including building SDL from source.

Screenshot of Tensy with the terminal to the side. The toast message says 'Built by slimcc'

slimcc also identifies itself using the __slimcc__ macro, so it is possible to check for it in the compiler version toast message in Tensy.


Donations

Did you find the blog post to be informative, amusing or otherwise interesting? All blog posts are written by a human who would appreciate a donation if you got some value out of this piece of writing.