1{ lib
2, callPackage
3, stdenvNoCC
4, makeWrapper
5, llvmPackages_13
6, cacert
7, flutter
8, jq
9}:
10
11# absolutely no mac support for now
12
13{ pubGetScript ? "flutter pub get"
14, flutterBuildFlags ? [ ]
15, runtimeDependencies ? [ ]
16, customPackageOverrides ? { }
17, autoDepsList ? false
18, depsListFile ? null
19, vendorHash ? ""
20, pubspecLockFile ? null
21, nativeBuildInputs ? [ ]
22, preUnpack ? ""
23, postFixup ? ""
24, extraWrapProgramArgs ? ""
25, ...
26}@args:
27let
28 flutterSetupScript = ''
29 export HOME="$NIX_BUILD_TOP"
30 flutter config --no-analytics &>/dev/null # mute first-run
31 flutter config --enable-linux-desktop >/dev/null
32 '';
33
34 deps = callPackage ../dart/fetch-dart-deps { dart = flutter; } {
35 sdkSetupScript = flutterSetupScript;
36 inherit pubGetScript vendorHash pubspecLockFile;
37 buildDrvArgs = args;
38 };
39
40 baseDerivation = llvmPackages_13.stdenv.mkDerivation (finalAttrs: args // {
41 inherit flutterBuildFlags runtimeDependencies;
42
43 outputs = [ "out" "debug" ];
44
45 nativeBuildInputs = [
46 makeWrapper
47 deps
48 flutter
49 jq
50 ] ++ nativeBuildInputs;
51
52 preUnpack = ''
53 ${lib.optionalString (!autoDepsList) ''
54 if ! { [ '${lib.boolToString (depsListFile != null)}' = 'true' ] ${lib.optionalString (depsListFile != null) "&& cmp -s <(jq -Sc . '${depsListFile}') <(jq -Sc . '${finalAttrs.passthru.depsListFile}')"}; }; then
55 echo 1>&2 -e '\nThe dependency list file was either not given or differs from the expected result.' \
56 '\nPlease choose one of the following solutions:' \
57 '\n - Duplicate the following file and pass it to the depsListFile argument.' \
58 '\n ${finalAttrs.passthru.depsListFile}' \
59 '\n - Set autoDepsList to true (not supported by Hydra or permitted in Nixpkgs)'.
60 exit 1
61 fi
62 ''}
63
64 ${preUnpack}
65 '';
66
67 configurePhase = ''
68 runHook preConfigure
69
70 ${flutterSetupScript}
71
72 runHook postConfigure
73 '';
74
75 buildPhase = ''
76 runHook preBuild
77
78 mkdir -p build/flutter_assets/fonts
79
80 doPubGet flutter pub get --offline -v
81 flutter build linux -v --release --split-debug-info="$debug" ${builtins.concatStringsSep " " (map (flag: "\"${flag}\"") finalAttrs.flutterBuildFlags)}
82
83 runHook postBuild
84 '';
85
86 installPhase = ''
87 runHook preInstall
88
89 built=build/linux/*/release/bundle
90
91 mkdir -p $out/bin
92 mv $built $out/app
93
94 for f in $(find $out/app -iname "*.desktop" -type f); do
95 install -D $f $out/share/applications/$(basename $f)
96 done
97
98 for f in $(find $out/app -maxdepth 1 -type f); do
99 ln -s $f $out/bin/$(basename $f)
100 done
101
102 # make *.so executable
103 find $out/app -iname "*.so" -type f -exec chmod +x {} +
104
105 # remove stuff like /build/source/packages/ubuntu_desktop_installer/linux/flutter/ephemeral
106 for f in $(find $out/app -executable -type f); do
107 if patchelf --print-rpath "$f" | grep /build; then # this ignores static libs (e,g. libapp.so) also
108 echo "strip RPath of $f"
109 newrp=$(patchelf --print-rpath $f | sed -r "s|/build.*ephemeral:||g" | sed -r "s|/build.*profile:||g")
110 patchelf --set-rpath "$newrp" "$f"
111 fi
112 done
113
114 runHook postInstall
115 '';
116
117 postFixup = ''
118 # Add runtime library dependencies to the LD_LIBRARY_PATH.
119 # For some reason, the RUNPATH of the executable is not used to load dynamic libraries in dart:ffi with DynamicLibrary.open().
120 #
121 # This could alternatively be fixed with patchelf --add-needed, but this would cause all the libraries to be opened immediately,
122 # which is not what application authors expect.
123 for f in "$out"/bin/*; do
124 wrapProgram "$f" \
125 --suffix LD_LIBRARY_PATH : '${lib.makeLibraryPath finalAttrs.runtimeDependencies}' \
126 ${extraWrapProgramArgs}
127 done
128
129 ${postFixup}
130 '';
131
132 passthru = {
133 inherit (deps) depsListFile;
134 };
135 });
136
137 packageOverrideRepository = (callPackage ../../development/compilers/flutter/package-overrides { }) // customPackageOverrides;
138 productPackages = builtins.filter (package: package.kind != "dev")
139 (if autoDepsList
140 then lib.importJSON deps.depsListFile
141 else
142 if depsListFile == null
143 then [ ]
144 else lib.importJSON depsListFile);
145in
146builtins.foldl'
147 (prev: package:
148 if packageOverrideRepository ? ${package.name}
149 then
150 prev.overrideAttrs
151 (packageOverrideRepository.${package.name} {
152 inherit (package)
153 name
154 version
155 kind
156 source
157 dependencies;
158 })
159 else prev)
160 baseDerivation
161 productPackages