push sheeet
Some checks failed
Periodic Merges (6h) / master → staging-nixos (push) Failing after 12m50s
Periodic Merges (6h) / master → staging-next (push) Failing after 12m54s
Periodic Merges (24h) / merge-base(master,staging) → haskell-updates (push) Failing after 11m54s
Periodic Merges (6h) / staging-next → staging (push) Failing after 12m13s
Periodic Merges (24h) / staging-next-25.05 → staging-25.05 (push) Failing after 13m24s
Periodic Merges (24h) / release-25.05 → staging-next-25.05 (push) Failing after 14m28s

This commit is contained in:
Dark Steveneq
2025-10-09 14:15:47 +02:00
commit 646b892680
49168 changed files with 5897842 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
{ lib, callPackage }:
lib.recurseIntoAttrs {
withStructuredAttrs = callPackage ./package.nix { __structuredAttrs = true; };
withoutStructuredAttrs = callPackage ./package.nix { __structuredAttrs = false; };
}

View File

@@ -0,0 +1,107 @@
# This is a test for autoPatchelfHook. To test it, we just need a simple binary
# which uses the hook. We took the derivation from tonelib-jam, which sounds
# like a good candidate with a small closure, and trimmed it down.
{
stdenv,
lib,
fetchurl,
autoPatchelfHook,
dpkg,
freetype,
curl,
# This test checks that the behavior of autoPatchelfHook is correct whether
# __structuredAttrs
# (https://nixos.org/manual/nix/stable/language/advanced-attributes#adv-attr-structuredAttrs)
# is set or not. Hence __structuredAttrs is provided as a parameter.
__structuredAttrs,
}:
let
runtimeDependencies = [
(lib.getLib curl)
"/some/dep"
"/some/other/dep"
]
# A dependency with space only works with __structuredAttrs set to true.
++ lib.lists.optional __structuredAttrs "/some/dep with space";
in
stdenv.mkDerivation {
name = "auto-patchelf-test";
src = fetchurl {
url = "https://tonelib.net/download/221222/ToneLib-Jam-amd64.deb";
sha256 = "sha256-c6At2lRPngQPpE7O+VY/Hsfw+QfIb3COIuHfbqqIEuM=";
};
unpackCmd = ''
dpkg -x $curSrc source
'';
nativeBuildInputs = [
dpkg
autoPatchelfHook
];
installPhase = ''
mv usr $out
'';
buildInputs = [
freetype
];
autoPatchelfIgnoreMissingDeps = [
"libGL.so.1"
"libasound.so.2"
];
inherit runtimeDependencies;
# Additional phase performing the actual test.
installCheckPhase =
let
allDeps = runtimeDependencies ++ [
(lib.getLib freetype)
];
in
''
local binary="$out/bin/ToneLib-Jam"
local interpreter=$(patchelf --print-interpreter $binary)
local runpath=$(patchelf --print-rpath $binary)
local glibcStorePath="${stdenv.cc.libc}"
# Check that the glibc path is a prefix of the interpreter. If
# autoPatchelfHook ran correctly, the binary should have set the interpreter
# to point to the store.
echo "[auto-patchelf-hook-test]: Check that the interpreter is in the store"
test "''${interpreter#$glibcStorePath}" != "$interpreter"
readarray -td':' runpathArray < <(echo -n "$runpath")
echo "[auto-patchelf-hook-test]: Check that the runpath has the right number of entries"
test "''${#runpathArray[@]}" -eq ${toString (builtins.length allDeps)}
echo "[auto-patchelf-hook-test]: Check that the runpath contains the expected runtime deps"
''
+ lib.strings.concatStringsSep "\n" (
lib.lists.imap0 (
i: path:
let
iAsStr = toString i;
in
''
echo "[auto-patchelf-hook-test]: Check that entry ${iAsStr} is ${path}"
test "''${paths[${iAsStr}]}" = "$path"
''
) allDeps
);
doInstallCheck = true;
inherit __structuredAttrs;
meta = {
# Downloads an x86_64-linux only binary
platforms = [ "x86_64-linux" ];
};
}

View File

@@ -0,0 +1,39 @@
{
lib,
stdenv,
runCommand,
getent,
xcbuild,
}:
# Prints information about the state of the build environment for
# assistance debugging Hydra. Feel free to add anything you would find
# useful to this.
runCommand "build-environment-info"
{
nativeBuildInputs = [ getent ] ++ lib.optionals stdenv.buildPlatform.isDarwin [ xcbuild ];
}
''
# Its useful to get more info even if a command fails.
set +e
run() {
echoCmd : "$@"
"$@"
}
run uname -a
${lib.optionalString stdenv.buildPlatform.isDarwin ''
run env SYSTEM_VERSION_COMPAT=0 plutil -p /System/Library/CoreServices/SystemVersion.plist
''}
run id
run getent passwd "$(id -un)"
run ulimit -a
# Always fail so that this job can easily be restarted.
run exit 1
''

View File

@@ -0,0 +1,99 @@
{
lib,
buildFHSEnv,
runCommand,
stdenv,
fetchurl,
dpkg,
glibc,
callPackage,
}:
let
getSharedObjectFromDebian =
sharedObjectName: src:
stdenv.mkDerivation {
name = "${sharedObjectName}-fetcher";
inherit src;
nativeBuildInputs = [
dpkg
];
dontBuild = true;
dontConfigure = true;
dontFixup = true;
installPhase = ''
echo shared objects found are:
ls -l usr/lib/*/
cp usr/lib/*/${sharedObjectName} $out
'';
};
makeSharedObjectTest =
sharedObject: targetPkgs:
let
lddFHSEnv = buildFHSEnv {
name = "ldd-with-ncurses-FHS-env";
inherit targetPkgs;
runScript = "ldd";
};
ldd-in-FHS = "${lddFHSEnv}/bin/${lddFHSEnv.name}";
ldd = "${lib.getBin glibc}/bin/ldd";
find_libFHSEnv = buildFHSEnv {
name = "ls-with-ncurses-FHS-env";
targetPkgs = p: [
p.ncurses5
];
runScript = "find /lib/ -executable";
};
find_lib-in-FHS = "${find_libFHSEnv}/bin/${find_libFHSEnv.name}";
in
runCommand "FHS-lib-test"
{
meta = {
# Downloads an x86_64-linux only binary
platforms = [ "x86_64-linux" ];
};
}
''
echo original ldd output is:
${ldd} ${sharedObject}
lddOutput="$(${ldd-in-FHS} ${sharedObject})"
echo ldd output inside FHS is:
echo "$lddOutput"
if echo $lddOutput | grep -q "not found"; then
echo "shared object could not find all dependencies in the FHS!"
echo The libraries below where found in the FHS:
${find_lib-in-FHS}
exit 1
else
echo $lddOutput > $out
fi
'';
in
{
# This test proves an issue with buildFHSEnv - don't expect it to succeed,
# this is discussed in https://github.com/NixOS/nixpkgs/pull/279844 .
libtinfo =
makeSharedObjectTest
(getSharedObjectFromDebian "libedit.so.2.0.70" (fetchurl {
url = "mirror://debian/pool/main/libe/libedit/libedit2_3.1-20221030-2_amd64.deb";
hash = "sha256-HPFKvycW0yedsS0GV6VzfPcAdKHnHTvfcyBmJePInOY=";
}))
(p: [
p.libtinfo
p.libbsd
]);
liblzma =
makeSharedObjectTest
(getSharedObjectFromDebian "libxml2.so.2.9.14" (fetchurl {
url = "mirror://debian/pool/main/libx/libxml2/libxml2_2.9.14+dfsg-1.3~deb12u1_amd64.deb";
hash = "sha256-NbdstwOPwclAIEpPBfM/+3nQJzU85Gk5fZrc+Pmz4ac=";
}))
(p: [
p.xz
p.zlib
p.icu72
]);
}

View File

@@ -0,0 +1,8 @@
#include <atomic>
#include <cstdint>
int main()
{
std::atomic_int x = {0};
return !std::atomic_is_lock_free(&x);
}

View File

@@ -0,0 +1,7 @@
#include <stdio.h>
int main(int argc, char **argv)
{
fprintf(stderr, "ok\n");
return 0;
}

View File

@@ -0,0 +1,10 @@
#include <stdio.h>
#include <foo.h>
int main(int argc, char **argv)
{
if (foo() != 42)
return 1;
fprintf(stderr, "ok\n");
return 0;
}

View File

@@ -0,0 +1,7 @@
#include <CoreFoundation/CoreFoundation.h>
int main(int argc, char** argv)
{
CFShow(CFSTR("ok"));
return 0;
}

View File

@@ -0,0 +1,7 @@
#include <iostream>
int main(int argc, char **argv)
{
std::cerr << "ok" << std::endl;
return 0;
}

View File

@@ -0,0 +1,157 @@
{
lib,
stdenv,
glibc,
buildPackages,
}:
let
# Sanitizers are not supported on Darwin.
# Sanitizer headers aren't available in older libc++ stdenvs due to a bug
sanitizersWorking =
(stdenv.buildPlatform == stdenv.hostPlatform)
&& !stdenv.hostPlatform.isDarwin
&& !stdenv.hostPlatform.isMusl
&& (
(stdenv.cc.isClang && lib.versionAtLeast (lib.getVersion stdenv.cc.name) "5.0.0")
|| (stdenv.cc.isGNU && stdenv.hostPlatform.isLinux)
);
staticLibc = lib.optionalString (stdenv.hostPlatform.libc == "glibc") "-L ${glibc.static}/lib";
emulator = stdenv.hostPlatform.emulator buildPackages;
isCxx = stdenv.cc.libcxx != null;
libcxxStdenvSuffix = lib.optionalString isCxx "-libcxx";
CC = "PATH= ${lib.getExe' stdenv.cc "${stdenv.cc.targetPrefix}cc"}";
CXX = "PATH= ${lib.getExe' stdenv.cc "${stdenv.cc.targetPrefix}c++"}";
READELF = "PATH= ${lib.getExe' stdenv.cc "${stdenv.cc.targetPrefix}readelf"}";
in
stdenv.mkDerivation {
pname = "cc-wrapper-test-${stdenv.cc.cc.pname}${libcxxStdenvSuffix}";
version = stdenv.cc.version;
buildCommand = ''
echo "Testing: ${stdenv.cc.name}" >&2
echo "With libc: ${stdenv.cc.libc.name}" >&2
set -o pipefail
NIX_DEBUG=1 ${CC} -v
NIX_DEBUG=1 ${CXX} -v
echo "checking whether compiler builds valid C binaries... " >&2
${CC} -o cc-check ${./cc-main.c}
${emulator} ./cc-check
echo "checking whether compiler builds valid C++ binaries... " >&2
${CXX} -o cxx-check ${./cxx-main.cc}
${emulator} ./cxx-check
# test for https://github.com/NixOS/nixpkgs/issues/214524#issuecomment-1431745905
# .../include/cxxabi.h:20:10: fatal error: '__cxxabi_config.h' file not found
# in libcxxStdenv
echo "checking whether cxxabi.h can be included... " >&2
${CXX} -o include-cxxabi ${./include-cxxabi.cc}
${emulator} ./include-cxxabi
# cxx doesn't have libatomic.so
${lib.optionalString (!isCxx) ''
# https://github.com/NixOS/nixpkgs/issues/91285
echo "checking whether libatomic.so can be linked... " >&2
${CXX} -shared -o atomics.so ${./atomics.cc} -latomic ${
lib.optionalString (stdenv.cc.isClang && lib.versionOlder stdenv.cc.version "6.0.0") "-std=c++17"
}
${READELF} -d ./atomics.so | grep libatomic.so && echo "ok" >&2 || echo "failed" >&2
''}
# Test that linking libc++ works, and statically.
${lib.optionalString isCxx ''
echo "checking whether can link with libc++... " >&2
NIX_DEBUG=1 ${CXX} ${./cxx-main.cc} -c -o cxx-main.o
NIX_DEBUG=1 ${CC} cxx-main.o -lc++ -o cxx-main
NIX_DEBUG=1 ${CC} cxx-main.o ${lib.getLib stdenv.cc.libcxx}/lib/libc++.a -o cxx-main-static
${emulator} ./cxx-main
${emulator} ./cxx-main-static
rm cxx-main{,-static,.o}
''}
${lib.optionalString (stdenv.hostPlatform.isDarwin && stdenv.cc.isClang) ''
echo "checking whether compiler can build with CoreFoundation.framework... " >&2
mkdir -p foo/lib
${CC} -framework CoreFoundation -o core-foundation-check ${./core-foundation-main.c}
${emulator} ./core-foundation-check
''}
${lib.optionalString (!stdenv.hostPlatform.isDarwin) ''
echo "checking whether compiler builds valid static C binaries... " >&2
${CC} ${staticLibc} -static -o cc-static ${./cc-main.c}
${emulator} ./cc-static
${lib.optionalString (stdenv.cc.isGNU && lib.versionAtLeast (lib.getVersion stdenv.cc.name) "8.0.0")
''
echo "checking whether compiler builds valid static pie C binaries... " >&2
${CC} ${staticLibc} -static-pie -o cc-static-pie ${./cc-main.c}
${emulator} ./cc-static-pie
''
}
''}
${
# See: https://github.com/llvm/llvm-project/commit/ed1d07282cc9d8e4c25d585e03e5c8a1b6f63a74
# `gcc` does not support this so we gate the test on `clang`
lib.optionalString stdenv.cc.isClang ''
echo "checking whether cc-wrapper accepts -- followed by positional (file) args..." >&2
mkdir -p positional
# Make sure `--` is not parsed as a "non flag arg"; we should get an
# input file error here and *not* a linker error.
{ ! ${CC} --; } |& grep -q "no input files"
# And that positional file args _must_ be files (this is just testing
# that we remembered to put the `--` back in the args to the compiler):
{ ! ${CC} -c -- -o foo ${./foo.c}; } \
|& grep -q "no such file or directory: '-o'"
# Now check that we accept single and multiple positional file args:
${CC} -c -DVALUE=42 -o positional/foo.o -- ${./foo.c}
${CC} -o positional/main -- positional/foo.o ${./ldflags-main.c}
${emulator} ./positional/main
''
}
echo "checking whether compiler uses NIX_CFLAGS_COMPILE... " >&2
mkdir -p foo/include
cp ${./foo.c} foo/include/foo.h
NIX_CFLAGS_COMPILE="-Ifoo/include -DVALUE=42" ${CC} -o cflags-check ${./cflags-main.c}
${emulator} ./cflags-check
echo "checking whether compiler uses NIX_LDFLAGS... " >&2
mkdir -p foo/lib
${CC} -shared \
${lib.optionalString stdenv.hostPlatform.isDarwin "-Wl,-install_name,@rpath/libfoo.dylib"} \
-DVALUE=42 \
-o foo/lib/libfoo${stdenv.hostPlatform.extensions.sharedLibrary} \
${./foo.c}
NIX_LDFLAGS="-L$NIX_BUILD_TOP/foo/lib -rpath $NIX_BUILD_TOP/foo/lib" ${CC} -lfoo -o ldflags-check ${./ldflags-main.c}
${emulator} ./ldflags-check
echo "Check whether -nostdinc and -nostdinc++ is handled correctly" >&2
mkdir -p std-include
cp ${./stdio.h} std-include/stdio.h
NIX_DEBUG=1 ${CC} -I std-include -nostdinc -o nostdinc-main ${./nostdinc-main.c}
${emulator} ./nostdinc-main
${CXX} -I std-include -nostdinc++ -o nostdinc-main++ ${./nostdinc-main.c}
${emulator} ./nostdinc-main++
${lib.optionalString sanitizersWorking ''
echo "checking whether sanitizers are fully functional... ">&2
${CC} -o sanitizers -fsanitize=address,undefined ${./sanitizers.c}
ASAN_OPTIONS=use_sigaltstack=0 ${emulator} ./sanitizers
''}
echo "Check whether CC and LD with NIX_X_USE_RESPONSE_FILE hardcodes all required binaries..." >&2
NIX_CC_USE_RESPONSE_FILE=1 NIX_LD_USE_RESPONSE_FILE=1 ${CC} -v
touch $out
'';
meta.platforms = lib.platforms.all;
}

View File

@@ -0,0 +1,33 @@
/* an example that should be protected by FORTIFY_SOURCE=2 but
* only if the appropriate -fstrict-flex-arrays= argument is used
* for the corresponding value used for BUFFER_DEF_SIZE
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct buffer_with_header {
char header[1];
char buffer[BUFFER_DEF_SIZE];
};
int main(int argc, char *argv[]) {
/* use volatile pointer to prevent compiler
* using the outer allocation length with a
* fortified strcpy, which would throw off
* the function-name-sniffing fortify-detecting
* approaches
*/
struct buffer_with_header *volatile b = \
(struct buffer_with_header *)malloc(sizeof(struct buffer_with_header)+1);
/* if there are no arguments, skip the write to allow
* builds with BUFFER_DEF_SIZE=0 to have a case where
* the program passes even with strict protection.
*/
if (argc > 1) {
strcpy(b->buffer, argv[1]);
puts(b->buffer);
}
return 0;
}

View File

@@ -0,0 +1,4 @@
unsigned int foo(void)
{
return VALUE;
}

View File

@@ -0,0 +1,16 @@
/* an example that should be protected by FORTIFY_SOURCE=1 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
/* allocate on the heap so we're likely to get an
* over-allocation and can be more sure that a
* failure is because of fortify protection rather
* than a genuine segfault */
char* buffer = malloc(sizeof(char) * 7);
strcpy(buffer, argv[1]);
puts(buffer);
return 0;
}

View File

@@ -0,0 +1,16 @@
/* an example that should be protected by FORTIFY_SOURCE=2 but
* not FORTIFY_SOURCE=1 */
#include <stdio.h>
#include <string.h>
struct buffer_with_pad {
char buffer[7];
char pad[25];
};
int main(int argc, char *argv[]) {
struct buffer_with_pad b;
strcpy(b.buffer, argv[1]);
puts(b.buffer);
return 0;
}

View File

@@ -0,0 +1,13 @@
/* an example that should be protected by FORTIFY_SOURCE=3 but
* not FORTIFY_SOURCE=2 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char* buffer = malloc(atoi(argv[2]));
strcpy(buffer, argv[1]);
puts(buffer);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
#include <cxxabi.h>
#include <iostream>
int main(int argc, char **argv)
{
std::cerr << "ok" << std::endl;
return 0;
}

View File

@@ -0,0 +1,12 @@
#include <stdio.h>
extern unsigned int foo(void);
int main(int argc, char **argv)
{
if (foo() != 42) {
return 1;
}
fprintf(stderr, "ok\n");
return 0;
}

View File

@@ -0,0 +1,37 @@
{ lib, stdenv }:
stdenv.mkDerivation {
name = "cc-multilib-test";
# XXX: "depend" on cc-wrapper test?
# TODO: Have tests report pointer size or something; ensure they are what we asked for
buildCommand = ''
NIX_DEBUG=1 $CC -v
NIX_DEBUG=1 $CXX -v
printf "checking whether compiler builds valid C binaries...\n " >&2
$CC -o cc-check ${./cc-main.c}
./cc-check
printf "checking whether compiler builds valid 32bit C binaries...\n " >&2
$CC -m32 -o c32-check ${./cc-main.c}
./c32-check
printf "checking whether compiler builds valid 64bit C binaries...\n " >&2
$CC -m64 -o c64-check ${./cc-main.c}
./c64-check
printf "checking whether compiler builds valid 32bit C++ binaries...\n " >&2
$CXX -m32 -o cxx32-check ${./cxx-main.cc}
./cxx32-check
printf "checking whether compiler builds valid 64bit C++ binaries...\n " >&2
$CXX -m64 -o cxx64-check ${./cxx-main.cc}
./cxx64-check
touch $out
'';
meta.platforms = lib.platforms.x86_64;
}

View File

@@ -0,0 +1,8 @@
// This one should not come from libc because of -nostdinc
#include <stdio.h>
int main(int argc, char *argv[]) {
// provided by our own stdio.h
foo();
return 0;
}

View File

@@ -0,0 +1,8 @@
#include <sanitizer/asan_interface.h>
#include <stdio.h>
int main(int argc, char **argv)
{
fprintf(stderr, "ok\n");
return 0;
}

View File

@@ -0,0 +1 @@
static void foo(void) {}

View File

@@ -0,0 +1 @@
0.1.2

View File

@@ -0,0 +1,65 @@
{
hello,
checkpointBuildTools,
runCommand,
texinfo,
stdenv,
rsync,
}:
let
baseHelloArtifacts = checkpointBuildTools.prepareCheckpointBuild hello;
patchedHello = hello.overrideAttrs (old: {
buildInputs = [ texinfo ];
src = runCommand "patch-hello-src" { } ''
mkdir -p $out
cd $out
tar xf ${hello.src} --strip-components=1
patch -p1 < ${./hello.patch}
'';
});
checkpointBuiltHello = checkpointBuildTools.mkCheckpointBuild patchedHello baseHelloArtifacts;
checkpointBuiltHelloWithCheck = checkpointBuiltHello.overrideAttrs (old: {
doCheck = true;
checkPhase = ''
echo "checking if unchanged source file is not recompiled"
[ "$(stat --format="%Y" lib/exitfail.o)" = "$(stat --format="%Y" ${baseHelloArtifacts}/outputs/lib/exitfail.o)" ]
'';
});
baseHelloRemoveFileArtifacts = checkpointBuildTools.prepareCheckpointBuild (
hello.overrideAttrs (old: {
patches = [ ./hello-additionalFile.patch ];
})
);
preparedHelloRemoveFileSrc = runCommand "patch-hello-src" { } ''
mkdir -p $out
cd $out
tar xf ${hello.src} --strip-components=1
patch -p1 < ${./hello-additionalFile.patch}
'';
patchedHelloRemoveFile = hello.overrideAttrs (old: {
buildInputs = [ texinfo ];
src = runCommand "patch-hello-src" { } ''
mkdir -p $out
cd $out
${rsync}/bin/rsync -cutU --chown=$USER:$USER --chmod=+w -r ${preparedHelloRemoveFileSrc}/* .
patch -p1 < ${./hello-removeFile.patch}
'';
});
checkpointBuiltHelloWithRemovedFile = checkpointBuildTools.mkCheckpointBuild patchedHelloRemoveFile baseHelloRemoveFileArtifacts;
in
stdenv.mkDerivation {
name = "patched-hello-returns-correct-output";
buildCommand = ''
touch $out
echo "testing output of hello binary"
[ "$(${checkpointBuiltHelloWithCheck}/bin/hello)" = "Hello, incremental world!" ]
echo "testing output of hello with removed file"
[ "$(${checkpointBuiltHelloWithRemovedFile}/bin/hello)" = "Hello, incremental world!" ]
'';
}

View File

@@ -0,0 +1,67 @@
:100644 100644 0000000 0000000 M Makefile.in
:000000 100644 0000000 0000000 A src/additionalFile.c
:100644 100644 0000000 0000000 M src/hello.c
:100644 100644 0000000 0000000 M src/system.h
diff --git a/Makefile.in b/Makefile.in
index 1597d39..f63f830 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -312,7 +312,7 @@ am_lib_libhello_a_OBJECTS = lib/basename-lgpl.$(OBJEXT) \
lib/version-etc.$(OBJEXT) lib/version-etc-fsf.$(OBJEXT) \
lib/wctype-h.$(OBJEXT) lib/xmalloc.$(OBJEXT) \
lib/xalloc-die.$(OBJEXT) lib/xstriconv.$(OBJEXT) \
- lib/xstrndup.$(OBJEXT)
+ lib/xstrndup.$(OBJEXT) src/additionalFile.$(OBJEXT)
lib_libhello_a_OBJECTS = $(am_lib_libhello_a_OBJECTS)
am_hello_OBJECTS = src/hello.$(OBJEXT)
hello_OBJECTS = $(am_hello_OBJECTS)
@@ -1842,7 +1842,7 @@ lib_libhello_a_SOURCES = lib/basename-lgpl.c lib/c-ctype.h \
$(am__append_4) $(am__append_5) lib/version-etc.h \
lib/version-etc.c lib/version-etc-fsf.c lib/wctype-h.c \
lib/xmalloc.c lib/xalloc-die.c lib/xstriconv.h lib/xstriconv.c \
- lib/xstrndup.h lib/xstrndup.c
+ lib/xstrndup.h lib/xstrndup.c src/additionalFile.c
lib_libhello_a_LIBADD = $(gl_LIBOBJS)
lib_libhello_a_DEPENDENCIES = $(gl_LIBOBJS)
EXTRA_lib_libhello_a_SOURCES = lib/close.c lib/stripslash.c lib/dup2.c \
diff --git a/src/additionalFile.c b/src/additionalFile.c
new file mode 100644
index 0000000..34d683d
--- /dev/null
+++ b/src/additionalFile.c
@@ -0,0 +1,6 @@
+#include "config.h"
+#include "system.h"
+
+int somefunc() {
+ return 0;
+}
diff --git a/src/hello.c b/src/hello.c
index 2e7d38e..a8e36dc 100644
--- a/src/hello.c
+++ b/src/hello.c
@@ -146,7 +146,11 @@ main (int argc, char *argv[])
#endif
/* Having initialized gettext, get the default message. */
- greeting_msg = _("Hello, world!");
+ if (somefunc() == 0) {
+ greeting_msg = _("Hello, world!");
+ } else {
+ greeting_msg = _("Hello, incremental world!");
+ }
/* Even exiting has subtleties. On exit, if any writes failed, change
the exit status. The /dev/full device on GNU/Linux can be used for
diff --git a/src/system.h b/src/system.h
index d39cdb9..dc425d2 100644
--- a/src/system.h
+++ b/src/system.h
@@ -59,4 +59,6 @@
} \
while (0)
+int somefunc();
+
#endif /* HELLO_SYSTEM_H */

View File

@@ -0,0 +1,67 @@
:100644 100644 0000000 0000000 M Makefile.in
:100644 000000 0000000 0000000 D src/additionalFile.c
:100644 100644 0000000 0000000 M src/hello.c
:100755 100755 0000000 0000000 M tests/hello-1
diff --git a/Makefile.in b/Makefile.in
index f63f830..1597d39 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -312,7 +312,7 @@ am_lib_libhello_a_OBJECTS = lib/basename-lgpl.$(OBJEXT) \
lib/version-etc.$(OBJEXT) lib/version-etc-fsf.$(OBJEXT) \
lib/wctype-h.$(OBJEXT) lib/xmalloc.$(OBJEXT) \
lib/xalloc-die.$(OBJEXT) lib/xstriconv.$(OBJEXT) \
- lib/xstrndup.$(OBJEXT) src/additionalFile.$(OBJEXT)
+ lib/xstrndup.$(OBJEXT)
lib_libhello_a_OBJECTS = $(am_lib_libhello_a_OBJECTS)
am_hello_OBJECTS = src/hello.$(OBJEXT)
hello_OBJECTS = $(am_hello_OBJECTS)
@@ -1842,7 +1842,7 @@ lib_libhello_a_SOURCES = lib/basename-lgpl.c lib/c-ctype.h \
$(am__append_4) $(am__append_5) lib/version-etc.h \
lib/version-etc.c lib/version-etc-fsf.c lib/wctype-h.c \
lib/xmalloc.c lib/xalloc-die.c lib/xstriconv.h lib/xstriconv.c \
- lib/xstrndup.h lib/xstrndup.c src/additionalFile.c
+ lib/xstrndup.h lib/xstrndup.c
lib_libhello_a_LIBADD = $(gl_LIBOBJS)
lib_libhello_a_DEPENDENCIES = $(gl_LIBOBJS)
EXTRA_lib_libhello_a_SOURCES = lib/close.c lib/stripslash.c lib/dup2.c \
diff --git a/src/additionalFile.c b/src/additionalFile.c
deleted file mode 100644
index 34d683d..0000000
--- a/src/additionalFile.c
+++ /dev/null
@@ -1,6 +0,0 @@
-#include "config.h"
-#include "system.h"
-
-int somefunc() {
- return 0;
-}
diff --git a/src/hello.c b/src/hello.c
index a8e36dc..53722d9 100644
--- a/src/hello.c
+++ b/src/hello.c
@@ -126,6 +126,10 @@ parse_options (int argc, char *argv[], const char **greeting_msg)
}
}
+int somefunc() {
+ return 1;
+}
+
int
main (int argc, char *argv[])
{
diff --git a/tests/hello-1 b/tests/hello-1
index 96ffef8..f0b9f8d 100755
--- a/tests/hello-1
+++ b/tests/hello-1
@@ -21,7 +21,7 @@ export LANGUAGE LC_ALL LC_MESSAGES LANG
tmpfiles="hello-test1.ok"
cat <<EOF > hello-test1.ok
-Hello, world!
+Hello, incremental world!
EOF
tmpfiles="$tmpfiles hello-test1.out"

View File

@@ -0,0 +1,26 @@
diff --git a/src/hello.c b/src/hello.c
index 182303c..453962f 100644
--- a/src/hello.c
+++ b/src/hello.c
@@ -57,7 +57,7 @@ main (int argc, char *argv[])
#endif
/* Having initialized gettext, get the default message. */
- greeting_msg = _("Hello, world!");
+ greeting_msg = _("Hello, incremental world!");
/* Even exiting has subtleties. On exit, if any writes failed, change
the exit status. The /dev/full device on GNU/Linux can be used for
diff --git a/tests/hello-1 b/tests/hello-1
index 3b7a815..e15fa95 100755
--- a/tests/hello-1
+++ b/tests/hello-1
@@ -21,7 +21,7 @@ export LANGUAGE LC_ALL LC_MESSAGES LANG
tmpfiles="hello-test1.ok"
cat <<EOF > hello-test1.ok
-Hello, world!
+Hello, incremental world!
EOF
tmpfiles="$tmpfiles hello-test1.out"

28
pkgs/test/config.nix Normal file
View File

@@ -0,0 +1,28 @@
{
lib,
pkgs,
...
}:
lib.recurseIntoAttrs {
# https://github.com/NixOS/nixpkgs/issues/175196
# This test has since been simplified to test the recursion without
# the fluff to make it look like a real-world example.
# The requirement we test here is:
# - `permittedInsecurePackages` must be allowed to
# use `pkgs` to retrieve at least *some* information.
#
# Instead of `builtins.seq`, the list may be constructed based on actual package info.
allowPkgsInPermittedInsecurePackages =
let
pkgs' = import ../.. {
system = pkgs.stdenv.hostPlatform.system;
config = {
permittedInsecurePackages = builtins.seq pkgs'.glibc.version [ ];
};
};
in
pkgs'.hello;
}

View File

@@ -0,0 +1,5 @@
{ lib, callPackage }:
lib.recurseIntoAttrs {
overrideCoqDerivation = callPackage ./overrideCoqDerivation { };
}

View File

@@ -0,0 +1,43 @@
{
lib,
coq,
mkCoqPackages,
runCommand,
}:
let
# This is just coq, but with dontFilter set to true. We need to set
# dontFilter to true here so that _all_ packages are visible in coqPackages.
# There may be some versions of the top-level coq and coqPackages that don't
# build QuickChick, which is what we are using for this test below.
coqWithAllPackages = coq // {
dontFilter = true;
};
coqPackages = mkCoqPackages coqWithAllPackages;
# This is the main test. This uses overrideCoqDerivation to
# override arguments to mkCoqDerivation.
#
# Here, we override the defaultVersion and release arguments to
# mkCoqDerivation.
overriddenQuickChick = coqPackages.lib.overrideCoqDerivation {
defaultVersion = "9999";
release."9999".sha256 = lib.fakeSha256;
} coqPackages.QuickChick;
in
runCommand "coq-overrideCoqDerivation-test-0.1"
{ meta.maintainers = with lib.maintainers; [ cdepillabout ]; }
''
# Confirm that the computed version number for the overridden QuickChick does
# actually become 9999, as set above.
if [ "${overriddenQuickChick.version}" -eq "9999" ]; then
echo "overriddenQuickChick version was successfully set to 9999"
touch $out
else
echo "ERROR: overriddenQuickChick version was supposed to be 9999, but was actually: ${overriddenQuickChick.version}"
exit 1
fi
''

226
pkgs/test/cross/default.nix Normal file
View File

@@ -0,0 +1,226 @@
{ pkgs, lib }:
let
testedSystems = lib.filterAttrs (
name: value:
let
platform = lib.systems.elaborate value;
in
platform.isLinux || platform.isWindows
) lib.systems.examples;
getExecutable =
pkgs: pkgFun: exec:
"${pkgFun pkgs}${exec}${pkgs.stdenv.hostPlatform.extensions.executable}";
compareTest =
{
emulator,
pkgFun,
hostPkgs,
crossPkgs,
exec,
args ? [ ],
}:
let
pkgName = (pkgFun hostPkgs).name;
args' = lib.concatStringsSep " " args;
in
crossPkgs.runCommand "test-${pkgName}-${crossPkgs.stdenv.hostPlatform.config}"
{
nativeBuildInputs = [ pkgs.dos2unix ];
}
''
# Just in case we are using wine, get rid of that annoying extra
# stuff.
export WINEDEBUG=-all
HOME=$(pwd)
mkdir -p $out
# We need to remove whitespace, unfortunately
# Windows programs use \r but Unix programs use \n
echo Running native-built program natively
# find expected value natively
${getExecutable hostPkgs pkgFun exec} ${args'} \
| dos2unix > $out/expected
echo Running cross-built program in emulator
# run emulator to get actual value
${emulator} ${getExecutable crossPkgs pkgFun exec} ${args'} \
| dos2unix > $out/actual
echo Comparing results...
if [ "$(cat $out/actual)" != "$(cat $out/expected)" ]; then
echo "${pkgName} did not output expected value:"
cat $out/expected
echo "instead it output:"
cat $out/actual
exit 1
else
echo "${pkgName} test passed"
echo "both produced output:"
cat $out/actual
fi
'';
mapMultiPlatformTest =
crossSystemFun: test:
lib.dontRecurseIntoAttrs (
lib.mapAttrs (
name: system:
lib.recurseIntoAttrs (test rec {
crossPkgs = import pkgs.path {
localSystem = { inherit (pkgs.stdenv.hostPlatform) config; };
crossSystem = crossSystemFun system;
};
emulator = crossPkgs.stdenv.hostPlatform.emulator pkgs;
# Apply some transformation on windows to get dlls in the right
# place. Unfortunately mingw doesnt seem to be able to do linking
# properly.
platformFun =
pkg:
if crossPkgs.stdenv.hostPlatform.isWindows then
pkgs.buildEnv {
name = "${pkg.name}-winlinks";
paths = [ pkg ] ++ pkg.buildInputs;
}
else
pkg;
})
) testedSystems
);
tests = {
file =
{
platformFun,
crossPkgs,
emulator,
}:
compareTest {
inherit emulator crossPkgs;
hostPkgs = pkgs;
exec = "/bin/file";
args = [
"${pkgs.file}/share/man/man1/file.1.gz"
"${pkgs.dejavu_fonts}/share/fonts/truetype/DejaVuMathTeXGyre.ttf"
];
pkgFun = pkgs: platformFun pkgs.file;
};
hello =
{
platformFun,
crossPkgs,
emulator,
}:
compareTest {
inherit emulator crossPkgs;
hostPkgs = pkgs;
exec = "/bin/hello";
pkgFun = pkgs: pkgs.hello;
};
pkg-config =
{
platformFun,
crossPkgs,
emulator,
}:
crossPkgs.runCommand "test-pkg-config-${crossPkgs.stdenv.hostPlatform.config}"
{
depsBuildBuild = [ crossPkgs.pkgsBuildBuild.pkg-config ];
nativeBuildInputs = [
crossPkgs.pkgsBuildHost.pkg-config
crossPkgs.buildPackages.zlib
];
depsBuildTarget = [ crossPkgs.pkgsBuildTarget.pkg-config ];
buildInputs = [ crossPkgs.zlib ];
NIX_DEBUG = 7;
}
''
mkdir $out
${crossPkgs.pkgsBuildBuild.pkg-config.targetPrefix}pkg-config --cflags zlib > "$out/for-build"
${crossPkgs.pkgsBuildHost.pkg-config.targetPrefix}pkg-config --cflags zlib > "$out/for-host"
! diff "$out/for-build" "$out/for-host"
'';
};
# see https://github.com/NixOS/nixpkgs/issues/213453
# this is a good test of a lot of tricky glibc/libgcc corner cases
mbuffer =
let
mbuffer = pkgs.pkgsCross.aarch64-multiplatform.mbuffer;
emulator = with lib.systems; (elaborate examples.aarch64-multiplatform).emulator pkgs;
in
pkgs.runCommand "test-mbuffer" { } ''
echo hello | ${emulator} ${mbuffer}/bin/mbuffer
touch $out
'';
# This is meant to be a carefully curated list of builds/packages
# that tend to break when refactoring our cross-compilation
# infrastructure.
#
# It should strike a balance between being small enough to fit in
# a single eval (i.e. not so large that hydra-eval-jobs is needed)
# so we can ask @ofborg to check it, yet should have good examples
# of things that often break. So, no buckshot `mapTestOnCross`
# calls here.
sanity = [
mbuffer
#pkgs.pkgsCross.gnu64.bash # https://github.com/NixOS/nixpkgs/issues/243164
pkgs.gcc_multi.cc
pkgs.pkgsMusl.stdenv
pkgs.pkgsLLVM.stdenv
pkgs.pkgsStatic.bash
#pkgs.pkgsCross.gnu64_simplekernel.bash # https://github.com/NixOS/nixpkgs/issues/264989
pkgs.pkgsCross.arm-embedded.stdenv
pkgs.pkgsCross.sheevaplug.stdenv # for armv5tel
pkgs.pkgsCross.raspberryPi.stdenv # for armv6l
pkgs.pkgsCross.armv7l-hf-multiplatform.stdenv
pkgs.pkgsCross.m68k.stdenv
pkgs.pkgsCross.aarch64-multiplatform.pkgsBuildTarget.gcc
pkgs.pkgsCross.powernv.pkgsBuildTarget.gcc
pkgs.pkgsCross.s390.stdenv
pkgs.pkgsCross.mips64el-linux-gnuabi64.stdenv
pkgs.pkgsCross.mips64el-linux-gnuabin32.stdenv
pkgs.pkgsCross.mingwW64.stdenv
# Uses the expression that is used by the most cross-compiled GHCs
pkgs.pkgsCross.riscv64.haskell.compiler.native-bignum.ghc948
]
++ lib.optionals (with pkgs.stdenv.buildPlatform; isx86_64 && isLinux) [
# Musl-to-glibc cross on the same architecture tends to turn up
# lots of interesting corner cases. Only expected to work for
# x86_64-linux buildPlatform.
pkgs.pkgsMusl.pkgsCross.gnu64.hello
# Two web browsers -- exercises almost the entire packageset
pkgs.pkgsCross.aarch64-multiplatform.qutebrowser
pkgs.pkgsCross.aarch64-multiplatform.firefox
# Uses pkgsCross.riscv64-embedded; see https://github.com/NixOS/nixpkgs/issues/267859
pkgs.spike
];
in
{
gcc = lib.recurseIntoAttrs (
lib.mapAttrs (_: mapMultiPlatformTest (system: system // { useLLVM = false; })) tests
);
llvm = lib.recurseIntoAttrs (
lib.mapAttrs (_: mapMultiPlatformTest (system: system // { useLLVM = true; })) tests
);
inherit mbuffer sanity;
}

View File

@@ -0,0 +1,31 @@
{
lib,
recurseIntoAttrs,
cudaPackages,
cudaPackages_12_6,
cudaPackages_12_8,
cudaPackages_12_9,
cudaPackages_12,
}@args:
let
isTest =
name: package:
builtins.elem (package.pname or null) [
"cuda-library-samples"
"saxpy"
];
in
(lib.trivial.pipe args [
(lib.filterAttrs (name: _: lib.hasPrefix "cudaPackages" name))
(lib.mapAttrs (
_: ps:
lib.pipe ps [
(lib.filterAttrs isTest)
recurseIntoAttrs
]
))
recurseIntoAttrs
])

28
pkgs/test/cue/default.nix Normal file
View File

@@ -0,0 +1,28 @@
{
writeCueValidator,
runCommand,
writeText,
...
}:
let
validator = writeCueValidator (writeText "schema.cue" ''
#Def1: {
field1: string
}
'') { document = "#Def1"; };
in
runCommand "cue-validation" { } ''
cat > valid.json <<EOF
{ "field1": "abc" }
EOF
cat > invalid.json <<EOF
{ "field2": "abc" }
EOF
${validator} valid.json
if ${validator} invalid.json; then
echo "this example should fail"
exit 1
fi
touch $out
''

237
pkgs/test/default.nix Normal file
View File

@@ -0,0 +1,237 @@
{ pkgs, callPackage }:
with pkgs;
{
cc-wrapper =
with builtins;
let
pkgNames = (attrNames pkgs);
llvmTests =
let
pkgSets = lib.pipe pkgNames [
(filter (lib.hasPrefix "llvmPackages"))
# Are aliases.
(filter (n: n != "llvmPackages_latest"))
(filter (n: n != "llvmPackages_9"))
(filter (n: n != "llvmPackages_10"))
(filter (n: n != "llvmPackages_11"))
(filter (n: n != "llvmPackages_12"))
(filter (n: n != "llvmPackages_13"))
(filter (n: n != "llvmPackages_14"))
(filter (n: n != "llvmPackages_15"))
(filter (n: n != "llvmPackages_16"))
(filter (n: n != "llvmPackages_17"))
];
tests = lib.genAttrs pkgSets (
name:
recurseIntoAttrs {
clang = callPackage ./cc-wrapper { stdenv = pkgs.${name}.stdenv; };
libcxx = callPackage ./cc-wrapper { stdenv = pkgs.${name}.libcxxStdenv; };
}
);
in
tests;
gccTests =
let
pkgSets = lib.pipe (attrNames pkgs) (
[
(filter (lib.hasPrefix "gcc"))
(filter (lib.hasSuffix "Stdenv"))
(filter (n: n != "gccCrossLibcStdenv"))
(filter (n: n != "gcc49Stdenv"))
(filter (n: n != "gcc6Stdenv"))
(filter (n: n != "gcc7Stdenv"))
(filter (n: n != "gcc8Stdenv"))
(filter (n: n != "gcc9Stdenv"))
(filter (n: n != "gcc10Stdenv"))
(filter (n: n != "gcc11Stdenv"))
(filter (n: n != "gcc12Stdenv"))
]
++
lib.optionals
(
!(
(stdenv.buildPlatform.isLinux && stdenv.buildPlatform.isx86_64)
&& (stdenv.hostPlatform.isLinux && stdenv.hostPlatform.isx86_64)
)
)
[
(filter (n: !lib.hasSuffix "MultiStdenv" n))
]
);
in
lib.genAttrs pkgSets (name: callPackage ./cc-wrapper { stdenv = pkgs.${name}; });
in
recurseIntoAttrs {
default = callPackage ./cc-wrapper { };
supported = stdenv.mkDerivation {
name = "cc-wrapper-supported";
builtGCC =
let
inherit (lib) filterAttrs;
sets = lib.pipe gccTests [
(filterAttrs (_: v: lib.meta.availableOn stdenv.hostPlatform v.stdenv.cc))
# Broken
(filterAttrs (n: _: n != "gccMultiStdenv"))
];
in
toJSON sets;
builtLLVM =
let
inherit (lib) filterAttrs;
sets = lib.pipe llvmTests [
(filterAttrs (_: v: lib.meta.availableOn stdenv.hostPlatform v.clang.stdenv.cc))
(filterAttrs (_: v: lib.meta.availableOn stdenv.hostPlatform v.libcxx.stdenv.cc))
];
in
toJSON sets;
buildCommand = ''
touch $out
'';
};
llvmTests = recurseIntoAttrs llvmTests;
gccTests = recurseIntoAttrs gccTests;
};
devShellTools = callPackage ../build-support/dev-shell-tools/tests { };
stdenv-inputs = callPackage ./stdenv-inputs { };
stdenv = recurseIntoAttrs (callPackage ./stdenv { });
hardeningFlags = recurseIntoAttrs (callPackage ./cc-wrapper/hardening.nix { });
hardeningFlags-gcc = recurseIntoAttrs (
callPackage ./cc-wrapper/hardening.nix {
stdenv = gccStdenv;
}
);
hardeningFlags-clang = recurseIntoAttrs (
callPackage ./cc-wrapper/hardening.nix {
stdenv = llvmPackages.stdenv;
}
);
config = callPackage ./config.nix { };
top-level = callPackage ./top-level { };
haskell = callPackage ./haskell { };
hooks = recurseIntoAttrs (callPackage ./hooks { });
cc-multilib-gcc = callPackage ./cc-wrapper/multilib.nix { stdenv = gccMultiStdenv; };
cc-multilib-clang = callPackage ./cc-wrapper/multilib.nix { stdenv = clangMultiStdenv; };
compress-drv = callPackage ../build-support/compress-drv/test.nix { };
fetchurl = recurseIntoAttrs (callPackages ../build-support/fetchurl/tests.nix { });
fetchtorrent = recurseIntoAttrs (callPackages ../build-support/fetchtorrent/tests.nix { });
fetchpatch = recurseIntoAttrs (callPackages ../build-support/fetchpatch/tests.nix { });
fetchpatch2 = recurseIntoAttrs (
callPackages ../build-support/fetchpatch/tests.nix { fetchpatch = fetchpatch2; }
);
fetchDebianPatch = recurseIntoAttrs (callPackages ../build-support/fetchdebianpatch/tests.nix { });
fetchzip = recurseIntoAttrs (callPackages ../build-support/fetchzip/tests.nix { });
fetchgit = recurseIntoAttrs (callPackages ../build-support/fetchgit/tests.nix { });
fetchNextcloudApp = recurseIntoAttrs (
callPackages ../build-support/fetchnextcloudapp/tests.nix { }
);
fetchFromBitbucket = recurseIntoAttrs (callPackages ../build-support/fetchbitbucket/tests.nix { });
fetchFromGitHub = recurseIntoAttrs (callPackages ../build-support/fetchgithub/tests.nix { });
fetchFirefoxAddon = recurseIntoAttrs (
callPackages ../build-support/fetchfirefoxaddon/tests.nix { }
);
fetchPypiLegacy = recurseIntoAttrs (callPackages ../build-support/fetchpypilegacy/tests.nix { });
install-shell-files = recurseIntoAttrs (callPackage ./install-shell-files { });
checkpointBuildTools = callPackage ./checkpointBuild { };
kernel-config = callPackage ./kernel.nix { };
ld-library-path = callPackage ./ld-library-path { };
cross = recurseIntoAttrs (callPackage ./cross { });
php = recurseIntoAttrs (callPackages ./php { });
go = recurseIntoAttrs (callPackage ../build-support/go/tests.nix { });
pkg-config = recurseIntoAttrs (callPackage ../top-level/pkg-config/tests.nix { });
buildRustCrate = recurseIntoAttrs (callPackage ../build-support/rust/build-rust-crate/test { });
importCargoLock = recurseIntoAttrs (callPackage ../build-support/rust/test/import-cargo-lock { });
vim = callPackage ./vim { };
nixos-functions = callPackage ./nixos-functions { };
nixosOptionsDoc = recurseIntoAttrs (callPackage ../../nixos/lib/make-options-doc/tests.nix { });
overriding = callPackage ./overriding.nix { };
texlive = recurseIntoAttrs (callPackage ./texlive { });
cuda = callPackage ./cuda { };
trivial-builders = callPackage ../build-support/trivial-builders/test/default.nix { };
writers = callPackage ../build-support/writers/test.nix { };
testers = callPackage ../build-support/testers/test/default.nix { };
dhall = callPackage ./dhall { };
cue-validation = callPackage ./cue { };
coq = callPackage ./coq { };
dotnet = recurseIntoAttrs (callPackages ./dotnet { });
makeHardcodeGsettingsPatch = recurseIntoAttrs (callPackage ./make-hardcode-gsettings-patch { });
makeWrapper = callPackage ./make-wrapper { };
makeBinaryWrapper = callPackage ./make-binary-wrapper {
makeBinaryWrapper = pkgs.makeBinaryWrapper.override {
# Enable sanitizers in the tests only, to avoid the performance cost in regular usage.
# The sanitizers cause errors on aarch64-darwin, see https://github.com/NixOS/nixpkgs/pull/150079#issuecomment-994132734
sanitizers =
pkgs.lib.optionals (!(pkgs.stdenv.hostPlatform.isDarwin && pkgs.stdenv.hostPlatform.isAarch64))
[
"undefined"
"address"
];
};
};
pkgs-lib = recurseIntoAttrs (import ../pkgs-lib/tests { inherit pkgs; });
buildFHSEnv = recurseIntoAttrs (callPackages ./buildFHSEnv { });
auto-patchelf-hook = callPackage ./auto-patchelf-hook { };
# Accumulate all passthru.tests from arrayUtilities into a single attribute set.
arrayUtilities = recurseIntoAttrs (
lib.concatMapAttrs (
name: value:
lib.optionalAttrs (value ? passthru.tests) {
${name} = value.passthru.tests;
}
) arrayUtilities
);
srcOnly = callPackage ../build-support/src-only/tests.nix { };
systemd = callPackage ./systemd { };
replaceVars = recurseIntoAttrs (callPackage ./replace-vars { });
substitute = recurseIntoAttrs (callPackage ./substitute { });
build-environment-info = callPackage ./build-environment-info { };
rust-hooks = recurseIntoAttrs (callPackages ../build-support/rust/hooks/test { });
}

View File

@@ -0,0 +1,14 @@
{ dhallPackages }:
# This file tests that dhallPackages.buildDhallUrl is able to successfully
# build a Nix Dhall package for a given remote Dhall import.
#
# TODO: It would be nice to extend this test to make sure that the resulting
# Nix Dhall package is has the expected contents.
dhallPackages.buildDhallUrl {
url = "https://raw.githubusercontent.com/cdepillabout/example-dhall-nix/e6a675c72ecd4dd23d254a02aea8181fe875747f/mydhallfile.dhall";
hash = "sha256-434x+QjHRzuprBdw0h6wmwB1Zj6yZqQb533me8XdO4c=";
dhallHash = "sha256-434x+QjHRzuprBdw0h6wmwB1Zj6yZqQb533me8XdO4c=";
source = true;
}

View File

@@ -0,0 +1,6 @@
{ lib, callPackage }:
lib.recurseIntoAttrs {
buildDhallUrl = callPackage ./buildDhallUrl { };
generateDhallDirectoryPackage = callPackage ./generateDhallDirectoryPackage { };
}

View File

@@ -0,0 +1,17 @@
{ dhallPackages, fetchFromGitHub }:
# This file tests that dhallPackages.generateDhallDirectoryPackage works.
#
# TODO: It would be nice to extend this test to make sure that the resulting
# Nix file has the expected contents, but it might be tough to do that easily
# without IFD.
dhallPackages.generateDhallDirectoryPackage {
src = fetchFromGitHub {
owner = "cdepillabout";
repo = "example-dhall-nix";
rev = "e6a675c72ecd4dd23d254a02aea8181fe875747f";
sha256 = "sha256-c/EZq76s/+hmLkaeJWKqgh2KrHuJRYI6kWry0E0YQ6s=";
};
file = "mydhallfile.dhall";
}

View File

@@ -0,0 +1,9 @@
{ lib, callPackage }:
{
project-references = callPackage ./project-references { };
use-dotnet-from-env = lib.recurseIntoAttrs (callPackage ./use-dotnet-from-env { });
structured-attrs = lib.recurseIntoAttrs (callPackage ./structured-attrs { });
final-attrs = lib.recurseIntoAttrs (callPackage ./final-attrs { });
nuget-deps = lib.recurseIntoAttrs (callPackage ./nuget-deps { });
}

View File

@@ -0,0 +1,76 @@
{
lib,
dotnet-sdk,
buildPackages, # buildDotnetModule
testers,
runCommand,
}:
let
copyrightString = "Original Copyright";
originalCopyright = builtins.toFile "original-copyright.txt" copyrightString;
overridenCopyright = builtins.toFile "overridden-copyright.txt" (
copyrightString + " with override!"
);
inherit (buildPackages) buildDotnetModule;
app-recursive = buildDotnetModule (finalAttrs: {
name = "final-attrs-rec-test-application";
src = ../structured-attrs/src;
nugetDeps = ../structured-attrs/nuget-deps.json;
dotnetFlags = [ "--property:Copyright=${finalAttrs.passthru.copyrightString}" ];
env.TargetFramework = "net${lib.versions.majorMinor (lib.getVersion dotnet-sdk)}";
__structuredAttrs = true;
passthru = {
inherit copyrightString;
};
});
app-const = buildDotnetModule {
name = "final-attrs-const-test-application";
src = ../structured-attrs/src;
nugetDeps = ../structured-attrs/nuget-deps.json;
dotnetFlags = [ "--property:Copyright=${copyrightString}" ];
env.TargetFramework = "net${lib.versions.majorMinor (lib.getVersion dotnet-sdk)}";
__structuredAttrs = true;
passthru = {
inherit copyrightString;
};
};
override =
app:
app.overrideAttrs (previousAttrs: {
passthru = previousAttrs.passthru // {
copyrightString = previousAttrs.passthru.copyrightString + " with override!";
};
});
run =
name: app:
runCommand name { } ''
${app}/bin/Application >"$out"
'';
in
{
check-output = testers.testEqualContents {
assertion = "buildDotnetModule produces the expected output when called with a recursive function";
expected = originalCopyright;
actual = run "dotnet-final-attrs-test-rec-output" app-recursive;
};
output-matches-const = testers.testEqualContents {
assertion = "buildDotnetModule produces the same output when called with attrs or a recursive function";
expected = run "dotnet-final-attrs-test-const" app-const;
actual = run "dotnet-final-attrs-test-rec" app-recursive;
};
override-has-no-effect = testers.testEqualContents {
assertion = "buildDotnetModule produces the expected output when called with a recursive function";
expected = originalCopyright;
actual = run "dotnet-final-attrs-test-override-const-output" (override app-const);
};
override-modifies-output = testers.testEqualContents {
assertion = "buildDotnetModule produces the expected output when called with a recursive function";
expected = overridenCopyright;
actual = run "dotnet-final-attrs-test-override-rec-output" (override app-recursive);
};
}

View File

@@ -0,0 +1,45 @@
# Tests that `nugetDeps` in buildDotnetModule can handle various types.
{
lib,
dotnet-sdk,
buildPackages, # buildDotnetModule
runCommand,
}:
let
inherit (lib)
mapAttrs
;
inherit (buildPackages)
emptyDirectory
buildDotnetModule
;
in
mapAttrs
(
name: nugetDeps:
buildDotnetModule {
name = "nuget-deps-${name}";
unpackPhase = ''
runHook preUnpack
mkdir test
cd test
dotnet new console -o .
ls -l
runHook postUnpack
'';
inherit nugetDeps;
}
)
{
"null" = null;
"nix-file" = ./nuget-deps.nix;
"json-file" = ./nuget-deps.json;
"derivation" = emptyDirectory;
"list" = [ emptyDirectory ];
}

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,6 @@
# This file was automatically generated by passthru.fetch-deps.
# Please dont edit it manually, your changes might get overwritten!
{ fetchNuGet }:
[
]

View File

@@ -0,0 +1 @@
ProjectReferencesTest.Library.Hello();

View File

@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>exe</OutputType>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../library/Library.csproj" />
<PackageReference Include="ProjectReferencesTest.Library" Version="*" Condition=" '$(ContinuousIntegrationBuild)'=='true' " />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,43 @@
# Tests the `projectReferences = [ ... ];` feature of buildDotnetModule.
# The `library` derivation exposes a .nupkg, which is then consumed by the `application` derivation.
# https://nixos.org/manual/nixpkgs/unstable/index.html#packaging-a-dotnet-application
{
lib,
dotnet-sdk,
buildPackages, # buildDotnetModule
runCommand,
}:
let
inherit (buildPackages) buildDotnetModule;
nugetDeps = ./nuget-deps.json;
# Specify the TargetFramework via an environment variable so that we don't
# have to update the .csproj files when updating dotnet-sdk
TargetFramework = "net${lib.versions.majorMinor (lib.getVersion dotnet-sdk)}";
library = buildDotnetModule {
name = "project-references-test-library";
src = ./library;
inherit nugetDeps;
env.TargetFramework = TargetFramework;
packNupkg = true;
};
application = buildDotnetModule {
name = "project-references-test-application";
src = ./application;
inherit nugetDeps;
env.TargetFramework = TargetFramework;
projectReferences = [ library ];
};
in
runCommand "project-references-test" { } ''
${application}/bin/Application
mkdir $out
''

View File

@@ -0,0 +1,8 @@
namespace ProjectReferencesTest;
public static class Library
{
public static void Hello()
{
System.Console.WriteLine("Hello, World!");
}
}

View File

@@ -0,0 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageId>ProjectReferencesTest.Library</PackageId>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,39 @@
{
lib,
dotnet-sdk,
buildPackages, # buildDotnetModule
testers,
runCommand,
}:
let
# Note: without structured attributes, we cant use derivation arguments that
# contain spaces unambiguously because arguments are passed as space-separated
# environment variables.
copyrightString = "Public domain 🅮";
inherit (buildPackages) buildDotnetModule;
app = buildDotnetModule {
name = "structured-attrs-test-application";
src = ./src;
nugetDeps = ./nuget-deps.json;
dotnetFlags = [ "--property:Copyright=${copyrightString}" ];
env.TargetFramework = "net${lib.versions.majorMinor (lib.getVersion dotnet-sdk)}";
__structuredAttrs = true;
};
in
{
no-structured-attrs = testers.testBuildFailure (
app.overrideAttrs {
__structuredAttrs = false;
}
);
check-output = testers.testEqualContents {
assertion = "buildDotnetModule sets AssemblyCopyrightAttribute with structured attributes";
expected = builtins.toFile "expected-copyright.txt" copyrightString;
actual = runCommand "dotnet-structured-attrs-test" { } ''
${app}/bin/Application >"$out"
'';
};
}

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,10 @@
using System;
using System.Reflection;
Console.Write(
(
(AssemblyCopyrightAttribute)Assembly
.GetExecutingAssembly()
.GetCustomAttributes(typeof(AssemblyCopyrightAttribute), true)[0]
).Copyright
);

View File

@@ -0,0 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>exe</OutputType>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,65 @@
{
lib,
dotnet-sdk,
buildPackages, # buildDotnetModule, dotnet-runtime
testers,
runCommand,
removeReferencesTo,
}:
let
inherit (buildPackages) buildDotnetModule dotnet-runtime;
app = buildDotnetModule {
name = "use-dotnet-from-env-test-application";
src = ./src;
nugetDeps = ./nuget-deps.json;
useDotnetFromEnv = true;
env.TargetFramework = "net${lib.versions.majorMinor (lib.getVersion dotnet-sdk)}";
};
appWithoutFallback = app.overrideAttrs (oldAttrs: {
nativeBuildInputs = (oldAttrs.nativeBuildInputs or [ ]) ++ [
removeReferencesTo
];
postFixup = (oldAttrs.postFixup or "") + ''
remove-references-to -t ${dotnet-runtime} "$out/bin/Application"
'';
});
runtimeVersion = lib.head (lib.splitString "-" (lib.getVersion dotnet-runtime));
runtimeVersionFile = builtins.toFile "dotnet-version.txt" runtimeVersion;
in
{
fallback = testers.testEqualContents {
assertion = "buildDotnetModule sets fallback DOTNET_ROOT in wrapper";
expected = runtimeVersionFile;
actual = runCommand "use-dotnet-from-env-fallback-test" { } ''
${app}/bin/Application >"$out"
'';
};
# Check that appWithoutFallback does not use fallback .NET runtime.
without-fallback = testers.testBuildFailure (
runCommand "use-dotnet-from-env-without-fallback-test" { } ''
${appWithoutFallback}/bin/Application >"$out"
''
);
# NB assumes that without-fallback above to passes.
use-dotnet-root-env = testers.testEqualContents {
assertion = "buildDotnetModule uses DOTNET_ROOT from environment in wrapper";
expected = runtimeVersionFile;
actual =
runCommand "use-dotnet-from-env-root-test" { env.DOTNET_ROOT = "${dotnet-runtime}/share/dotnet"; }
''
${appWithoutFallback}/bin/Application >"$out"
'';
};
use-dotnet-path-env = testers.testEqualContents {
assertion = "buildDotnetModule uses DOTNET_ROOT from dotnet in PATH in wrapper";
expected = runtimeVersionFile;
actual = runCommand "use-dotnet-from-env-path-test" { dotnetRuntime = dotnet-runtime; } ''
PATH=$dotnetRuntime/bin''${PATH+:}$PATH ${appWithoutFallback}/bin/Application >"$out"
'';
};
}

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,3 @@
using System;
Console.Write(Environment.Version.ToString());

View File

@@ -0,0 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>exe</OutputType>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,43 @@
{
lib,
haskell,
haskellPackages,
runCommand,
}:
let
localRaw = haskellPackages.callPackage ./generated.nix { };
in
lib.recurseIntoAttrs rec {
helloFromCabalSdist = haskellPackages.buildFromCabalSdist haskellPackages.hello;
# A more complicated example with a cabal hook.
hercules-ci-cnix-store = haskellPackages.buildFromCabalSdist haskellPackages.hercules-ci-cnix-store;
localFromCabalSdist = haskellPackages.buildFromCabalSdist localRaw;
# This test makes sure that localHasNoDirectReference can actually fail if
# it doesn't do anything. If this test fails, either the test setup was broken,
# or Haskell packaging has changed the way `src` is treated in such a way that
# either the test or the design of `buildFromCabalSdist` needs to be reconsidered.
assumptionLocalHasDirectReference =
runCommand "localHasDirectReference"
{
drvPath = builtins.unsafeDiscardOutputDependency localRaw.drvPath;
}
''
grep ${localRaw.src} $drvPath >/dev/null
touch $out
'';
localHasNoDirectReference =
runCommand "localHasNoDirectReference"
{
drvPath = builtins.unsafeDiscardOutputDependency localFromCabalSdist.drvPath;
}
''
grep -v ${localRaw.src} $drvPath >/dev/null
touch $out
'';
}

View File

@@ -0,0 +1,17 @@
# nix run ../../../../..#cabal2nix -- ./local
{
mkDerivation,
base,
lib,
}:
mkDerivation {
pname = "local";
version = "0.1.0.0";
src = ./local;
isLibrary = false;
isExecutable = true;
executableHaskellDepends = [ base ];
description = "Nixpkgs test case";
license = lib.licenses.mit;
mainProgram = "local";
}

View File

@@ -0,0 +1,5 @@
# Revision history for local
## 0.1.0.0 -- YYYY-mm-dd
* First version. Released on an unsuspecting world.

View File

@@ -0,0 +1,4 @@
module Main where
main :: IO ()
main = putStrLn "Hello, Haskell!"

View File

@@ -0,0 +1,13 @@
cabal-version: 2.4
name: local
version: 0.1.0.0
synopsis: Nixpkgs test case
license: MIT
extra-source-files: CHANGELOG.md
executable local
main-is: Main.hs
build-depends: base
hs-source-dirs: app
default-language: Haskell2010

View File

@@ -0,0 +1,12 @@
{ lib, callPackage }:
lib.recurseIntoAttrs {
cabalSdist = callPackage ./cabalSdist { };
documentationTarball = callPackage ./documentationTarball { };
env = callPackage ./env { };
ghcWithPackages = callPackage ./ghcWithPackages { };
incremental = callPackage ./incremental { };
setBuildTarget = callPackage ./setBuildTarget { };
shellFor = callPackage ./shellFor { };
upstreamStackHpackVersion = callPackage ./upstreamStackHpackVersion { };
}

View File

@@ -0,0 +1,24 @@
{ pkgs, haskellPackages }:
let
drv = haskellPackages.random;
docs = pkgs.haskell.lib.compose.documentationTarball drv;
in
pkgs.runCommand "test haskell.lib.compose.documentationTarball"
{
meta = {
inherit (docs.meta) platforms;
};
}
''
tar xvzf "${docs}/${drv.name}-docs.tar.gz"
# Check for Haddock html
find "${drv.name}-docs" | grep -q "System-Random.html"
# Check for source html
find "${drv.name}-docs" | grep -q "src/System.Random.html"
touch "$out"
''

55
pkgs/test/haskell/env/default.nix vendored Normal file
View File

@@ -0,0 +1,55 @@
{
lib,
haskellPackages,
}:
let
withEnv =
env:
haskellPackages.mkDerivation {
pname = "puppy";
version = "1.0.0";
src = null;
license = null;
inherit env;
};
failures = lib.runTests {
testCanSetEnv = {
expr =
(withEnv {
PUPPY = "DOGGY";
}).drvAttrs.PUPPY;
expected = "DOGGY";
};
testCanSetEnvMultiple = {
expr =
let
env =
(withEnv {
PUPPY = "DOGGY";
SILLY = "GOOFY";
}).drvAttrs;
in
{
inherit (env) PUPPY SILLY;
};
expected = {
PUPPY = "DOGGY";
SILLY = "GOOFY";
};
};
testCanSetEnvPassthru = {
expr =
(withEnv {
PUPPY = "DOGGY";
}).passthru.env.PUPPY;
expected = "DOGGY";
};
};
in
# TODO: Use `lib.debug.throwTestFailures`: https://github.com/NixOS/nixpkgs/pull/416207
lib.optional (failures != [ ]) (throw "${lib.generators.toPretty { } failures}")

View File

@@ -0,0 +1,69 @@
{
lib,
runCommand,
runCommandCC,
haskellPackages,
}:
lib.recurseIntoAttrs {
# This is special-cased to return just `ghc`.
trivial = haskellPackages.ghcWithPackages (hsPkgs: [ ]);
# Here we actually build a trivial package.
hello = haskellPackages.ghcWithPackages (hsPkgs: [
hsPkgs.hello
]);
# Here we build a database with multiple packages.
multiple = haskellPackages.ghcWithPackages (hsPkgs: [
hsPkgs.hspec
hsPkgs.unordered-containers
]);
# See: https://github.com/NixOS/nixpkgs/pull/224542
regression-224542 =
let
ghc = haskellPackages.ghcWithPackages (hsPkgs: [
hsPkgs.hspec
]);
in
runCommand "regression-224542"
{
nativeBuildInputs = [
ghc
];
}
''
${ghc.targetPrefix}ghc --interactive \
-Werror=unrecognised-warning-flags \
-Werror=missed-extra-shared-lib \
2>&1 \
| tee ghc-output.txt
# If GHC failed to find a shared library, linking dylibs in
# `ghcWithPackages` didn't work correctly.
if grep --quiet "error: .*-Wmissed-extra-shared-lib" ghc-output.txt \
&& grep --quiet "no such file" ghc-output.txt; then
exit 1
fi
touch $out
'';
use-llvm =
let
ghc = (haskellPackages.ghcWithPackages.override { useLLVM = true; }) (_: [ ]);
in
runCommandCC "ghc-with-packages-use-llvm"
{
nativeBuildInputs = [ ghc ];
}
''
echo 'main = pure ()' > test.hs
# -ddump-llvm is unnecessary, but nice for visual feedback in the build log
${ghc.targetPrefix}ghc --make -fllvm -keep-llvm-files -ddump-llvm test.hs
# Did we actually use the LLVM backend?
test -f test.ll
touch $out
'';
}

View File

@@ -0,0 +1,39 @@
# Demonstration of incremental builds for Haskell. Useful for speeding up CI.
#
# See: https://www.haskellforall.com/2022/12/nixpkgs-support-for-incremental-haskell.html
# See: https://felixspringer.xyz/homepage/blog/incrementalHaskellBuildsWithNix
{
haskell,
haskellPackages,
lib,
}:
let
inherit (haskell.lib.compose) overrideCabal;
# Incremental builds work with GHC >=9.4.
temporary = haskellPackages.temporary;
# This will do a full build of `temporary`, while writing the intermediate build products
# (compiled modules, etc.) to the `intermediates` output.
temporary-full-build-with-incremental-output = overrideCabal (drv: {
doInstallIntermediates = true;
enableSeparateIntermediatesOutput = true;
}) temporary;
# This will do an incremental build of `temporary` by copying the previously
# compiled modules and intermediate build products into the source tree
# before running the build.
#
# GHC will then naturally pick up and reuse these products, making this build
# complete much more quickly than the previous one.
temporary-incremental-build = overrideCabal (drv: {
previousIntermediates = temporary-full-build-with-incremental-output.intermediates;
}) temporary;
in
temporary-incremental-build.overrideAttrs (old: {
meta = {
teams = [ lib.teams.mercury ];
};
})

View File

@@ -0,0 +1,51 @@
{ pkgs, haskellPackages }:
let
# This can be regenerated by running `cabal2nix ./src` in the current directory.
pkgDef =
{
mkDerivation,
base,
lib,
}:
mkDerivation {
pname = "haskell-setBuildTarget";
version = "0.1.0.0";
src = ./src;
isLibrary = false;
isExecutable = true;
executableHaskellDepends = [ base ];
license = pkgs.lib.licenses.mit;
};
drv = haskellPackages.callPackage pkgDef { };
test =
target: excluded:
let
only = pkgs.haskell.lib.compose.setBuildTarget target drv;
in
''
if [[ ! -f "${only}/bin/${target}" ]]; then
echo "${target} was not built"
exit 1
fi
if [[ -f "${only}/bin/${excluded}" ]]; then
echo "${excluded} was built, when it should not have been"
exit 1
fi
'';
in
pkgs.runCommand "test haskell.lib.compose.setBuildTarget"
{
meta = {
inherit (drv.meta) platforms;
};
}
''
${test "foo" "bar"}
${test "bar" "foo"}
touch "$out"
''

View File

@@ -0,0 +1,4 @@
module Main where
main :: IO ()
main = putStrLn "Hello, Bar!"

View File

@@ -0,0 +1,4 @@
module Main where
main :: IO ()
main = putStrLn "Hello, Foo!"

View File

@@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain

View File

@@ -0,0 +1,16 @@
cabal-version: >=1.10
name: haskell-setBuildTarget
version: 0.1.0.0
author: Isaac Shapira
maintainer: fresheyeball@protonmail.com
build-type: Simple
executable foo
main-is: Foo.hs
build-depends: base
default-language: Haskell2010
executable bar
main-is: Bar.hs
build-depends: base
default-language: Haskell2010

View File

@@ -0,0 +1,71 @@
{
lib,
writeText,
srcOnly,
haskellPackages,
cabal-install,
}:
(haskellPackages.shellFor {
packages = p: [
p.constraints
p.cereal
];
# WARNING: When updating this, make sure that the libraries passed to
# `extraDependencies` are not actually transitive dependencies of libraries in
# `packages` above. We explicitly want to test that it is possible to specify
# `extraDependencies` that are not in the closure of `packages`.
extraDependencies = p: { libraryHaskellDepends = [ p.conduit ]; };
nativeBuildInputs = [ cabal-install ];
unpackPhase = ''
sourceRoot=$(pwd)/scratch
mkdir -p "$sourceRoot"
cd "$sourceRoot"
cp -r "${srcOnly haskellPackages.constraints}" constraints
cp -r "${srcOnly haskellPackages.cereal}" cereal
cp ${writeText "cabal.project" "packages: constraints cereal"} cabal.project
'';
buildPhase = ''
export HOME=$(mktemp -d)
mkdir -p $HOME/.cabal
touch $HOME/.cabal/config
# Check that the extraDependencies.libraryHaskellDepends arg is correctly
# picked up. This uses ghci to interpret a small Haskell program that uses
# a package from extraDependencies.
ghci <<EOF
:set -XOverloadedStrings
:m + Conduit
runResourceT $ connect (yield "done") (sinkFile "outfile")
EOF
if [[ "done" != "$(cat outfile)" ]]; then
echo "ERROR: extraDependencies appear not to be available in the environment"
exit 1
fi
# Check packages arg
cabal v2-build --offline --verbose constraints cereal --ghc-options="-O0 -j$NIX_BUILD_CORES"
'';
installPhase = ''
touch $out
'';
}).overrideAttrs
(oldAttrs: {
meta =
let
oldMeta = oldAttrs.meta or { };
oldMaintainers = oldMeta.maintainers or [ ];
additionalMaintainers = with lib.maintainers; [ cdepillabout ];
allMaintainers = oldMaintainers ++ additionalMaintainers;
in
oldMeta
// {
maintainers = allMaintainers;
inherit (cabal-install.meta) platforms;
};
# `shellFor` adds a `buildCommand` (via `envFunc -> runCommandCC`), which
# overrides custom phases. To ensure this test's phases run, we remove
# that `buildCommand` from the derivation.
buildCommand = null;
})

View File

@@ -0,0 +1,158 @@
# This derivation confirms that the version of hpack used by stack in Nixpkgs
# is the exact same version as the upstream stack release.
#
# It is important to make sure the version of hpack used by stack in Nixpkgs
# matches with the version of hpack used by the upstream stack release. This
# is because hpack works slightly differently based on the version, and it can
# be frustrating to use hpack in a team setting when members are using different
# versions. See for more info: https://github.com/NixOS/nixpkgs/issues/223390
#
# This test is written as a fixed-output derivation, because we need to access
# accesses the internet to download the upstream stack release.
{
cacert,
curl,
lib,
stack,
stdenv,
}:
let
# Find the hpack derivation that is a dependency of stack. Throw exception
# if hpack cannot be found.
hpack =
lib.findFirst (v: v.pname or "" == "hpack") (throw "could not find stack's hpack dependency")
stack.passthru.getCabalDeps.executableHaskellDepends;
# This is a statically linked version of stack, so it should be usable within
# the Nixpkgs builder (at least on x86_64-linux).
stackDownloadUrl = "https://github.com/commercialhaskell/stack/releases/download/v${stack.version}/stack-${stack.version}-linux-x86_64.tar.gz";
# This test code has been explicitly pulled out of the derivation below so
# that it can be hashed and added to the `name` of the derivation. This is
# so that this test derivation won't be cached if the body of the test is
# modified.
#
# WARNING: When modifying this script, make sure you don't introduce any
# paths to the Nix store within it. We only want this derivation to be re-run
# when the stack version (or the version of its hpack dependency) changes in
# Nixpkgs.
testScript = ''
curl=(
curl
--location
--max-redirs 20
--retry 3
--disable-epsv
--cookie-jar cookies
--user-agent "nixpkgs stack version test/1.0"
--insecure
)
# Fetch the statically-linked upstream Stack binary.
echo "Trying to download a statically linked stack binary from ${stackDownloadUrl} to ./stack.tar.gz ..."
"''${curl[@]}" "${stackDownloadUrl}" > ./stack.tar.gz
tar xf ./stack.tar.gz
upstream_stack_version_output="$(./stack-${stack.version}-linux-x86_64/stack --version)"
echo "upstream \`stack --version\` output: $upstream_stack_version_output"
nixpkgs_stack_version_output="$(stack --version)"
echo "nixpkgs \`stack --version\` output: $nixpkgs_stack_version_output"
# Confirm that the upstream stack version is the same as the stack version
# in Nixpkgs. This check isn't strictly necessary, but it is a good sanity
# check.
if [[ "$upstream_stack_version_output" =~ "Version "([0-9]+((\.[0-9]+)+)) ]]; then
upstream_stack_version="''${BASH_REMATCH[1]}"
echo "parsed upstream stack version: $upstream_stack_version"
echo "stack version from nixpkgs: ${stack.version}"
if [[ "${stack.version}" != "$upstream_stack_version" ]]; then
echo "ERROR: stack version in Nixpkgs (${stack.version}) does not match the upstream version for some reason: $upstream_stack_version"
exit 1
fi
else
echo "ERROR: Upstream stack version cannot be found in --version output: $upstream_stack_version"
exit 1
fi
# Confirm that the hpack version used in the upstream stack release is the
# same as the hpack version used by the Nixpkgs stack binary.
if [[ "$upstream_stack_version_output" =~ hpack-([0-9]+((\.[0-9]+)+)) ]]; then
upstream_hpack_version="''${BASH_REMATCH[1]}"
echo "parsed upstream stack's hpack version: $upstream_hpack_version"
echo "Nixpkgs stack's hpack version: ${hpack.version}"
if [[ "${hpack.version}" != "$upstream_hpack_version" ]]; then
echo "ERROR: stack's hpack version in Nixpkgs (${hpack.version}) does not match the upstream stack's hpack version: $upstream_hpack_version"
echo "The stack derivation in Nixpkgs needs to be fixed up so that it depends on hpack-$upstream_hpack_version, instead of ${hpack.name}"
exit 1
fi
else
echo "ERROR: Upstream stack's hpack version cannot be found in --version output: $upstream_hpack_version"
exit 1
fi
# Output a string with a known hash.
echo "success" > $out
'';
testScriptHash = builtins.hashString "sha256" testScript;
in
stdenv.mkDerivation {
# This name is very important.
#
# The idea here is that want this derivation to be re-run everytime the
# version of stack (or the version of its hpack dependency) changes in
# Nixpkgs. We also want to re-run this derivation whenever the test script
# is changed.
#
# Nix/Hydra will re-run derivations if their name changes (even if they are a
# FOD and they have the same hash).
#
# The name of this derivation contains the stack version string, the hpack
# version string, and a hash of the test script. So Nix will know to
# re-run this version when (and only when) one of those values change.
name = "upstream-stack-hpack-version-test-${stack.name}-${hpack.name}-${testScriptHash}";
# This is the sha256 hash for the string "success", which is output upon this
# test succeeding.
outputHash = "sha256-gbK9TqmMjbZlVPvI12N6GmmhMPMx/rcyt1yqtMSGj9U=";
outputHashMode = "flat";
outputHashAlgo = "sha256";
nativeBuildInputs = [
curl
stack
];
impureEnvVars = lib.fetchers.proxyImpureEnvVars;
buildCommand = ''
# Make sure curl can access HTTPS sites, like GitHub.
#
# Note that we absolutely don't want the Nix store path of the cacert
# derivation in the testScript, because we don't want to rebuild this
# derivation when only the cacert derivation changes.
export SSL_CERT_FILE="${cacert}/etc/ssl/certs/ca-bundle.crt"
''
+ testScript;
meta = with lib; {
description = "Test that the stack in Nixpkgs uses the same version of Hpack as the upstream stack release";
maintainers = with maintainers; [ cdepillabout ];
# This derivation internally runs a statically-linked version of stack from
# upstream. This statically-linked version of stack is only available for
# x86_64-linux, so this test can only be run on x86_64-linux.
platforms = [ "x86_64-linux" ];
};
}

View File

@@ -0,0 +1,12 @@
# To run these tests:
# nix-build -A tests.hooks
{
stdenv,
tests,
lib,
}:
{
default-stdenv-hooks = lib.recurseIntoAttrs tests.stdenv.hooks;
}

View File

@@ -0,0 +1,3 @@
{ installShellFiles }:
installShellFiles.tests

78
pkgs/test/kernel.nix Normal file
View File

@@ -0,0 +1,78 @@
# make sure to use NON EXISTING kernel settings else they may conflict with
# common-config.nix
{ lib, pkgs }:
let
lts_kernel = pkgs.linuxPackages.kernel;
# to see the result once the module transformed the lose structured config
getConfig =
structuredConfig:
(lts_kernel.override {
structuredExtraConfig = structuredConfig;
}).configfile.structuredConfig;
mandatoryVsOptionalConfig = lib.mkMerge [
{ NIXOS_FAKE_USB_DEBUG = lib.kernel.yes; }
{ NIXOS_FAKE_USB_DEBUG = lib.kernel.option lib.kernel.yes; }
];
freeformConfig = lib.mkMerge [
{ NIXOS_FAKE_MMC_BLOCK_MINORS = lib.kernel.freeform "32"; } # same as default, won't trigger any error
{ NIXOS_FAKE_MMC_BLOCK_MINORS = lib.kernel.freeform "64"; } # will trigger an error but the message is not great:
];
mkDefaultWorksConfig = lib.mkMerge [
{ "NIXOS_TEST_BOOLEAN" = lib.kernel.yes; }
{ "NIXOS_TEST_BOOLEAN" = lib.mkDefault lib.kernel.no; }
];
allOptionalRemainOptional = lib.mkMerge [
{ NIXOS_FAKE_USB_DEBUG = lib.kernel.option lib.kernel.yes; }
{ NIXOS_FAKE_USB_DEBUG = lib.kernel.option lib.kernel.yes; }
];
failures = lib.runTests {
testEasy = {
expr = (getConfig { NIXOS_FAKE_USB_DEBUG = lib.kernel.yes; }).NIXOS_FAKE_USB_DEBUG;
expected = {
tristate = "y";
optional = false;
freeform = null;
};
};
# mandatory flag should win over optional
testMandatoryCheck = {
expr = (getConfig mandatoryVsOptionalConfig).NIXOS_FAKE_USB_DEBUG.optional;
expected = false;
};
testYesWinsOverNo = {
expr = (getConfig mkDefaultWorksConfig)."NIXOS_TEST_BOOLEAN".tristate;
expected = "y";
};
testAllOptionalRemainOptional = {
expr = (getConfig allOptionalRemainOptional)."NIXOS_FAKE_USB_DEBUG".optional;
expected = true;
};
# check that freeform options are unique
# Should trigger
# > The option `settings.NIXOS_FAKE_MMC_BLOCK_MINORS.freeform' has conflicting definitions, in `<unknown-file>' and `<unknown-file>'
testTreeform =
let
res = builtins.tryEval ((getConfig freeformConfig).NIXOS_FAKE_MMC_BLOCK_MINORS.freeform);
in
{
expr = res.success;
expected = false;
};
};
in
lib.optional (failures != [ ]) (
throw "The following kernel unit tests failed: ${lib.generators.toPretty { } failures}"
)

View File

@@ -0,0 +1,89 @@
{ lib, stdenv }:
# This tests that libraries listed in LD_LIBRARY_PATH take precedence over those listed in RPATH.
let
# A simple test library: libgreeting.so which exports a single function getGreeting() returning the good old hello greeting.
libgreeting = stdenv.mkDerivation {
name = "libgreeting";
code = ''
const char* getGreeting() { return "Hello, world!"; }
'';
unpackPhase = ''
echo "$code" > libgreeting.c
'';
installPhase = ''
mkdir -p $out/lib
$CC -c -fpic libgreeting.c
$CC -shared libgreeting.o -o $out/lib/libgreeting.so
'';
};
# A variant of libgreeting.so that returns a different message.
libgoodbye = libgreeting.overrideAttrs (_: {
name = "libgoodbye";
code = ''
const char* getGreeting() { return "Goodbye, world!"; }
'';
});
# A simple consumer of libgreeting.so that just prints the greeting to stdout.
testProgram = stdenv.mkDerivation {
name = "greeting-test";
buildInputs = [ libgreeting ];
code = ''
#include <stdio.h>
extern const char* getGreeting(void);
int main() {
puts(getGreeting());
}
'';
unpackPhase = ''
echo "$code" > greeting-test.c
'';
installPhase = ''
mkdir -p $out/bin
$CC -c greeting-test.c
$CC greeting-test.o -lgreeting -o $out/bin/greeting-test
# Now test the installed binaries right after compiling them. In particular,
# don't do this in installCheckPhase because fixupPhase has been run by then!
(
export PATH=$out/bin
set -x
# Verify that our unmodified binary works as expected.
[ "$(greeting-test)" = "Hello, world!" ]
# And finally, test that a library in LD_LIBRARY_PATH takes precedence over the linked-in library.
[ "$(LD_LIBRARY_PATH=${libgoodbye}/lib greeting-test)" = "Goodbye, world!" ]
)
'';
};
in
stdenv.mkDerivation {
name = "test-LD_LIBRARY_PATH";
nativeBuildInputs = [ testProgram ];
buildCommand = ''
# And for good measure, repeat the tests again from a separate derivation,
# as fixupPhase done by the stdenv can (and has!) affect the result.
[ "$(greeting-test)" = "Hello, world!" ]
[ "$(LD_LIBRARY_PATH=${libgoodbye}/lib greeting-test)" = "Goodbye, world!" ]
touch $out
'';
meta.platforms = lib.platforms.linux;
}

View File

@@ -0,0 +1,29 @@
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
int main(int argc, char **argv) {
char **argv_tmp = calloc(9 + argc + 3 + 1, sizeof(*argv_tmp));
assert(argv_tmp != NULL);
argv_tmp[0] = argv[0];
argv_tmp[1] = "-x";
argv_tmp[2] = "-y";
argv_tmp[3] = "-z";
argv_tmp[4] = "-abc";
argv_tmp[5] = "test var here";
argv_tmp[6] = "-g";
argv_tmp[7] = "*.txt";
argv_tmp[8] = "-a";
argv_tmp[9] = "*";
for (int i = 1; i < argc; ++i) {
argv_tmp[9 + i] = argv[i];
}
argv_tmp[9 + argc + 0] = "-foo";
argv_tmp[9 + argc + 1] = "-bar";
argv_tmp[9 + argc + 2] = "test var 2 here";
argv_tmp[9 + argc + 3] = NULL;
argv = argv_tmp;
argv[0] = "/send/me/flags";
return execv("/send/me/flags", argv);
}

View File

@@ -0,0 +1,7 @@
--append-flags "-foo -bar" \
--add-flags "-x -y -z" \
--add-flags -abc \
--add-flag 'test var here' \
--add-flags "-g *.txt" \
--add-flags "-a *" \
--append-flag 'test var 2 here'

View File

@@ -0,0 +1,14 @@
CWD=SUBST_CWD
SUBST_ARGV0
-x
-y
-z
-abc
test var here
-g
*.txt
-a
*
-foo
-bar
test var 2 here

View File

@@ -0,0 +1,7 @@
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv) {
argv[0] = "alternative-name";
return execv("/send/me/flags", argv);
}

View File

@@ -0,0 +1 @@
--argv0 alternative-name

View File

@@ -0,0 +1,2 @@
CWD=SUBST_CWD
alternative-name

View File

@@ -0,0 +1,7 @@
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv) {
argv[0] = "/send/me/flags";
return execv("/send/me/flags", argv);
}

View File

@@ -0,0 +1,2 @@
CWD=SUBST_CWD
SUBST_ARGV0

View File

@@ -0,0 +1,11 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0)
int main(int argc, char **argv) {
assert_success(chdir("./tmp/foo"));
argv[0] = "/send/me/flags";
return execv("/send/me/flags", argv);
}

View File

@@ -0,0 +1 @@
--chdir ./tmp/foo

View File

@@ -0,0 +1,2 @@
CWD=SUBST_CWD/tmp/foo
SUBST_ARGV0

View File

@@ -0,0 +1,53 @@
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0)
void set_env_prefix(char *env, char *sep, char *prefix) {
char *existing = getenv(env);
if (existing) {
char *val;
assert_success(asprintf(&val, "%s%s%s", prefix, sep, existing));
assert_success(setenv(env, val, 1));
free(val);
} else {
assert_success(setenv(env, prefix, 1));
}
}
void set_env_suffix(char *env, char *sep, char *suffix) {
char *existing = getenv(env);
if (existing) {
char *val;
assert_success(asprintf(&val, "%s%s%s", existing, sep, suffix));
assert_success(setenv(env, val, 1));
free(val);
} else {
assert_success(setenv(env, suffix, 1));
}
}
int main(int argc, char **argv) {
assert_success(setenv("MESSAGE", "HELLO", 0));
set_env_prefix("PATH", ":", "/usr/bin/");
set_env_suffix("PATH", ":", "/usr/local/bin/");
putenv("MESSAGE2=WORLD");
char **argv_tmp = calloc(3 + argc + 0 + 1, sizeof(*argv_tmp));
assert(argv_tmp != NULL);
argv_tmp[0] = argv[0];
argv_tmp[1] = "-x";
argv_tmp[2] = "-y";
argv_tmp[3] = "-z";
for (int i = 1; i < argc; ++i) {
argv_tmp[3 + i] = argv[i];
}
argv_tmp[3 + argc + 0] = NULL;
argv = argv_tmp;
argv[0] = "my-wrapper";
return execv("/send/me/flags", argv);
}

View File

@@ -0,0 +1,6 @@
--argv0 my-wrapper \
--set-default MESSAGE HELLO \
--prefix PATH : /usr/bin/ \
--suffix PATH : /usr/local/bin/ \
--add-flags "-x -y -z" \
--set MESSAGE2 WORLD

View File

@@ -0,0 +1,8 @@
MESSAGE=HELLO
PATH=/usr/bin/:/usr/local/bin/
MESSAGE2=WORLD
CWD=SUBST_CWD
my-wrapper
-x
-y
-z

View File

@@ -0,0 +1,30 @@
{
stdenv,
runCommand,
makeBinaryWrapper,
binutils,
lib,
expectedArch ? stdenv.hostPlatform.parsed.cpu.name,
}:
runCommand "make-binary-wrapper-test-cross"
{
nativeBuildInputs = [
makeBinaryWrapper
binutils
];
# For x86_64-linux the machine field is
# Advanced Micro Devices X86-64
# and uses a dash instead of a underscore unlike x86_64-linux in hostPlatform.parsed.cpu.name
expectedArch = lib.replaceStrings [ "_" ] [ "-" ] expectedArch;
}
''
touch prog
chmod +x prog
makeWrapper prog $out
read -r _ arch < <($READELF --file-header $out | grep Machine:)
if [[ ''${arch,,} != *"''${expectedArch,,}"* ]]; then
echo "expected $expectedArch, got $arch"
exit 1
fi
''

View File

@@ -0,0 +1,74 @@
{
lib,
stdenv,
pkgsCross,
makeBinaryWrapper,
writeText,
runCommand,
runCommandCC,
}:
let
env = {
nativeBuildInputs = [ makeBinaryWrapper ];
};
envCheck = runCommandCC "envcheck" env ''
cc -Wall -Werror -Wpedantic -o $out ${./envcheck.c}
'';
makeGoldenTest =
testname:
runCommand "make-binary-wrapper-test-${testname}" env ''
mkdir -p tmp/foo # for the chdir test
source=${./. + "/${testname}"}
params=$(<"$source/${testname}.cmdline")
eval "makeCWrapper /send/me/flags $params" > wrapper.c
diff wrapper.c "$source/${testname}.c"
if [ -f "$source/${testname}.env" ]; then
eval "makeWrapper ${envCheck} wrapped $params"
env -i ./wrapped > env.txt
sed "s#SUBST_ARGV0#${envCheck}#;s#SUBST_CWD#$PWD#" \
"$source/${testname}.env" > golden-env.txt
if ! diff env.txt golden-env.txt; then
echo "env/argv should be:"
cat golden-env.txt
echo "env/argv output is:"
cat env.txt
exit 1
fi
else
# without a golden env, we expect the wrapper compilation to fail
! eval "makeWrapper ${envCheck} wrapped $params" &> error.txt
fi
cp wrapper.c $out
'';
tests =
lib.genAttrs [
"add-flags"
"argv0"
"basic"
"chdir"
"combination"
"env"
"inherit-argv0"
"invalid-env"
"overlength-strings"
"prefix"
"suffix"
] makeGoldenTest
// lib.optionalAttrs (!stdenv.hostPlatform.isDarwin) {
cross =
pkgsCross.${if stdenv.buildPlatform.isAarch64 then "gnu64" else "aarch64-multiplatform"}.callPackage
./cross.nix
{ };
};
in
writeText "make-binary-wrapper-tests" ''
${lib.concatStringsSep "\n" (builtins.attrValues tests)}
''
// tests

14
pkgs/test/make-binary-wrapper/env/env.c vendored Normal file
View File

@@ -0,0 +1,14 @@
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define assert_success(e) do { if ((e) < 0) { perror(#e); abort(); } } while (0)
int main(int argc, char **argv) {
putenv("PART1=HELLO");
assert_success(setenv("PART2", "WORLD", 0));
assert_success(unsetenv("SOME_OTHER_VARIABLE"));
putenv("PART3=\"!!\n\"");
argv[0] = "/send/me/flags";
return execv("/send/me/flags", argv);
}

View File

@@ -0,0 +1,4 @@
--set PART1 HELLO \
--set-default PART2 WORLD \
--unset SOME_OTHER_VARIABLE \
--set PART3 $'"!!\n"'

View File

@@ -0,0 +1,6 @@
PART1=HELLO
PART2=WORLD
PART3="!!
"
CWD=SUBST_CWD
SUBST_ARGV0

View File

@@ -0,0 +1,22 @@
#include <limits.h>
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv, char **envp) {
for (char **env = envp; *env != 0; ++env) {
puts(*env);
}
char cwd[PATH_MAX];
if (getcwd(cwd, sizeof(cwd))) {
printf("CWD=%s\n", cwd);
} else {
perror("getcwd() error");
return 1;
}
for (int i=0; i < argc; ++i) {
puts(argv[i]);
}
return 0;
}

View File

@@ -0,0 +1,6 @@
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char **argv) {
return execv("/send/me/flags", argv);
}

View File

@@ -0,0 +1 @@
--inherit-argv0

Some files were not shown because too many files have changed in this diff Show More