on cross-platform compilation systems

May 27, 2025

Profile picture

what a mess C build systems are

Looking into four major build systems in this post. CMake, build2, Bazel, and comparing them to Rust's Cargo. This post was motivated by some work I was doing compiling C to WASM.

an example program: open a window, render "hello world" and an image

// main.c example
#include <SDL.h>
#include <SDL_image.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
    // ...
    SDL_Window* win = SDL_CreateWindow("Hello World Window", 100, 100, 640, 480, SDL_WINDOW_SHOWN);
    // ...
    SDL_Surface* img = IMG_Load("hello.png");
    // this would require having the `hello.png` file in the same directory as the executable
}

CMake

CMakeLists.txt:

cmake_minimum_required(VERSION 3.10)
project(HelloWindow C)

find_package(SDL2 REQUIRED)
find_package(SDL2_image REQUIRED)

add_executable(hello main.c)
target_link_libraries(hello SDL2::SDL2 SDL2_image::SDL2_image)
  • declarative but odd syntax
  • cross-platform support

build2

buildfile:

exe{hello}: {hxx cxx}{main} \
            libsdl2%lib{sdl2} \
            libsdl2_image%lib{sdl2_image}
  • declarative and simpler syntax than CMake
  • automatic header dependency extraction, interesting
  • docs are very rough

Bazel

BUILD file:

load("@rules_cc//cc:defs.bzl", "cc_binary")

cc_binary(
    name = "hello",
    srcs = ["main.c"],
    deps = [
        "@sdl2//:sdl2",
        "@sdl2_image//:sdl2_image",
    ],
    data = ["hello.png"],
)

WORKSPACE file:

http_archive(
    name = "sdl2",
    url = "https://github.com/libsdl-org/SDL/releases/download/release-2.28.5/SDL2-2.28.5.tar.gz",
    # ... other fields ...
)
http_archive(
    name = "sdl2_image",
    url = "https://github.com/libsdl-org/SDL_image/releases/download/release-2.8.2/SDL2_image-2.8.2.tar.gz",
    # ... other fields ...
)
  • cc_binary.data! it can bundle the image as a static resource. definitely feels like something that is missing from CMake and build2 that require the image file to be present in the directory

Rust's Cargo

Cargo.toml:

[package]
name = "hello_window"
version = "0.1.0"
edition = "2021"

[dependencies]
iced = { version = "0.10", features = ["image"] }
  • dead simple, just works, handles compilation, linking, static assets...

References