Xmake Just Works
Building C++ projects is a mess. It always boils down to having build generators. Build system that generate a working build script that can then be compiled. They are essentially meta systems. But what build systems did I even try and why do I like or hate them.
Hating on CMake
They are all so complicated. The build system I like the most is dotnet. Being able to say dotnet run, dotnet add package, dotnet build is exactly what we want. The most commonly used steps are the simplest one with sane defaults.
When a tool asks you for something that should be a default instead, I am going to scream.
In CMake I always have to create a build folder MYSELF, have to cd into it and run again CMake. Alternative you can write a long command. Very often when you encounter a CMake project in the wild it asks you to run two commands to build a project.
cmake -S . -B build
cmake --build build --config RelWithDebInfo
When you don’t know CMake already, ask yourself what does -S do? Why do we have to say cmake --build build instead of cmake build?
We always want to build and run a project. Building and running should always be one step, one command. Never be two.
Adding Dependencies
I really like using projects created by others. In C# we add dependencies with ease.
dotnet add package SDL3-CS
Adding the same dependency using CMake looks like this:
cmake_minimum_required(VERSION 3.5)
project(mygame)
# Create an option to switch between a system sdl library and a vendored SDL library
option(MYGAME_VENDORED "Use vendored libraries" OFF)
if(MYGAME_VENDORED)
# This assumes you have added SDL as a submodule in vendored/SDL
add_subdirectory(vendored/SDL EXCLUDE_FROM_ALL)
else()
# 1. Look for a SDL3 package,
# 2. look for the SDL3-shared component, and
# 3. fail if the shared component cannot be found.
find_package(SDL3 REQUIRED CONFIG REQUIRED COMPONENTS SDL3-shared)
endif()
# Create your game executable target as usual
add_executable(mygame WIN32 mygame.c)
# Link to the actual SDL3 library.
target_link_libraries(mygame PRIVATE SDL3::SDL3)
I understand why it is like that. There is no official build system, there is no official package manager there are many. What I am not understanding is why they just don’t copy from tooling that just works. Not onces created the dotnet tool system a problem for my project. While most C++ did for me. Simple things are simply hard in most C++ build systems.
And I can already hear people that can use and understand CMake better than me screaming “Skill Issue not a CMake one”. I strongly believe that any tool should be created in such a way that the simple most used actions are the most intuitive ones. If I need a special course or hour long tutorial series just to understand basic actions the tool is simply not good designed.
Visual Studio
I hate it, because you have to click through so many menus and windows just to link a new shared library. Expose headers etc. If there is no video guide showing you what to do: First open this menu, scroll down to here, click there, add this specific text snippet. You will feel lost and overwhelmed but your options. Too many menus, too many steps doing the most simple and basic things. Visual Studio is not intuitive.
Bazel
Bazel is exactly what you would expect from a Google project. Convoluted, created by people smarter than me, for people working at Google. Bazel is incredible when you work with monorepositories, many different languages besides C++ and you have to orchestrate that. A Java project depending on a C++ project needing to create an iOS and Android build.
In Bazel this aspect is easy because it’s the most common use case for Google. Sadly It’s not really my most common use case. I tried it and it didn’t fit nicely. BUT I think it’s better than CMake, so that is at least something.
Meson
Meson first released around Jun 15, 2014 is also an interesting option.
Sadly I didn’t come around using Meson that much. Again I think it’s better than CMake because it uses Python. Of course that comes with its own problems like using python and having to learn the DSL for Meson. But I don’t think you can avoid using a DSL for any C++ build system.
Meson suffers from the same problem CMake does. Simple things are not easy and require multiple steps.
XMake ♥
Yet another build system? XMake is rather new. Its first v1 release was in Jan 6, 2016 and is also not used as much as other build systems like CMake or Meson. Yet it finally makes things simpler. It uses just one executable. Can be installed with no problems no crazy setup to do. It just works. The quick start guide gives a good overview.
XMake is finally a build system I like. It was a breeze adding new dependencies, adding unit tests, being able to say xmake run tests to run them. But XMake is more than a C++ project builder it also works for many other languages like:
- c
- c++
- csharp
- cuda
- dlang
- fortran
- go
- kotlin
- nim
And many more.
Creating Hello World
Its dead simple
xmake create hello_world
cd hello_world
xmake run
Produces the output hello, world!.
Adding Dependencies
No need to get a package manager running, awkwardly searches for git projects trying to integrate their build system. To my understanding XMake can use basically ever package system you can imagine. Read here and this more about it. But by default you don’t have to do anything.
Just use xmake require --search package_name to search for the package. Here I am search for joltphysics.
xmake require --search jolt
The package names:
jolt:
-> joltphysics-v5.5.0: A multi core friendly rigid body physics and collision detection library suitable for games and VR applications. (in xmake-repo)
And add the package to your XMake file.
add_rules("mode.debug", "mode.release")
add_requires("joltphysics v5.5.0")
target("hello_world")
set_kind("binary")
add_files("src/*.cpp")
add_packages("joltphysics")
I can’t empathize it enough, simple things are simple in XMake and that is the reason why I like it. I can only recommend it. XMake does exactly what I want. Having sane defaults for 90% of the use cases, commonly used tasks are one step by default.