Building Handmade Hero with Nix Flakes
Lately, I'm following along Handmade Hero on NixOS using SDL2 (thank you
Handmade Penguin), and wanted to setup Nix Flakes
to build the derivation. I
made something work for C/C++
with external dependencies such as SDL2
.
If you are unfamiliar with the nix ecosystem, I recommend reading my How-To Nix guide, but it's not a requirement. I'm still learning about these concepts myself, so don't worry.
My requirements:
ability to use
nix run
to display the project (via NixOS, or Nix on it's own)place C++ source files in
./src
the
Language Server Protocol
(LSP) should pick up theSDL2
library when using direnv in your editor of choice (I use Emacs btw 😎)
Show the flake.nix
already!
For my own system configuration I depend on nixos-unstable
, but for projects I
like to depend on more stable version nixos-23.05
. I need the flake-utils
,
since it makes working with flakes easier when building derivations for multiple
platforms.
{
description = "Handmade Hero on NixOS";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.05";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let pkgs = nixpkgs.legacyPackages.${system};
in {
# TODO(Kevin): What goes in here?
});
}
I use clangd
, not sure why, but it's the one I chose. If you want to use
gcc
, go for it. I also use gf
to provide me with a simple debugger as
RemedyBG is not available on Linux yet.
The executable depends on SDL2
being available at runtime, which is why we add
it to the buildInputs
. Usually you would read mkDerivation
, but this
environment provides gcc
by default, not clang++
. We have to call the
derivation helper from a clangStenv
.
packages = {
default = let inherit (pkgs) clangStdenv;
in clangStdenv.mkDerivation {
name = "my-handmade-hero";
src = ./.;
buildInputs = with pkgs; [ SDL2 ];
buildPhase = with pkgs;
"clang++ ./src/sdl_handmade.cpp -o handmade_hero -lSDL2";
installPhase = ''
mkdir -p $out/bin
cp handmade_hero $out/bin/my-handmade-hero
'';
};
};
The isolated development environment loads the same buildInputs
and
nativeBuildInputs
, from the earlier mention package declaration via
inputsFrom
. The shell reports the installed clang++
version as a sanity
check.
devShells = {
default = pkgs.mkShell.override { stdenv = pkgs.clangStdenv; } {
packages = with pkgs; [ clang-tools gf SDL2.dev ];
inputsFrom = [ self.packages.${system}.default ];
shellHook = with pkgs; ''
echo "`clang++ --version`"
'';
};
};
Now, by bringing all these puzzles pieces together, you end up with the
following flake.nix
.
{
description = "Handmade Hero on NixOS";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-23.05";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
name = "my-handmade-hero";
src = ./.;
pkgs = nixpkgs.legacyPackages.${system};
buildInputs = with pkgs; [ SDL2 SDL2.dev ];
nativeBuildInputs = with pkgs; [ clang-tools gf ];
in {
<<package>>
<<dev-shell>>
});
}
(ansi-color-apply text)
Generate the lock file, and check if the flake is has been setup correctly.
nix flake lock
nix flake show
git+file:///home/venikx/code/venikx.com?dir=src/content/blog/handmade-hero-nixos ├───devShells │ ├───aarch64-darwin │ │ └───default omitted (use '--all-systems' to show) │ ├───aarch64-linux │ │ └───default omitted (use '--all-systems' to show) │ ├───x86_64-darwin │ │ └───default omitted (use '--all-systems' to show) │ └───x86_64-linux │ └───default: development environment 'nix-shell' └───packages ├───aarch64-darwin │ └───default omitted (use '--all-systems' to show) ├───aarch64-linux │ └───default omitted (use '--all-systems' to show) ├───x86_64-darwin │ └───default omitted (use '--all-systems' to show) └───x86_64-linux └───default: package 'my-handmade-hero'
Verify the SDL2 Headers with a Message Box
The simplest way to check if C/C++ code properly links with the SDL2
library
is by showing a message box. Your editor (I use Emacs btw 😎) should now also be
able to complete SDL functions when you type SDL_
.
The hardest parts are behind us now. Running nix build
creates an executable
file inside result
. After running ./result/bin/handmade_hero
you should see
a message box. Or equivalently run nix run
.
nix run