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 ]
168 ++ lib.optional (!isOptimized) "-U_FORTIFY_SOURCE";
169
170 nativeCheckInputs = lib.optionals stdenv.hostPlatform.isLinux [
171 xorg.xorgserver
172 openbox
173 ];
174
175 nativeBuildInputs = [
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 ]
206 ++ lib.optional (lib.versionAtLeast flutterVersion "3.21") "flutter/third_party/skia";
207
208 postUnpack = ''
209 pushd ${src.name}
210
211 cp ${./pkg-config.py} src/build/config/linux/pkg-config.py
212
213 cp -pr --reflink=auto $swiftshader src/flutter/third_party/swiftshader
214 chmod -R u+w -- src/flutter/third_party/swiftshader
215
216 ln -s ${llvmPackages_15.llvm.monorepoSrc} src/flutter/third_party/swiftshader/third_party/llvm-project
217
218 mkdir -p src/flutter/buildtools/${constants.alt-platform}
219 ln -s ${llvm} src/flutter/buildtools/${constants.alt-platform}/clang
220
221 mkdir -p src/buildtools/${constants.alt-platform}
222 ln -s ${llvm} src/buildtools/${constants.alt-platform}/clang
223
224 mkdir -p src/${dartPath}/tools/sdks
225 ln -s ${dart} src/${dartPath}/tools/sdks/dart-sdk
226
227 ${lib.optionalString (stdenv.hostPlatform.isLinux) ''
228 for patchtool in ''${patchtools[@]}; do
229 patchelf src/$patchtool --set-interpreter $(cat $NIX_CC/nix-support/dynamic-linker)
230 done
231 ''}
232
233 for dir in ''${patchgit[@]}; do
234 pushd src/$dir
235 rm -rf .git
236 git init
237 git add .
238 git config user.name "nobody"
239 git config user.email "nobody@local.host"
240 git commit -a -m "$dir" --quiet
241 popd
242 done
243
244 dart src/${dartPath}/tools/generate_package_config.dart
245 echo "${dartSdkVersion}" >src/${dartPath}/sdk/version
246
247 rm -rf src/third_party/angle/.git
248 python3 src/flutter/tools/pub_get_offline.py
249
250 pushd src/flutter
251
252 for p in ''${patches[@]}; do
253 patch -p1 -i $p
254 done
255
256 popd
257 popd
258 '';
259
260 configureFlags = [
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 runHook preConfigure
277
278 export PYTHONPATH=$src/src/build
279 ''
280 + lib.optionalString stdenv.hostPlatform.isDarwin ''
281 export PATH=${darwin.xcode}/Contents/Developer/usr/bin/:$PATH
282 ''
283 + ''
284 python3 ./src/flutter/tools/gn $configureFlags \
285 --runtime-mode $runtimeMode \
286 --out-dir $out \
287 --target-sysroot $toolchain \
288 --target-dir $outName \
289 --target-triple ${stdenv.targetPlatform.config} \
290 --enable-fontconfig
291
292 runHook postConfigure
293 '';
294
295 buildPhase = ''
296 runHook preBuild
297
298 export TERM=dumb
299
300 ${lib.optionalString (lib.versionAtLeast flutterVersion "3.29") ''
301 # ValueError: ZIP does not support timestamps before 1980
302 substituteInPlace src/flutter/build/zip.py \
303 --replace-fail "zipfile.ZipFile(args.output, 'w', zipfile.ZIP_DEFLATED)" "zipfile.ZipFile(args.output, 'w', zipfile.ZIP_DEFLATED, strict_timestamps=False)"
304 ''}
305
306 ninja -C $out/out/$outName -j$NIX_BUILD_CORES
307
308 runHook postBuild
309 '';
310
311 # Tests are broken
312 doCheck = false;
313 checkPhase = ''
314 ln -s $out/out src/out
315 touch src/out/run_tests.log
316 sh src/flutter/testing/run_tests.sh $outName
317 rm src/out/run_tests.log
318 '';
319
320 installPhase = ''
321 runHook preInstall
322
323 rm -rf $out/out/$outName/{obj,exe.unstripped,lib.unstripped,zip_archives}
324 rm $out/out/$outName/{args.gn,build.ninja,build.ninja.d,compile_commands.json,toolchain.ninja}
325 find $out/out/$outName -name '*_unittests' -delete
326 find $out/out/$outName -name '*_benchmarks' -delete
327 ''
328 + lib.optionalString (finalAttrs.finalPackage.doCheck) ''
329 rm $out/out/$outName/{display_list_rendertests,flutter_tester}
330 ''
331 + ''
332 runHook postInstall
333 '';
334
335 passthru = {
336 dart = callPackage ./dart.nix { engine = finalAttrs.finalPackage; };
337 };
338
339 meta =
340 with lib;
341 {
342 # Very broken on Darwin
343 broken = stdenv.hostPlatform.isDarwin;
344 description = "Flutter engine";
345 homepage = "https://flutter.dev";
346 maintainers = with maintainers; [ RossComputerGuy ];
347 license = licenses.bsd3;
348 platforms = [
349 "x86_64-linux"
350 "aarch64-linux"
351 "x86_64-darwin"
352 "aarch64-darwin"
353 ];
354 }
355 // lib.optionalAttrs (lib.versionOlder flutterVersion "3.22") { hydraPlatforms = [ ]; };
356})