Any help would be appreciated. Hopefully this is concise enough.
- Goal: Use multiple flakes to provide the necessary framework to build portable C++ applications.
- Problem: Applications built without a flake are non-portable. Using a flake allows a portable build. Libraries that are built using a flake are placed into the nix store. CMake cannot find the library “package” path in the store to build my other CMake based C++ application.
- System Outputs:
- CMake based C++ libraries
- CMake based C++ applications
- ReactJs/Node application
- Java/Maven application.
- What works:
- Building the library only using the common flake.nix works and it installs the libraries into the store.
- Building the libraries and applications using only cmake works but creates non-portable output.
- What doesn’t work:
-
Use a flakes to build the CMake C++ application that uses the libraries.
-
Could not find a package configuration file provided by “MercuryCommon”
with any of the following names:
MercuryCommonConfig.cmake
mercurycommon-config.cmake
-
-
The root flake.nix file to build the components by calling nested flakes.
-
error: flake ‘git+file:///home/user/mercury?shallow=1’ does not provide attribute ‘packages.x86_64-linux.common’, ‘legacyPackages.x86_64-linux.common’ or ‘common’
-
-
- HELP WITH:
- Details on how to pass the library nix store path to other CMake builds.
- Details on how to build a root level flake.nix file.
- Components:
- Root flake.nix:
# Top-level flake.nix
{
description = "Workspace with build prioritization";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
common.url = "path:./processing/common";
archive.url = "path:./processing/mailarchive";
};
outputs = { self, common, archive, nixpkgs }: {
# Define top-level outputs, e.g., a combined development shell
devShells.x86_64-linux = nixpkgs.lib.mkMerge [
common.devShells.x86_64-linux
archive.devShells.x86_64-linux
];
};
}
- Common flake.nix
{
description = "CMake-based project using Catch2";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
flake-utils.url = "github:numtide/flake-utils";
catch2 = {
url = "github:catchorg/Catch2/v3.4.0";
flake = false;
};
pdfhummus = {
url = "github:galkahana/PDF-Writer/v4.6.2";
flake = false;
};
zxing-221 = {
url = "github:nu-book/zxing-cpp/v2.2.1";
flake = false;
};
};
outputs = { self, nixpkgs, flake-utils, catch2, pdfhummus, zxing-221 }:
let
pkgs = import nixpkgs {
system = "x86_64-linux";
overlays = [
(final: prev: {
# Primary zxing-cpp override
zxing-cpp = prev.zxing-cpp.overrideAttrs (old: {
version = "2.2.1";
src = zxing-221;
# Update hash if needed (run build to get the correct hash)
# hash = "sha256-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=";
# Maintain original build parameters
nativeBuildInputs = old.nativeBuildInputs or [] ++ [ prev.cmake ];
buildInputs = old.buildInputs or [] ++ [ prev.stb ];
});
})
];
};
in {
packages.x86_64-linux.default = pkgs.stdenv.mkDerivation {
pname = "common";
version = "3.2.0";
src = ./.;
nativeBuildInputs = [ pkgs.cmake pkgs.pkg-config ];
buildInputs = [
pkgs.unixODBC
pkgs.unixODBCDrivers.psql
pkgs.libuuid
pkgs.leptonica
pkgs.tesseract
pkgs.pcre
pkgs.opencv
pkgs.zbar
pkgs.zxing-cpp
pkgs.freeimage
pkgs.libarchive
pkgs.openssl
pkgs.libesmtp
pkgs.log4cpp
pkgs.xercesc
pkgs.xalanc
pkgs.libtiff
pkgs.libpng
pkgs.libjpeg
pkgs.hunspell
pkgs.hunspellDicts.en-us
pkgs.nmap
pkgs.libxml2
pkgs.bzip2
pkgs.gmime3
(pkgs.omniorb.overrideAttrs (old: rec {
version = "4.3.2";
src = pkgs.fetchurl {
url = "https://sourceforge.net/projects/omniorb/files/omniORB/omniORB-${version}/omniORB-${version}.tar.bz2/download";
name = "omniORB-${version}.tar.bz2";
sha256 = "sha256-HHRTMNAZBK/Xoe0KWJa5puU6waS4ZKSFA7k8fuy/H6g=";
};
buildInputs = (old.buildInputs or []) ++ [ pkgs.openssl ];
configureFlags = (old.configureFlags or []) ++ [ "--with-openssl=${pkgs.openssl.dev}" ];
}))
];
preConfigure = ''
echo "PRECONFIGURE PHASE>>>>>> ${catch2} & ${pdfhummus}"
mkdir -p extern/Catch2
cp -r ${catch2}/* extern/Catch2
chmod -R ug+w extern/Catch2
mkdir -p extern/PDFHummus
cp -r ${pdfhummus}/* extern/PDFHummus
chmod -R ug+w extern/PDFHummus
'';
# Phase 2: Configure
configurePhase = ''
runHook preConfigure
echo "CONFIGURE PHASE>>>>>>"
cmake -B build -S . \
-DCMAKE_INSTALL_PREFIX=$out \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CATCH2_DIR=$PWD/extern/Catch2 \
-DCMAKE_PDFHUMMUS_DIR=$PWD/extern/PDFHummus
'';
# Phase 3: Build
buildPhase = ''
NIX_CFLAGS_COMPILE="$(pkg-config --cflags opencv4) $NIX_CFLAGS_COMPILE"
NIX_CFLAGS_COMPILE="$(pkg-config --cflags opencv4) $NIX_CFLAGS_COMPILE"
cmake --build build --parallel $NIX_BUILD_CORES
'';
# Phase 4: Unit test
checkPhase = ''
ctest --output-on-failure
'';
# Phase 5: Install with verification
installPhase = ''
mkdir -p $out/{include,lib}
# First try CMake's native install
cmake --install build --prefix $out
if [ -d "build/include" ]; then
cp -rv build/include/*.h $out/include/ || true
elif [ -d "build/result/include" ]; then
cp -rv build/result/include/*.h $out/include/ || true
elif [ -d "include" ]; then
cp -rv include/* $out/include/ || true
fi
# Generate MercuryCommon CMake package config
mkdir -p $out/lib/cmake/MercuryCommon
cat > $out/lib/cmake/MercuryCommon/MercuryCommonConfig.cmake <<EOF
# Mercury Common Libraries Package
set(MERCCOMM_FOUND TRUE)
# Include directory (shared by all libs)
set(MERCCOMM_INCLUDE_DIR "\''${CMAKE_CURRENT_LIST_DIR}/../../../include")
# Import all libraries
foreach(lib
address company image ocr archive text config crypto
file pdf email logging processing sysutil database test
)
add_library(MercuryCommon::\''${lib} SHARED IMPORTED)
set_target_properties(MercuryCommon::\''${lib} PROPERTIES
IMPORTED_LOCATION "\''${CMAKE_CURRENT_LIST_DIR}/../../../lib/libmerc\''${lib}.so"
INTERFACE_INCLUDE_DIRECTORIES "\''${MERCCOMM_INCLUDE_DIR}"
)
endforeach()
# Convenience variables
set(MERCCOMM_LIBRARIES
MercuryCommon::address
MercuryCommon::company
MercuryCommon::image
MercuryCommon::ocr
MercuryCommon::archive
MercuryCommon::text
MercuryCommon::config
MercuryCommon::crypto
MercuryCommon::file
MercuryCommon::pdf
MercuryCommon::email
MercuryCommon::logging
MercuryCommon::processing
MercuryCommon::sysutil
MercuryCommon::database
MercuryCommon::test
)
EOF
# Version file
cat > $out/lib/cmake/MercuryCommon/MercuryCommonConfigVersion.cmake <<EOF
set(PACKAGE_VERSION "3.2.0")
if(PACKAGE_FIND_VERSION VERSION_EQUAL 3.2.0)
set(PACKAGE_VERSION_COMPATIBLE TRUE)
set(PACKAGE_VERSION_EXACT TRUE)
endif()
EOF
'';
# Debugging hooks
postInstall = ''
# Verify installation
if [ ! -d "$out/lib" ]; then
echo "ERROR: No library files were installed to $out"
exit 1
elif [ ! -d "$out/include" ]; then
echo "ERROR: No include files were installed to $out"
exit 1
fi
'';
# Extra protection against empty outputs
dontInstall = false;
doCheck = true;
};
devShells.x86_64-linux.default = pkgs.mkShell {
packages = [ pkgs.cmake catch2 pdfhummus ];
shellHook = ''
mkdir -p extern/Catch2
cp -r ${catch2}/* extern/Catch2
chmod -R ug+w extern/Catch2
mkdir -p extern/PDFHummus
cp -r ${pdfhummus}/* extern/PDFHummus
chmod -R ug+w extern/PDFHummus
'';
};
};
}
- archive.nix file:
{
description = "CMake-based project using Catch2";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
flake-utils.url = "github:numtide/flake-utils";
catch2 = {
url = "github:catchorg/Catch2/v3.4.0";
flake = false;
};
pdfhummus = {
url = "github:galkahana/PDF-Writer/v4.6.2";
flake = false;
};
common
};
outputs = { self, nixpkgs, flake-utils, catch2, pdfhummus }:
let
pkgs = import nixpkgs { system = "x86_64-linux"; };
in {
packages.x86_64-linux.default = pkgs.stdenv.mkDerivation {
pname = "archive";
version = "3.2.0";
src = ./.;
nativeBuildInputs = [ pkgs.cmake pkgs.pkg-config ];
buildInputs = [
pkgs.unixODBC
pkgs.unixODBCDrivers.psql
pkgs.libuuid
pkgs.log4cpp
pkgs.libarchive
pkgs.libesmtp
pkgs.pcre
pkgs.openssl
];
preConfigure = ''
echo "PRECONFIGURE PHASE>>>>>> ${catch2} & ${pdfhummus}"
mkdir -p extern/Catch2
cp -r ${catch2}/* extern/Catch2
chmod -R ug+w extern/Catch2
mkdir -p extern/PDFHummus
cp -r ${pdfhummus}/* extern/PDFHummus
chmod -R ug+w extern/PDFHummus
'';
# Phase 2: Configure
configurePhase = ''
runHook preConfigure
echo "CONFIGURE PHASE>>>>>>"
cmake -B build -S . \
-DCMAKE_INSTALL_PREFIX=$out \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CATCH2_DIR=extern/Catch2 \
-DCMAKE_PDFHUMMUS_DIR=extern/PDFHummus
'';
# Phase 3: Build
buildPhase = ''
NIX_CFLAGS_COMPILE="$(pkg-config --cflags opencv4) $NIX_CFLAGS_COMPILE"
NIX_CFLAGS_COMPILE="$(pkg-config --cflags opencv4) $NIX_CFLAGS_COMPILE"
cmake --build build --parallel $NIX_BUILD_CORES
'';
# Phase 4: Unit test
checkPhase = ''
ctest --output-on-failure
'';
# Phase 5: 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;
doCheck = true;
};
devShells.x86_64-linux.default = pkgs.mkShell {
packages = [ pkgs.cmake catch2 pdfhummus ];
shellHook = ''
mkdir -p extern/Catch2
cp -r ${catch2}/* extern/Catch2
chmod -R ug+w extern/Catch2
mkdir -p extern/PDFHummus
cp -r ${pdfhummus}/* extern/PDFHummus
chmod -R ug+w extern/PDFHummus
'';
};
};
}