This content originally appeared on DEV Community and was authored by Jacob Hummer
We know how to compile an Autotools project using cosmocc but how do you compile a CMake project with cosmocc?
Here’s an example project:
main.c
#include <stdio.h>
int main() {
puts("Hello world!");
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.29)
project(hello-world LANGUAGES C)
add_executable(hello-world main.c)
You can almost just do CC=cosmocc cmake ... and call it day. Almost. But not quite!
There are some other CMake settings you need to set to get things to work well with cosmocc.
First, you’ll need to add a CMAKE_USER_MAKE_RULES_OVERRIDE file to define the object suffix as .o instead of .obj. cosmocc currently doesn’t work if the object extension is not .o. 
cosmocc-override.cmake
set(CMAKE_ASM_OUTPUT_EXTENSION .o)
set(CMAKE_C_OUTPUT_EXTENSION .o)
set(CMAKE_CXX_OUTPUT_EXTENSION .o)
Why can’t we just specify -DCMAKE_C_OUTPUT_EXTENSION=".o" on the command line? It needs to be defined after the Generic configuration is loaded so it doesn’t get reset to the default .obj. CMAKE_USER_MAKE_RULES_OVERRIDE is the recommended way to do it. https://gitlab.kitware.com/cmake/cmake/-/issues/18713
ASM="cosmocc" \
CC="cosmocc" \
CXX="cosmoc++" \
cmake \
-DCMAKE_SYSTEM_NAME="Generic" \
-DCMAKE_SYSTEM_PROCESSOR="" \
-DCMAKE_USER_MAKE_RULES_OVERRIDE="$PWD/cosmocc-override.cmake" \
-DCMAKE_AR="$(command -v cosmoar)" \
-DCMAKE_RANLIB="" \
-B build
-- The C compiler identification is GNU 12.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /somewhere/cosmocc/bin/cosmocc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done (2.9s)
-- Generating done (0.0s)
-- Build files have been written to: /somewhere/hello-world/build
Do I have to specify CMAKE_SYSTEM_NAME and CMAKE_SYSTEM_PROCESSOR? Yes. They configure some CMake magic internally and configure what your CMakeLists.txt thinks it’s compilation target is.
Why not CMAKE_SYSTEM_NAME="Linux"? So that if(LINUX) and other Linux-specific stuff in CMakeLists.txt doesn’t activate for unknown-unknown-cosmo.
Why not CMAKE_SYSTEM_PROCESSOR="unknown"? The empty string is what means unknown-unknown-cosmo to CMake. CMake internals use if(CMAKE_SYSTEM_PROCESSOR), not if(CMAKE_SYSTEM_PROCESSOR STREQUAL unknown).
Why does CMAKE_AR need to be an absolute path? Unfixed issue. https://gitlab.kitware.com/cmake/cmake/-/issues/18087
Why does CMAKE_RANLIB need to be set if it’s just set to an empty string? To stop CMake using ranlib. cosmocc doesn’t have a cosmoranlib (yet).
Why can’t we do AR="cosmoar" like CC and CXX? Unfixed issue. https://gitlab.kitware.com/cmake/cmake/-/issues/18712
Now that the project is configured with all the compiler settings and other magic
we can run the build step:
cmake --build build
[ 50%] Building C object CMakeFiles/hello-world.dir/main.c.o
[100%] Linking C executable hello-world
[100%] Built target hello-world
You just made a magic
binary! 
On Windows you need to rename it or symlink it to have an .exe or .com suffix to execute it.
./build/hello-world
Hello world!
This content originally appeared on DEV Community and was authored by Jacob Hummer