1{
2 lib,
3 callPackage,
4 writeText,
5 symlinkJoin,
6 darwin,
7 clang,
8 llvm,
9 tools ? callPackage ./tools.nix {
10 inherit (stdenv)
11 hostPlatform
12 buildPlatform
13 ;
14 },
15 stdenv,
16 stdenvNoCC,
17 dart,
18 fetchgit,
19 runCommand,
20 llvmPackages,
21 llvmPackages_15,
22 patchelf,
23 openbox,
24 xorg,
25 libglvnd,
26 libepoxy,
27 wayland,
28 freetype,
29 pango,
30 glib,
31 harfbuzz,
32 cairo,
33 gdk-pixbuf,
34 at-spi2-atk,
35 zlib,
36 gtk3,
37 pkg-config,
38 ninja,
39 python312,
40 gitMinimal,
41 version,
42 flutterVersion,
43 dartSdkVersion,
44 swiftshaderHash,
45 swiftshaderRev,
46 hashes,
47 patches,
48 url,
49 runtimeMode ? "release",
50 isOptimized ? runtimeMode != "debug",
51}:
52let
53 expandSingleDep =
54 dep: lib.optionals (lib.isDerivation dep) ([ dep ] ++ map (output: dep.${output}) dep.outputs);
55
56 expandDeps = deps: lib.flatten (map expandSingleDep deps);
57
58 constants = callPackage ./constants.nix { platform = stdenv.targetPlatform; };
59
60 python3 = python312;
61
62 src = callPackage ./source.nix {
63 inherit
64 tools
65 flutterVersion
66 version
67 hashes
68 url
69 ;
70 inherit (stdenv)
71 hostPlatform
72 buildPlatform
73 targetPlatform
74 ;
75 };
76
77 swiftshader = fetchgit {
78 url = "https://swiftshader.googlesource.com/SwiftShader.git";
79 hash = swiftshaderHash;
80 rev = swiftshaderRev;
81
82 postFetch = ''
83 rm -rf $out/third_party/llvm-project
84 '';
85 };
86
87 llvm = symlinkJoin {
88 name = "llvm";
89 paths = with llvmPackages; [
90 clang
91 llvmPackages.llvm
92 ];
93 };
94
95 outName = "host_${runtimeMode}${lib.optionalString (!isOptimized) "_unopt"}";
96
97 dartPath = "${
98 if (lib.versionAtLeast flutterVersion "3.23") then "flutter/third_party" else "third_party"
99 }/dart";
100in
101stdenv.mkDerivation (finalAttrs: {
102 pname = "flutter-engine-${runtimeMode}${lib.optionalString (!isOptimized) "-unopt"}";
103 inherit
104 version
105 runtimeMode
106 patches
107 isOptimized
108 dartSdkVersion
109 src
110 outName
111 swiftshader
112 ;
113
114 setOutputFlags = false;
115 doStrip = isOptimized;
116
117 toolchain = symlinkJoin {
118 name = "flutter-engine-toolchain-${version}";
119
120 paths =
121 expandDeps (
122 lib.optionals (stdenv.hostPlatform.isLinux) [
123 gtk3
124 wayland
125 libepoxy
126 libglvnd
127 freetype
128 at-spi2-atk
129 glib
130 gdk-pixbuf
131 harfbuzz
132 pango
133 cairo
134 xorg.libxcb
135 xorg.libX11
136 xorg.libXcursor
137 xorg.libXrandr
138 xorg.libXrender
139 xorg.libXinerama
140 xorg.libXi
141 xorg.libXext
142 xorg.libXfixes
143 xorg.libXxf86vm
144 xorg.xorgproto
145 zlib
146 ]
147 ++ lib.optionals (stdenv.hostPlatform.isDarwin) [
148 clang
149 llvm
150 ]
151 )
152 ++ [
153 stdenv.cc.libc_dev
154 stdenv.cc.libc_lib
155 ];
156
157 # Needed due to Flutter expecting everything to be relative to $out
158 # and not true absolute path (ie relative to "/").
159 postBuild = ''
160 mkdir -p $(dirname $(dirname "$out/$out"))
161 ln -s $(dirname "$out") $out/$(dirname "$out")
162 '';
163 };
164
165 NIX_CFLAGS_COMPILE = [
166 "-I${finalAttrs.toolchain}/include"
167 ] ++ lib.optional (!isOptimized) "-U_FORTIFY_SOURCE";
168
169 nativeCheckInputs = lib.optionals stdenv.hostPlatform.isLinux [
170 xorg.xorgserver
171 openbox
172 ];
173
174 nativeBuildInputs =
175 [
176 (python3.withPackages (
177 ps: with ps; [
178 pyyaml
179 ]
180 ))
181 (tools.vpython python3)
182 gitMinimal
183 pkg-config
184 ninja
185 dart
186 ]
187 ++ lib.optionals (stdenv.hostPlatform.isLinux) [ patchelf ]
188 ++ lib.optionals (stdenv.hostPlatform.isDarwin) [
189 darwin.system_cmds
190 darwin.xcode
191 tools.xcode-select
192 ]
193 ++ lib.optionals (stdenv.cc.libc ? bin) [ stdenv.cc.libc.bin ];
194
195 buildInputs = [ gtk3 ];
196
197 patchtools = [ "flutter/third_party/gn/gn" ];
198
199 dontPatch = true;
200
201 patchgit = [
202 dartPath
203 "flutter"
204 "."
205 ] ++ lib.optional (lib.versionAtLeast flutterVersion "3.21") "flutter/third_party/skia";
206
207 postUnpack = ''
208 pushd ${src.name}
209
210 cp ${./pkg-config.py} src/build/config/linux/pkg-config.py
211
212 cp -pr --reflink=auto $swiftshader src/flutter/third_party/swiftshader
213 chmod -R u+w -- src/flutter/third_party/swiftshader
214
215 ln -s ${llvmPackages_15.llvm.monorepoSrc} src/flutter/third_party/swiftshader/third_party/llvm-project
216
217 mkdir -p src/flutter/buildtools/${constants.alt-platform}
218 ln -s ${llvm} src/flutter/buildtools/${constants.alt-platform}/clang
219
220 mkdir -p src/buildtools/${constants.alt-platform}
221 ln -s ${llvm} src/buildtools/${constants.alt-platform}/clang
222
223 mkdir -p src/${dartPath}/tools/sdks
224 ln -s ${dart} src/${dartPath}/tools/sdks/dart-sdk
225
226 ${lib.optionalString (stdenv.hostPlatform.isLinux) ''
227 for patchtool in ''${patchtools[@]}; do
228 patchelf src/$patchtool --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker)
229 done
230 ''}
231
232 for dir in ''${patchgit[@]}; do
233 pushd src/$dir
234 rm -rf .git
235 git init
236 git add .
237 git config user.name "nobody"
238 git config user.email "nobody@local.host"
239 git commit -a -m "$dir" --quiet
240 popd
241 done
242
243 dart src/${dartPath}/tools/generate_package_config.dart
244 echo "${dartSdkVersion}" >src/${dartPath}/sdk/version
245
246 rm -rf src/third_party/angle/.git
247 python3 src/flutter/tools/pub_get_offline.py
248
249 pushd src/flutter
250
251 for p in ''${patches[@]}; do
252 patch -p1 -i $p
253 done
254
255 popd
256 popd
257 '';
258
259 configureFlags =
260 [
261 "--no-prebuilt-dart-sdk"
262 "--embedder-for-target"
263 "--no-goma"
264 ]
265 ++ lib.optionals (stdenv.targetPlatform.isx86_64 == false) [
266 "--linux"
267 "--linux-cpu ${constants.alt-arch}"
268 ]
269 ++ lib.optional (!isOptimized) "--unoptimized"
270 ++ lib.optional (runtimeMode == "debug") "--no-stripped"
271 ++ lib.optional finalAttrs.finalPackage.doCheck "--enable-unittests"
272 ++ lib.optional (!finalAttrs.finalPackage.doCheck) "--no-enable-unittests";
273
274 # NOTE: Once https://github.com/flutter/flutter/issues/127606 is fixed, use "--no-prebuilt-dart-sdk"
275 configurePhase =
276 ''
277 runHook preConfigure
278
279 export PYTHONPATH=$src/src/build
280 ''
281 + lib.optionalString stdenv.hostPlatform.isDarwin ''
282 export PATH=${darwin.xcode}/Contents/Developer/usr/bin/:$PATH
283 ''
284 + ''
285 python3 ./src/flutter/tools/gn $configureFlags \
286 --runtime-mode $runtimeMode \
287 --out-dir $out \
288 --target-sysroot $toolchain \
289 --target-dir $outName \
290 --target-triple ${stdenv.targetPlatform.config} \
291 --enable-fontconfig
292
293 runHook postConfigure
294 '';
295
296 buildPhase = ''
297 runHook preBuild
298
299 export TERM=dumb
300
301 ${lib.optionalString (lib.versionAtLeast flutterVersion "3.29") ''
302 # ValueError: ZIP does not support timestamps before 1980
303 substituteInPlace src/flutter/build/zip.py \
304 --replace-fail "zipfile.ZipFile(args.output, 'w', zipfile.ZIP_DEFLATED)" "zipfile.ZipFile(args.output, 'w', zipfile.ZIP_DEFLATED, strict_timestamps=False)"
305 ''}
306
307 ninja -C $out/out/$outName -j$NIX_BUILD_CORES
308
309 runHook postBuild
310 '';
311
312 # Tests are broken
313 doCheck = false;
314 checkPhase = ''
315 ln -s $out/out src/out
316 touch src/out/run_tests.log
317 sh src/flutter/testing/run_tests.sh $outName
318 rm src/out/run_tests.log
319 '';
320
321 installPhase =
322 ''
323 runHook preInstall
324
325 rm -rf $out/out/$outName/{obj,exe.unstripped,lib.unstripped,zip_archives}
326 rm $out/out/$outName/{args.gn,build.ninja,build.ninja.d,compile_commands.json,toolchain.ninja}
327 find $out/out/$outName -name '*_unittests' -delete
328 find $out/out/$outName -name '*_benchmarks' -delete
329 ''
330 + lib.optionalString (finalAttrs.finalPackage.doCheck) ''
331 rm $out/out/$outName/{display_list_rendertests,flutter_tester}
332 ''
333 + ''
334 runHook postInstall
335 '';
336
337 passthru = {
338 dart = callPackage ./dart.nix { engine = finalAttrs.finalPackage; };
339 };
340
341 meta =
342 with lib;
343 {
344 # Very broken on Darwin
345 broken = stdenv.hostPlatform.isDarwin;
346 description = "The Flutter engine";
347 homepage = "https://flutter.dev";
348 maintainers = with maintainers; [ RossComputerGuy ];
349 license = licenses.bsd3;
350 platforms = [
351 "x86_64-linux"
352 "aarch64-linux"
353 "x86_64-darwin"
354 "aarch64-darwin"
355 ];
356 }
357 // lib.optionalAttrs (lib.versionOlder flutterVersion "3.22") { hydraPlatforms = [ ]; };
358})