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