I have been struggling with this for 2 days now with no apparent resolution or even an idea what I should do. I am using the nixos 23.11, with nix-shell and home manager. I have a fairly large project that has all of the components containerized for Docker. For the C++ applications I am using CMake. For unit testing I am using Catch2. I have scripts that take care of all of the details of building, testing and packaging. It has taken me a while to get to this point, but I have only been working through getting nixos setup just to support this evironment and now that it is done, using my scripts, I finally built and packaged my apps only to find that they don’t run outside of nixos because of all the linker dependencies.
After investigating, I found one solution is to use a flake to encapsulate the build so that the end result goes through nix to rewrite the dependencies before it goes into a container. So I created a flake.nix file and ran nix build. No matter what I do, I get an error. Either Git cannot clone catch2-populate or cannot find github. How do I fix these error in the flake or what is the best way to make a portable build for a C++ application that actually works?
Here is one version that results in a clone error.
Blockquote
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs";
catch2_src = { # ← Fetched by Nix (not CMake)
url = "github:catchorg/Catch2/v3.4.0";
flake = false;
};
};
outputs = { self, nixpkgs, catch2_src }:
let pkgs = nixpkgs.legacyPackages.x86_64-linux;
in {
packages.x86_64-linux.default = pkgs.stdenv.mkDerivation {
# ...
preConfigure = ''
cp -r ${catch2_src} ./catch2
substituteInPlace CMakeLists.txt \
--replace "GIT_REPOSITORY https://github.com/catchorg/Catch2.git" "SOURCE_DIR ${catch2_src}"
'';
};
};
}
I created a toy directory with a hello world and a unit test. I have changed the CmakeLists.txt to use addsubdirectory and have the flake.nix pull Catch2 from github and then copy it into the subdirectory.
Blockquote
cmake_minimum_required(VERSION 3.10)
project(hello-cpp)
set(CMAKE_CXX_STANDARD 17)
add_executable(hello src/main.cpp)
# Add Catch2 from vendored source (copied in flake)
add_subdirectory(external/Catch2)
add_executable(tests test/test_main.cpp)
target_link_libraries(tests PRIVATE Catch2::Catch2WithMain)
include(CTest)
add_test(NAME tests COMMAND tests)
enable_testing()
Blockquote
{
description = "CMake project using Catch2 via add_subdirectory";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
catch2 = {
url = "github:catchorg/Catch2/v3.4.0";
flake = false; # We only want the source
};
};
outputs = { self, nixpkgs, catch2 }:
let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
in {
packages.x86_64-linux.default = pkgs.stdenv.mkDerivation {
pname = "my-project";
version = "1.0";
src = ./.;
nativeBuildInputs = [ pkgs.cmake ];
buildInputs = [ pkgs.catch2 ]; # Still declare for linking
# Copy Catch2 source into place before CMake runs
preConfigure = ''
mkdir -p external/Catch2
cp -r ${catch2}/* external/Catch2/
chmod -R +w external/Catch2 # Ensure writable for CMake
'';
# Phase 3: Build
buildPhase = ''
cmake --build build --parallel $NIX_BUILD_CORES
'';
cmakeFlags = [
"-DCATCH_BUILD_TESTING=OFF" # Disable Catch2's own tests
"-DCATCH_INSTALL_DOCS=OFF"
];
};
# Development shell (optional)
devShells.x86_64-linux.default = pkgs.mkShell {
packages = [ pkgs.cmake ];
shellHook = ''
mkdir -p external/Catch2
cp -r ${catch2}/* external/Catch2/
'';
};
};
}
Different error now but still I am just flayling.
Blockquote
error: builder for '/nix/store/j6mm4nbafr4crgjixijybkzva0avw2s7-my-project-1.0.drv' failed with exit code 1;
last 25 log lines:
> -- Detecting C compile features
> -- Detecting C compile features - done
> -- Detecting CXX compiler ABI info
> -- Detecting CXX compiler ABI info - done
> -- Check for working CXX compiler: /nix/store/zd2viirgdm4ffgipgpslmysmlzs6fscb-gcc-wrapper-12.3.0/bin/g++ - skipped
> -- Detecting CXX compile features
> -- Detecting CXX compile features - done
> -- Performing Test HAVE_FLAG__ffile_prefix_map__build_nyivzj20hqbp7zb56k7qm6vdnxdab9ck_source_external_Catch2__
> -- Performing Test HAVE_FLAG__ffile_prefix_map__build_nyivzj20hqbp7zb56k7qm6vdnxdab9ck_source_external_Catch2__ - Success
> -- Configuring done (1.0s)
> -- Generating done (0.0s)
> CMake Warning:
> Manually-specified variables were not used by the project:
>
> CMAKE_EXPORT_NO_PACKAGE_REGISTRY
> CMAKE_FIND_USE_PACKAGE_REGISTRY
> CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY
> CMAKE_POLICY_DEFAULT_CMP0025
>
>
> -- Build files have been written to: /build/nyivzj20hqbp7zb56k7qm6vdnxdab9ck-source/build
> cmake: enabled parallel building
> cmake: enabled parallel installing
> Running phase: buildPhase
> Error: /build/nyivzj20hqbp7zb56k7qm6vdnxdab9ck-source/build/build is not a directory
For full logs, run 'nix log /nix/store/j6mm4nbafr4crgjixijybkzva0avw2s7-my-project-1.0.drv'.
In case anyone is curious here is the solution:
{
description = "CMake project with guaranteed output";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
catch2 = {
url = "github:catchorg/Catch2/v3.4.0";
flake = false;
};
};
outputs = { self, nixpkgs, catch2 }:
let
pkgs = nixpkgs.legacyPackages.x86_64-linux;
in {
packages.x86_64-linux.default = pkgs.stdenv.mkDerivation {
pname = "my-project";
version = "1.0";
src = ./.;
nativeBuildInputs = [ pkgs.cmake ];
buildInputs = [ pkgs.catch2 ];
# Phase 1: Prepare Catch2
preConfigure = ''
mkdir -p extern
cp -r ${catch2} extern/Catch2
chmod -R +w extern/Catch2
'';
# Phase 2: Configure
configurePhase = ''
cmake -B build -S . \
-DCMAKE_INSTALL_PREFIX=$out \
-DCMAKE_BUILD_TYPE=Release
'';
# Phase 3: Build
buildPhase = ''
cmake --build build --parallel $NIX_BUILD_CORES
'';
# Phase 4: Install with verification
installPhase = ''
cmake --install build
# Verify installation
if [ ! -d "$out" ]; then
echo "ERROR: No files were installed to $out"
exit 1
fi
echo "=== Installed files ==="
find $out -type f
'';
# Extra protection against empty outputs
dontInstall = false;
};
devShells.x86_64-linux.default = pkgs.mkShell {
packages = [ pkgs.cmake ];
shellHook = ''
mkdir -p extern/Catch2
cp -r ${catch2}/* extern/Catch2/
'';
};
};
}