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