From 0739253884b22adbe3516d68ed031c5901a3d786 Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Mon, 2 Mar 2026 08:39:45 -0800 Subject: [PATCH 1/4] testers.pkg-config.testInstall: init --- build-support/testers/default.nix | 2 + build-support/testers/pkg-config/default.nix | 187 +++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 build-support/testers/pkg-config/default.nix diff --git a/build-support/testers/default.nix b/build-support/testers/default.nix index ac31c22a..916800a1 100644 --- a/build-support/testers/default.nix +++ b/build-support/testers/default.nix @@ -239,6 +239,8 @@ testMetaPkgConfig = callPackage ./testMetaPkgConfig/tester.nix { }; + pkg-config = callPackage ./pkg-config { }; + shellcheck = callPackage ./shellcheck/tester.nix { }; shfmt = callPackage ./shfmt { }; diff --git a/build-support/testers/pkg-config/default.nix b/build-support/testers/pkg-config/default.nix new file mode 100644 index 00000000..845eb1d2 --- /dev/null +++ b/build-support/testers/pkg-config/default.nix @@ -0,0 +1,187 @@ +{ + lib, + buildPackages, + runCommand, +}: + +{ + # Test function to verify pkg-config installation and optionally compile example code + # Usage: testers.pkg-config.testInstall myPackage { modules = [ "foo" ]; example = ./example.c; } + testInstall = + package: + { + modules ? package.meta.pkgConfigModules or [ ], + example ? null, + }: + runCommand "test-pkg-config-install-${package.pname or package.name}" + { + nativeBuildInputs = [ + buildPackages.stdenv.cc + buildPackages.pkg-config + ]; + buildInputs = [ package ]; + inherit modules; + expectedInclude = lib.getInclude package; + expectedLib = lib.getLib package; + } + ( + lib.optionalString (example != null) '' + exampleSrc=${example} + '' + + '' + set -e + + echo "Testing pkg-config installation for ${package.name}" + echo "============================================" + + # Test each module (if modules are specified) + if [ -n "$modules" ]; then + for module in $modules; do + echo "" + echo "Testing module: $module" + + # Check if module exists + if ! pkg-config --exists "$module"; then + echo "❌ ERROR: Module $module not found" + echo "" + echo "Available modules:" + pkg-config --list-all + exit 1 + fi + + # Get and display version + version=$(pkg-config --modversion "$module") + echo " Version: $version" + + # Get and validate cflags + cflags=$(pkg-config --cflags "$module") + echo " CFLAGS: $cflags" + + # Get and validate libs + libs=$(pkg-config --libs "$module") + echo " LIBS: $libs" + + # Extract and validate include paths + includePaths=$(pkg-config --cflags-only-I "$module" || echo "") + if [ -n "$includePaths" ]; then + echo " Include paths: $includePaths" + # Check if any include path matches the expected Nix include path + foundInclude=false + for path in $includePaths; do + # Remove -I prefix + cleanPath=''${path#-I} + + # Assert that the path exists + if [ ! -d "$cleanPath" ]; then + echo " ❌ ERROR: Include path does not exist: $cleanPath" + exit 1 + fi + + # Assert that the path is not empty + if [ -z "$(ls -A "$cleanPath" 2>/dev/null)" ]; then + echo " ❌ ERROR: Include path exists but is empty: $cleanPath" + exit 1 + fi + + # Check if this path is under the expected include directory + if [[ "$cleanPath" == "$expectedInclude"* ]]; then + echo " ✅ Include path matches Nix store: $cleanPath" + foundInclude=true + break + fi + done + if [ "$foundInclude" = false ] && [ -d "$expectedInclude/include" ]; then + echo " ⚠️ WARNING: No include path matches expected Nix location: $expectedInclude/include" + fi + fi + + # Extract and validate library paths + libPaths=$(pkg-config --libs-only-L "$module" || echo "") + if [ -n "$libPaths" ]; then + echo " Library paths: $libPaths" + # Check if any lib path matches the expected Nix lib path + foundLib=false + for path in $libPaths; do + # Remove -L prefix + cleanPath=''${path#-L} + + # Assert that the path exists + if [ ! -d "$cleanPath" ]; then + echo " ❌ ERROR: Library path does not exist: $cleanPath" + exit 1 + fi + + # Assert that the path is not empty + if [ -z "$(ls -A "$cleanPath" 2>/dev/null)" ]; then + echo " ❌ ERROR: Library path exists but is empty: $cleanPath" + exit 1 + fi + + # Check if this path is under the expected lib directory + if [[ "$cleanPath" == "$expectedLib"* ]]; then + echo " ✅ Library path matches Nix store: $cleanPath" + foundLib=true + break + fi + done + if [ "$foundLib" = false ] && [ -d "$expectedLib/lib" ]; then + echo " ⚠️ WARNING: No library path matches expected Nix location: $expectedLib/lib" + fi + fi + + echo " ✅ Module $module OK" + done + else + echo "No pkg-config modules specified for testing" + if [ -z "$exampleSrc" ]; then + echo "ERROR: No modules or example provided - nothing to test" + exit 1 + fi + fi + + # If example source is provided, compile and link it + if [ -n "$exampleSrc" ]; then + echo "" + echo "Compiling example: $exampleSrc" + echo "--------------------------------" + + # Get combined flags for all modules + if [ -n "$modules" ]; then + allCflags=$(pkg-config --cflags $modules) + allLibs=$(pkg-config --libs $modules) + echo "Combined CFLAGS: $allCflags" + echo "Combined LIBS: $allLibs" + else + allCflags="" + allLibs="" + echo "No modules specified - compiling without pkg-config flags" + fi + + # Compile + echo "Compiling..." + if ! $CC $allCflags -c "$exampleSrc" -o example.o; then + echo "❌ ERROR: Compilation failed" + exit 1 + fi + echo " ✅ Compilation successful" + + # Link + echo "Linking..." + if ! $CC example.o $allLibs -o example; then + echo "❌ ERROR: Linking failed" + exit 1 + fi + echo " ✅ Linking successful" + + echo "" + echo "✅ Example code compiled and linked successfully" + fi + + echo "" + echo "============================================" + echo "✅ All pkg-config tests passed for ${package.name}" + + touch "$out" + '' + ); +} From 7ad6b444b6bb249e33f1da0a657b1be664d6b381 Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Mon, 2 Mar 2026 08:41:34 -0800 Subject: [PATCH 2/4] testers: import correctly --- top-level.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/top-level.nix b/top-level.nix index 66d28ee8..ea80f8bd 100644 --- a/top-level.nix +++ b/top-level.nix @@ -11,7 +11,6 @@ with final; { # TODO(corepkgs): support NixOS tests - testers = { }; nixosTests = { }; tests = { }; @@ -1339,6 +1338,8 @@ with final; perl540Packages = lib.recurseIntoAttrs perl.v5_40.pkgs; perlPackages = perl540Packages; + testers = callPackage ./build-support/testers { }; + texinfo6 = texinfo.v6; texinfo7 = texinfo.v7; texinfoInteractive = texinfo.interactive; From d4ad0e5ef9146e79bc8f7366363a09367145e5af Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Mon, 2 Mar 2026 08:45:45 -0800 Subject: [PATCH 3/4] bzip2: use pkg-config.testInstall --- pkgs/bzip2/default.nix | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkgs/bzip2/default.nix b/pkgs/bzip2/default.nix index 393de458..704c9e35 100644 --- a/pkgs/bzip2/default.nix +++ b/pkgs/bzip2/default.nix @@ -69,7 +69,10 @@ stdenv.mkDerivation ( ln -s $out/lib/libbz2.so.1.0.* $out/lib/libbz2.so.1.0 ''; - passthru.tests.pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage; + passthru.tests = { + pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage; + pkg-config-install = testers.pkg-config.testInstall finalAttrs.finalPackage {}; + }; meta = { description = "High-quality data compression program"; From 3097c1e8a2e7a58b4bdb5748eed6664c7f0e0bb0 Mon Sep 17 00:00:00 2001 From: Jonathan Ringer Date: Mon, 2 Mar 2026 08:53:23 -0800 Subject: [PATCH 4/4] bzip2: add example pkg-config compilation --- pkgs/bzip2/default.nix | 4 +++- pkgs/bzip2/test-example.c | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 pkgs/bzip2/test-example.c diff --git a/pkgs/bzip2/default.nix b/pkgs/bzip2/default.nix index 704c9e35..ac95695e 100644 --- a/pkgs/bzip2/default.nix +++ b/pkgs/bzip2/default.nix @@ -71,7 +71,9 @@ stdenv.mkDerivation ( passthru.tests = { pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage; - pkg-config-install = testers.pkg-config.testInstall finalAttrs.finalPackage {}; + pkg-config-install = testers.pkg-config.testInstall finalAttrs.finalPackage { + example = ./test-example.c; + }; }; meta = { diff --git a/pkgs/bzip2/test-example.c b/pkgs/bzip2/test-example.c new file mode 100644 index 00000000..ecbeae7e --- /dev/null +++ b/pkgs/bzip2/test-example.c @@ -0,0 +1,16 @@ +/* Minimal test program to verify bzip2 can be compiled and linked */ +#include +#include + +int main(void) { + /* Call a simple bzip2 function to verify the library is properly linked */ + const char *version = BZ2_bzlibVersion(); + + if (version == NULL) { + fprintf(stderr, "Error: BZ2_bzlibVersion() returned NULL\n"); + return 1; + } + + printf("Successfully linked against bzip2 version: %s\n", version); + return 0; +}