CMake Cross-Compiling using Docker
by Hristo Iliev | Last Updated:
C / C++
There are many cases where you want to cross-compile your program on multiple systems. This can be a tedious task but tools like CMake help a lot. I have been writing a lot about CMake on this blog but this time I will do a bit of a different article. Most programmers at this point have heard of containers and docker but if you haven’t – in this article I will explain how you can use them to your advantage to compile your program for different platfroms with dockcross without ever leaving your favourite environment.
Table of Contents
- Introduction to Containers
- What you need
- How to cross-compile with CMake
Introduction to Containers
Containers have been out there for a while now. The idea of a container is to abstract away a small operating system on your host without the complicated virtual machine setup. Docker is the most popular tool for managing containers. Usually an alternative to it for development purposes is considered Vagrant. The difference between those two is that Vagrant actually manages virtual machines and Docker manages small containers. Docker on Windows will use the Windows subsystem for Linux environment for its containers.
What you need
To follow on with this very simple tutorial you will need to install a few tools:
- https://git-scm.com/ – Download git because it will also install a git bash and you will need this to run the cross-compilation script.
- https://www.docker.com/ – Docker itself. When installing click the WSL option.
These will be the only things that you will need. After that we will execute a few commands in the command line to make it work. When installing docker you might need to restart Windows before you continue.
How to cross-compile with CMake
Dockcross is a set of containers that allow you to compile C++ aplications. They also come with preinstalled CMake, Make, Ninja, etc. Which comes to be very useful. They also set up the CMake toolchain for cross-compilation so all you need to do is execute cmake through docker.
I have written about cross-compiling for the web using emscripten and I have some very detailed articles on how to install emscripten on your project and then use it. What if I told you that all that can be simplified to a few commands in the terminal?
To install a dockcross container you need to open up a git bash terminal change to the project directory and run:
docker run --rm dockcross/web-wasm > ./dockcross-web-wasm
Note: If you want you can also go to the microsoft store and install an ubunto wsl. Then in docker make sure that in the settings you allow integration with your subsystem. When you do this you can execute the commands directly from wsl.
This command will prepare a web wasm container and save a script for running it in a file called dockcross-web-wasm. The next step then is to make this file executable and run it:
dos2unix ./dockcross-web-wasm chmod +x ./dockcross-web-wasm ./dockcross-web-wasm cmake -S . -B ./build-wasm -G Ninja ./dockcross-web-wasm cmake --build ./build-wasm
This will run all the steps and in a short while you would have a directory build-wasm with your built files. You could potentially build for many more linux environments. Just check out the official repository for dockcross.
Building your own image
Often for games you need to have few additional libraries. Especially ones for graphics. If you want to create your own image based on dockcross you just need to create a new Dockerfile in any directory:
FROM dockcross/linux-x64-clang ENV DEFAULT_DOCKCROSS_IMAGE linux-x64 RUN apt-get update -qq RUN apt-get install -y python3 curl zip unzip RUN apt-get install -y --no-install-recommends libx11-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev libxext-dev libxfixes-dev libgl1-mesa-dev libpthread-stubs0-dev libc6-dev
And then run the following terminal command
docker build -t linux-x64 . And then if you want to generate something like the above command executable:
docker run --rm linux-x64 > ./dockcross-linux-x64
The rest of the execution should be like before.
Well now you know how to compile without having to spin up complicated virtual machines or run web build machines to do so. If you get proficient enough with Docker you could even spin up your own variants of those containers where you can test with different linux packages.
Docker is popular in the web development sector but it is very useful for local native development as well. Dockcross gives you the ability to cover a few more platforms locally – Linux, Windows, Android and Wasm. Hope you find this information useful!
Please. Could you also provide an example of compiling the Pong game (https://thatonegamedev.com/cpp/prgramming-a-pong-game-in-ansi-c)?
Hey, @Tony Sadly the example with the Pong game won't work out of the box. In that example I use vcpkg and vcpkg has issue installing dependencies under dockcross. You would have to have a more add_subdirectory approach with your CMake files. In general to work with raylib you would need to create your own image based on dockcross with some graphical libraries installed. I've added a section in this article how to do that.