llvm-cbe: reviving an LLVM backend that turns IR back into portable C
resurrected LLVM "C Backend", with improvements
At a glance
- What is it?
- llvm-cbe is an LLVM code generator that emits C from LLVM IR, resurrected by Julia Computing and pinned to the latest LLVM release, currently 22. The trade is a readable, compilable C file in exchange for the optimisations a native backend would have applied, and the project is explicit about it: only the newest LLVM is supported on the head branch.
- Who is it for?
- llvm-cbe suits a project that needs a readable and portable C artefact from a piece of LLVM IR, whether for an auditable build, a target without a native LLVM backend, or a compilation step that has to be inspectable.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 75 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the backend does: IR in, C out, and then a real compiler
The README describes llvm-cbe as an LLVM C backend that has been resurrected by Julia Computing with various improvements. The pipeline it implements is visible in the usage example, and it is worth walking through because the whole design is in it. You take a C file, compile it to LLVM IR with clang using the emit-llvm flag, and then run llvm-cbe on the .ll file to produce a .cbe.c file. That generated C is then compiled with gcc into an executable, which you run. So the backend is a translation step in the middle of a normal toolchain, and its output is a source file rather than an object file. The reason this is useful is that the resulting C is portable and readable, and a build that must be inspected, audited or shipped to a machine without the original toolchain can be handed the C and nothing else.
selectionsort$ clang-22 -S -emit-llvm -g main.c
selectionsort$ ls
main.c main.ll
selectionsort$ ../../build/tools/llvm-cbe/llvm-cbe main.llThe version policy is one LLVM at a time, and the reason is stated
The FAQ on the version update policy is short and unusually honest about why. The policy of this project is to only support the latest released version of LLVM on the head of the repository. The rationale is that supporting multiple versions is additional work for a project which has no sponsors. And since there are very few changes other than version compatibility maintenance, anyone using an older version of LLVM can just checkout the last commit to work on that branch. The link is to an issue in the repository where the discussion is held. Two things follow for an adopter. The current version works with LLVM 22, and older versions are available through the tags. And a project that has to support several LLVM versions is committing to maintaining patches itself, which for a backend with few functional changes is mostly mechanical but not free.
Building LLVM 22 is step one, and the distributions may not have it
The installation instructions make LLVM the first task, with two routes. You can install the packages from your system, and the README gives the exact commands per distribution. On macOS, use pkgsrc and run pkgin in llvm clang ninja-build. On CentOS, install the llvm-devel package with dnf install llvm-devel clang ninja-build. On Debian and derivatives, install the llvm-dev package with apt install llvm-22-dev clang-22 ninja-build. The warning that follows is the practical one: this project uses LLVM 22, so make sure the package manager is installing it and not some other version, and at the time of writing Ubuntu 24.04 LTS installs version 18. So on a current Ubuntu you either need a newer repository, a different distribution, or you build LLVM yourself. The compile-it-yourself route clones the llvm-project repository at the llvmorg-22.1.8 tag with a shallow clone, configures with CMake and the Ninja generator, and builds. It also notes that to convert C to LLVM IR to run the tests you need a C compiler using the LLVM infrastructure, such as clang, and that to run the tests you need to build lli.
~$ git clone --single-branch --branch llvmorg-22.1.8 --depth 1 https://github.com/llvm/llvm-project.git
~$ cd llvm-project
llvm-project$ mkdir llvm/build
llvm-project$ cd llvm/build
build$ cmake .. -G "Ninja" -DCMAKE_BUILD_TYPE=Debug -DLLVM_PARALLEL_LINK_JOBS=1
build$ ninjaBuilding the backend, and where the source tree has to sit
Step two is compiling llvm-cbe, and the placement depends on how you got LLVM. If you built LLVM yourself, the backend goes into the LLVM source tree, because that is how an LLVM out-of-tree component is built. You move to the llvm-project/llvm/projects directory, clone llvm-cbe there, go back to the build directory, and run cmake with the Ninja generator followed by ninja llvm-cbe. If you used your distribution's package, you clone llvm-cbe anywhere you like, create a build directory, configure with cmake and build the same target. The repository layout at the top level is the familiar LLVM component arrangement, with a lib/ directory, a test/ directory, a tools/ directory, an unittests/ directory, a runtime/ directory, a docs/ directory, a CMakeLists.txt, a Dockerfile and a docker-compose.yml. The CMake target name is the same in both cases, which is the one detail that has to be right.
~$ cd llvm-project/llvm/projects
projects$ git clone https://github.com/JuliaHubOSS/llvm-cbe
projects$ cd ../build
build$ cmake .. -G "Ninja"
build$ ninja llvm-cbeOptions are prefixed --cbe-, and the help output is the reference
The README says you can find options to configure the C backend's output with llvm-cbe --help, and to look for options beginning with --cbe-. That naming convention is a small but useful detail, because the backend shares a binary with nothing else and a uniform prefix makes the options findable in a long help listing. The usage example also shows the input file naming convention, where llvm-cbe on main.ll produces main.cbe.c, and then gcc -o main.cbe main.cbe.c produces the executable. The result of running the whole pipeline is a directory containing main.c, main.cbe, main.cbe.c and main.ll, which is a useful picture of the artifact chain: original source, intermediate IR, generated C, and the compiled program.
selectionsort$ gcc -o main.cbe main.cbe.c
selectionsort$ ls
main.c main.cbe main.cbe.c main.ll
selectionsort$ ./main.cbeTwo test suites: CWriterTest in the LLVM tree and pytest in the backend
Testing is described in two parts. The unit tests are built inside the LLVM build tree, with make CBEUnitTests followed by running projects/llvm-cbe/unittests/CWriterTest, and there are two prerequisites worth noting. You need to have passed -DLLVM_INCLUDE_TESTS=1 to cmake if you used your distribution's LLVM package, since the distribution build will not have the test targets enabled, and you also need gtest installed, which on Debian derivatives means libgtest-dev. The other tests are run from the llvm-cbe directory with pytest, after compiling llvm-cbe and installing pytest, and you might have to adjust the llvm-cbe and lli paths in the configuration. The last detail is the one that matters on a machine with many cores, since installing pytest-xdist will let you run the suite in parallel, for example with pytest -n 4 for four cores.
llvm-project$ cd llvm/build
build$ make CBEUnitTests && projects/llvm-cbe/unittests/CWriterTestllvm-cbe$ pytestThe Docker path is out of date, and that tells you about the project
The repository has a Dockerfile and a docker-compose.yml, and the compose file is a nice compact demonstration of the pipeline. It builds from the Dockerfile, mounts the test directory, and runs a script that changes into the hello_world test, compiles main.c to LLVM IR with clang, compiles the IR back to C with llvm-cbe, compiles the generated C with gcc and runs the result. The Dockerfile, however, fetches LLVM 8.0.0 from releases.llvm.org, unpacks it into /root/llvm, copies the backend into the projects directory, builds llvm-cbe, lli and CBEUnitTests, runs the unit test, and symlinks the binary into /bin. The base image is buildpack-deps:stretch. So the container path is pinned to a much older LLVM than the one the README documents, which is a mismatch a reader should notice rather than discover at build time. The repository is not archived, the last push was on 2026-08-11, and there are no GitHub releases.
Editorial conclusion
llvm-cbe suits a project that needs a readable and portable C artefact from a piece of LLVM IR, whether for an auditable build, a target without a native LLVM backend, or a compilation step that has to be inspectable. It is the wrong choice if you care about the performance of the generated code, because the point of the backend is C that a normal compiler will recompile, and a poor fit if you need to support several LLVM versions at once, since the stated policy is to support only the latest released LLVM on the head of the repository. Before building it, read the FAQ on the version update policy, install LLVM 22 rather than whatever your distribution ships, since Ubuntu 24.04 LTS is noted as installing version 18, and note that the Dockerfile in the repository still fetches LLVM 8.0.0.
Frequently asked questions
What is llvm-cbe and who maintains it?
It is an LLVM C backend, a code generator that emits C from LLVM IR, which has been resurrected by Julia Computing with various improvements. The primary language is C++ and the repository is hosted under JuliaHubOSS.
Which LLVM version does llvm-cbe support?
The current version works with LLVM 22, and older versions are available through the tags. The stated policy is to support only the latest released version of LLVM on the head of the repository, because supporting multiple versions is additional work for a project which has no sponsors.
How do I install LLVM for llvm-cbe?
On Debian and derivatives use apt install llvm-22-dev clang-22 ninja-build, on CentOS dnf install llvm-devel clang ninja-build, and on macOS with pkgsrc run pkgin in llvm clang ninja-build. The README warns that the project uses LLVM 22, and that Ubuntu 24.04 LTS installs version 18, so you may need to build LLVM yourself from the llvmorg-22.1.8 tag.
How do I build and run the llvm-cbe tests?
Unit tests are built inside the LLVM build tree with make CBEUnitTests and then running projects/llvm-cbe/unittests/CWriterTest, which needs -DLLVM_INCLUDE_TESTS=1 and gtest. The other tests run with pytest from the llvm-cbe directory, and pytest-xdist lets you parallelise them, for example with pytest -n 4.
How do I configure the output of the llvm-cbe backend?
The README says to run llvm-cbe --help and look for options beginning with --cbe-. Running the backend on an .ll file produces a .cbe.c file, which you then compile with a normal compiler such as gcc.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/juliahuboss-llvm-cbe)Was this useful?