To provide a consistent build on Windows, Linux, macOS and BSD across various compilers, dynamic and static linking, all described in one single file, CMake is used, with the help of vcpkg to support static linking.
In its most basic form on Linux/BSD, with dynamic linking, a build can be invoked as follows:
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release # Configuration phase
make -j $(nproc) # Build phase
This will locate all system-wide dependencies and show a clear message if a mandatory dependency is not installed. Check the output to see if it matches your expectations in regard to optional dependencies.
When configure phase passes, the build phase will produce a dynamically linked binary.
The resulting binary can be found in the build directory at build/ezquake-linux-x86_64
.
The default mode of compilation is to not show the full command line, only errors and
warnings. To enable verbose mode, set CMAKE_VERBOSE_MAKEFILE
to ON
.
While CMake can be configured via CMAKE_C_CFLAGS
, it also supports picking up CFLAGS
from the aptly named environment variable CFLAGS
.
The ezQuake build also declares a few options on its own to customize the resulting executable.
Unfortunately CMake CLI has no built-in command to list them, so check CMakeLists.txt
:
grep -E ^option CMakeLists.txt
Putting the above customizations to work may look like this:
export CFLAGS=-march=native
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_VERBOSE_MAKEFILE=ON -DRENDERER_CLASSIC_OPENGL=OFF
make -j $(nproc)
CMake caches as much as possible when the build is initialized to allow for fast iteration when developing. Should an option not activate as expected, removing the build directory and starting over is always a failsafe. Static dependencies are cached elsewhere and will not have to be rebuilt if only the build directory is removed.
CMake presets can be seen as aliases that associates a number of build settings to a name. While this may not add much value for the trivial dynamically linked Linux/BSD build, the presets do add some desirable conveniences for other targets as is seen in later sections.
There are two types of presets relevant to the ezQuake build:
- Configuration Presets
- Build Presets
The available presets can be listed via:
$ cmake --list-presets
Available configure presets:
"mingw64-x64-cross"
"mingw64-i686-cross"
...
$ cmake --build --list-presets
Available build presets:
"msbuild-x64-debug" - Build msbuild-x64 debug
"msbuild-x64-release" - Build msbuild-x64 release
"msbuild-x64-relwithdebinfo" - Build msbuild-x64 release with debug info
...
These can be invoked, regardless of underlying build system, via:
# Creates build-dynamic directory, and initializes the build
cmake --preset dynamic
# Builds executable in build-dynamic/Release/ezquake
cmake --build --preset dynamic-release
# ...or if skipping the build preset, pass path to build directory instead
camke --build build-dynamic --config Release
The build directory is by convention always called build-${presetName}
when using presets.
All declared presets are of type Multi-Config so they're able to produce Debug, Release, and RelWithDebInfo variants from the same configuration.
While build presets are somewhat optional when building from the terminal, they add convenience when working from within an editor with CMake support.
Static builds are supported on Windows, Linux and macOS and offloads building of dependencies to vcpkg. The CMake configuration is agnostic to dynamic or static linking and enabling of static linking happens via parametrizing the CMake invocation with the vcpkg toolchain. This is done automatically by using any of the Windows, macOS, or the static presets.
Before starting a static build, vcpkg needs to be initialized. This is done by invoking
bootstrap.sh
on *nix-like platforms. Depending on which type of build
is used on Windows, the bootstrap.ps1
PowerShell script does the equivalent.
The invocation of a Linux static build is near identical to a dynamic build:
./bootstrap.sh
cmake --preset static
cmake --build build-static --config Release
If you haven't compiled a static version before, or if the project has updated the vcpkg repository version since last build, this will take a few minutes.
Note that for Linux/BSD builds, you have to install the appropriate X11/Wayland development headers for the static build to work with each of those targets.
Any *nix environment can produce a Windows build via:
./bootstrap.sh
cmake --preset mingw64-x64-cross
cmake --build build-mingw64-x64-cross --config Release
In addition to mingw64 being installed, a native compiler is also needed as parts of the vcpkg build need to execute on the host.
Microsoft is highly invested in both CMake and vcpkg, so native support in Visual Studio has existed for a number of years by now. Importing the project in Visual Studio 17 detects the CMake and vcpkg combination and builds the dependencies.
Once done, the build presets will be listed in the Configurations drop down. The msbuild-*
or ninja-msvc-*
related build presets are typically a good fit.
To run ezQuake against a specific game directory, go via menu to Debug > Debug and Launch
Settings for ezquake which will open up the launch_schema.json
file where you introduce
currentDir
similar to the following:
{
"version": "...",
"defaults": {},
"configurations": [
{
"type": "...",
"currentDir": "C:\\Quake"
}
]
}
As the Visual Studio Solution is generated first after CMake configuration phase has finished,
the ./bootstrap.ps1
PowerShell script must be invoked the first time to initialize vcpkg.
powershell -File bootstrap.ps1
camke --preset msbuild-x64
Once done you will have a Visual Studio Solution in build-msbuild-x64/ezquake.sln
.
Any compilation changes that should be upstreamed must be updated in CMakeLists.txt
.
During the configuration phase, if a ezquake.vcxproj.user
file exists in the top directory,
this will be copied to the build directory next to the Visual Studio Solution to allow for
persisting custom settings as the solution is generated.
To simplify bundling static linking is used to build ezQuake on macOS, so start off by
invoking bootstrap.sh
first. When initializing for example the macos-arm64
preset
an Xcode project will be produced at build-macos-arm64/ezquake.xcodeproj
with similar
structure to that of Visual Studio.
The same preset is also used when building via the terminal:
./bootstrap.sh
cmake --preset macos-arm64
cmake --build build-macos-arm64 --config Release
This will produce ezQuake.app
under build-macos-arm64/Release/ezQuake.app
by invoking
xcodebuild
behind the scenes to do the actual building and bundling.
If you don't intend to build ezQuake again and want to reclaim some space, you can find the shared vcpkg cache at:
- All platforms
./vcpkg/buildtrees
- *nix
~/.cache/vcpkg/
- Windows
c:\Users\$UserName\AppData\Local\vcpkg
In CMakeLists.txt source files are categorized into their approximate use cases (client, server, common, sys, etc), and this also applies to header files. The reason for this is to serve editors with the correct context, and if generating either a Xcode or Visual Studio project this categorization is also visualized in the project tree view.
Looking forward, this will allow adding a ezquake-sv
target by just reusing the relevant
subset of source files.
Vcpkg is used in manifest mode, with the dependencies declared in vcpkg.json
.
While it's possible to lock dependencies at a specific version, this is not used today. Instead
the vcpkg submodule dictates the set of dependency versions the project relies on.
If adding a new mandatory dependency that static versions of ezQuake should use, first find it at vcpkg.io, and if missing, read up on overlay ports.
If a specific platform requires customizations to how the static dependencies are built a triplet
for this platform can be introduced. An example of such an override is the x64 MinGW
triplet that adds -march=nehalem
when building dependencies.