1{ pkgs, lib }:
2
3let
4
5 testedSystems = lib.filterAttrs (name: value: let
6 platform = lib.systems.elaborate value;
7 in platform.isLinux || platform.isWindows
8 ) lib.systems.examples;
9
10 getExecutable = pkgs: pkgFun: exec:
11 "${pkgFun pkgs}${exec}${pkgs.hostPlatform.extensions.executable}";
12
13 compareTest = { emulator, pkgFun, hostPkgs, crossPkgs, exec, args ? [] }: let
14 pkgName = (pkgFun hostPkgs).name;
15 args' = lib.concatStringsSep " " args;
16 in crossPkgs.runCommand "test-${pkgName}-${crossPkgs.hostPlatform.config}" {
17 nativeBuildInputs = [ pkgs.dos2unix ];
18 } ''
19 # Just in case we are using wine, get rid of that annoying extra
20 # stuff.
21 export WINEDEBUG=-all
22
23 HOME=$(pwd)
24 mkdir -p $out
25
26 # We need to remove whitespace, unfortunately
27 # Windows programs use \r but Unix programs use \n
28
29 echo Running native-built program natively
30
31 # find expected value natively
32 ${getExecutable hostPkgs pkgFun exec} ${args'} \
33 | dos2unix > $out/expected
34
35 echo Running cross-built program in emulator
36
37 # run emulator to get actual value
38 ${emulator} ${getExecutable crossPkgs pkgFun exec} ${args'} \
39 | dos2unix > $out/actual
40
41 echo Comparing results...
42
43 if [ "$(cat $out/actual)" != "$(cat $out/expected)" ]; then
44 echo "${pkgName} did not output expected value:"
45 cat $out/expected
46 echo "instead it output:"
47 cat $out/actual
48 exit 1
49 else
50 echo "${pkgName} test passed"
51 echo "both produced output:"
52 cat $out/actual
53 fi
54 '';
55
56 mapMultiPlatformTest = crossSystemFun: test: lib.mapAttrs (name: system: test rec {
57 crossPkgs = import pkgs.path {
58 localSystem = { inherit (pkgs.hostPlatform) config; };
59 crossSystem = crossSystemFun system;
60 };
61
62 emulator = crossPkgs.hostPlatform.emulator pkgs;
63
64 # Apply some transformation on windows to get dlls in the right
65 # place. Unfortunately mingw doesn’t seem to be able to do linking
66 # properly.
67 platformFun = pkg: if crossPkgs.hostPlatform.isWindows then
68 pkgs.buildEnv {
69 name = "${pkg.name}-winlinks";
70 paths = [pkg] ++ pkg.buildInputs;
71 } else pkg;
72 }) testedSystems;
73
74 tests = {
75
76 file = {platformFun, crossPkgs, emulator}: compareTest {
77 inherit emulator crossPkgs;
78 hostPkgs = pkgs;
79 exec = "/bin/file";
80 args = [
81 "${pkgs.file}/share/man/man1/file.1.gz"
82 "${pkgs.dejavu_fonts}/share/fonts/truetype/DejaVuMathTeXGyre.ttf"
83 ];
84 pkgFun = pkgs: platformFun pkgs.file;
85 };
86
87 hello = {platformFun, crossPkgs, emulator}: compareTest {
88 inherit emulator crossPkgs;
89 hostPkgs = pkgs;
90 exec = "/bin/hello";
91 pkgFun = pkgs: pkgs.hello;
92 };
93
94 pkg-config = {platformFun, crossPkgs, emulator}: crossPkgs.runCommand
95 "test-pkg-config-${crossPkgs.hostPlatform.config}"
96 {
97 depsBuildBuild = [ crossPkgs.pkgsBuildBuild.pkg-config ];
98 nativeBuildInputs = [ crossPkgs.pkgsBuildHost.pkg-config crossPkgs.buildPackages.zlib ];
99 depsBuildTarget = [ crossPkgs.pkgsBuildTarget.pkg-config ];
100 buildInputs = [ crossPkgs.zlib ];
101 NIX_DEBUG = 7;
102 } ''
103 mkdir $out
104 ${crossPkgs.pkgsBuildBuild.pkg-config.targetPrefix}pkg-config --cflags zlib > "$out/for-build"
105 ${crossPkgs.pkgsBuildHost.pkg-config.targetPrefix}pkg-config --cflags zlib > "$out/for-host"
106 ! diff "$out/for-build" "$out/for-host"
107 '';
108 };
109
110in {
111 gcc = (lib.mapAttrs (_: mapMultiPlatformTest (system: system // {useLLVM = false;})) tests);
112 llvm = (lib.mapAttrs (_: mapMultiPlatformTest (system: system // {useLLVM = true;})) tests);
113}