New project - dmake: A build system with CMake as input language
Weird I started a new project - a (going to be, mostly) CMake compatible build system. Source not released yet as it is early stage. But it seems promising so I'll write about it. Despite the many efforts to improve the C/C++ build systems, notably Meson and Ninja did a great job, CMake remains the Lingua Franca of the C/C++ world. But CMake sucks in my very own and limited opinion. The splitting of configuration and build phase causes many, many problems. The most (in-)famous being GLOB isn't evaluated at build time. Often leading to wild goose chases on why files aren't compiled. Only to fugure a reconfiguration is needed. But also you can't expect people to switch to Meson and endure the pain of manually integrating with projects using CMake.
And I will be the 1st one to admit this project is largly enabled by AI. I don't have enough time on hand to implement a project of this scale.
So, dmake. An actual build system that eats CMakeLists.txt as the input source, runs it, avoids most of the caching traps, does it's own dependency tracking and builds. Be it it's more of a toy right now.
It is not perfectly compatible, the CMake language is a bit of a mess. And a long way to go to get the CMake built-ins implemented. But good enough that it can self host and provide a better (and more opinionated) experience.
Let me show you. Being a implementation of CMake. The project can be built by CMake.
❯ cmake ..
-- The C compiler identification is GNU 15.2.1
-- The CXX compiler identification is GNU 15.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done (0.3s)
-- Generating done (0.0s)
-- Build files have been written to: /home/marty/Documents/dmake/build
❯ make -j
[ 19%] Building CXX object CMakeFiles/dmake.dir/dmake/cache_store.cpp.o
[ 19%] Building CXX object CMakeFiles/dmake.dir/dmake/language.cpp.o
[ 29%] Building CXX object CMakeFiles/dmake.dir/dmake/genex_evaluator.cpp.o
[ 29%] Building CXX object CMakeFiles/dmake.dir/dmake/inner/sha256.cpp.o
[ 32%] Building CXX object CMakeFiles/dmake.dir/dmake/builtins/message.cpp.o
[ 35%] Building CXX object CMakeFiles/dmake.dir/dmake/builtins/variable.cpp.o
[ 19%] Building CXX object CMakeFiles/dmake.dir/dmake/cmake-language.cpp.o
[ 19%] Building CXX object CMakeFiles/dmake.dir/dmake/build_system.cpp.o
[ 19%] Building CXX object CMakeFiles/dmake.dir/dmake/utils.cpp.o
[ 45%] Building CXX object CMakeFiles/dmake.dir/dmake/target.cpp.o
[ 19%] Building CXX object CMakeFiles/dmake.dir/dmake/command_parser.cpp.o
[ 38%] Building C object CMakeFiles/dmake.dir/dmake/inner/blake2b.c.o
[ 45%] Building CXX object CMakeFiles/dmake.dir/dmake/module_scanner.cpp.o
[ 48%] Building CXX object CMakeFiles/dmake.dir/dmake/interperter.cpp.o
[ 45%] Building CXX object CMakeFiles/dmake.dir/dmake/genex_parser.cpp.o
[ 58%] Building CXX object CMakeFiles/dmake.dir/dmake/builtins/find_package.cpp.o
[ 58%] Building CXX object CMakeFiles/dmake.dir/dmake/builtins/find_commands.cpp.o
[ 61%] Building CXX object CMakeFiles/dmake.dir/dmake/builtins/math.cpp.o
[ 58%] Building CXX object CMakeFiles/dmake.dir/dmake/builtins/list.cpp.o
[ 67%] Building CXX object CMakeFiles/dmake.dir/dmake/builtins/process.cpp.o
[ 67%] Building CXX object CMakeFiles/dmake.dir/dmake/builtins/string.cpp.o
[ 70%] Building CXX object CMakeFiles/dmake.dir/dmake/builtins/target.cpp.o
[ 74%] Building CXX object CMakeFiles/dmake.dir/dmake/builtins/file.cpp.o
[ 77%] Building CXX object CMakeFiles/dmake.dir/dmake/builtins/project.cpp.o
[ 80%] Building CXX object CMakeFiles/dmake.dir/dmake/builtins/path.cpp.o
[ 87%] Building CXX object CMakeFiles/dmake.dir/dmake/CMakeList.cpp.o
[ 90%] Building CXX object CMakeFiles/dmake.dir/dmake/builtins/try_compile.cpp.o
[ 90%] Building CXX object CMakeFiles/dmake.dir/dmake/builtins/property.cpp.o
In file included from /home/marty/Documents/dmake/dmake/interperter.cpp:5:
/home/marty/Documents/dmake/dmake/gnu_compiler.hpp: In function ‘std::string dmake::detail::run_command(const std::string&)’:
/home/marty/Documents/dmake/dmake/gnu_compiler.hpp:22:44: warning: ignoring attributes on template argument ‘int (*)(FILE*)’ [-Wignored-attributes]
22 | std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(command.c_str(), "r"), pclose);
| ^
[ 93%] Linking CXX shared library libdmake.so
[ 93%] Built target dmake
[ 96%] Building CXX object CMakeFiles/dmake_cli.dir/dmake-cli/main.cpp.o
[100%] Linking CXX executable dmake
[100%] Built target dmake_cli
Then the project can read the same CMakeLists.txt CMake uses and build itself.
# in project root
❯ ./build/dmake --config release
[STATUS] Generating build graph...
[STATUS] Starting release build...
Compiling [dmake_cli] main.cpp
Compiling [dmake] build_system.cpp
Compiling [dmake] CMakeList.cpp
Compiling [dmake] file.cpp
Compiling [dmake] find_package.cpp
Compiling [dmake] find_commands.cpp
Compiling [dmake] math.cpp
Compiling [dmake] list.cpp
Compiling [dmake] path.cpp
Compiling [dmake] process.cpp
Compiling [dmake] project.cpp
Compiling [dmake] message.cpp
Compiling [dmake] property.cpp
Compiling [dmake] target.cpp
Compiling [dmake] string.cpp
Compiling [dmake] try_compile.cpp
Compiling [dmake] variable.cpp
Compiling [dmake] cache_store.cpp
Compiling [dmake] cmake-language.cpp
Compiling [dmake] command_parser.cpp
Compiling [dmake] genex_evaluator.cpp
Compiling [dmake] genex_parser.cpp
Compiling [dmake] blake2b.c
Compiling [dmake] sha256.cpp
Compiling [dmake] interperter.cpp
Compiling [dmake] language.cpp
Compiling [dmake] module_scanner.cpp
Compiling [dmake] target.cpp
Compiling [dmake] utils.cpp
Linking [dmake] libdmake.so
Linking [dmake_cli] dmake
Finished build in 20.61s
[STATUS] Build finished.
dmake also provides testing capablities like ctest.
❯ ./build/dmake --config release test
[STATUS] Generating build graph...
[STATUS] Starting release build...
Compiling [dmake_tests] interpreter_tests.cpp
Compiling [dmake_tests] genex_tests.cpp
Compiling [dmake_tests] language_tests.cpp
Compiling [dmake_tests] main.cpp
Compiling [dmake_tests] pch_tests.cpp
Compiling [dmake_tests] shadow_map_tests.cpp
Compiling [dmake_tests] command_parser.cpp
Compiling [dmake_tests] compiler_tests.cpp
Compiling [dmake_tests] target_sources_tests.cpp
Linking [dmake_tests] dmake_tests
Finished build in 12.36s
[STATUS] Build finished.
Running 1 tests...
[1/1] interpreter_tests PASSED (0.10s)
Test Summary: 1/1 passed (0.10s)
But, it has much better error reporting! One of the core development loop is me trying various projects. Try to build them. And figure out what else I need to support. Unlike CMake which generates errors you avoid reading. dmake tells you where, what it expects, highlight it and a neat stack trace.
And it's rewarding to see that CMake is now telling you "hey, you skipped implementing something. Go back and do it". See what I have during development
❯ ./build/dmake ~/Documents/trantor -DTRANTOR_USE_TLS=none
[WARN] This macro can only be used with libraries
[STATUS] Trantor using SSL library: None
[STATUS] c-ares found!
[STATUS] Found module: /usr/share/cmake/Modules/FindThreads.cmake
error: FindThreads only works if either C or CXX language is enabled
--> /usr/share/cmake/Modules/FindThreads.cmake:129:3
|
129 | message(FATAL_ERROR "FindThreads only works if either C or CXX language is enabled")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Call Stack (most recent call first):
/usr/share/cmake/Modules/FindThreads.cmake:122 (if)
/home/marty/Documents/trantor/CMakeLists.txt:276 (find_package)
Error: Interpretation error
We all like the CMake arguments and the mold linker. Sure, that works too.
❯ ./build/dmake ~/Documents/lispp -DCMAKE_LINKER_TYPE=MOLD
[STATUS] Generating build graph...
[STATUS] Starting debug build...
Compiling [lispp] g++ lispp_pch.hpp
Compiling [lispp] g++ main.cpp
Linking [lispp] g++ lispp
Finished build in 1.53s
[STATUS] Build finished.
compile_commands.json is generated by default and CMAKE_BUILD_TYPE is set to Debug by default - why aren't they already?
ls ~/Documents/lispp/build/debug/compile_commands.json -l
.rw-r--r-- marty marty 976 B Tue Jan 27 14:59:45 2026 /home/marty/Documents/lispp/build/debug/compile_commands.json
Pretty cool eh? Now this project is early. But it can compile the Lgrange (gemini) browser no problem as well as the Trantor networking library. In fact, see how much faster dmake is when a cmake has to reconfigure -- dmake's unoptimized interperter is 2x faster then CMake's. Though not saying interpertation speed is the bottleneck (it's not, it's agressive caching). But I think I made better tradeoffs then CMake that I avoid most of the stale cache problem while maintaining equal speed.
No, it is not cheating by not actually running the CMake script. It just does much better at caching what's important and executing.
(Notice the CMake example does not even invoke the actual build while dmake is already done!)
And to show it works. The Lagrange browser built by dmake.

Turns out getting the basics dones takes forever. Afterwards, things gets better much, much faster
Update Jan 31th
After some more hacking, mostly from not able to sleep from Jetlag while attending FOSDEM. Much more things are working
- drogon
- trantor
- jsoncpp
- yaml-cpp
Without modification!