1{
2 lib,
3 stdenv,
4 chromium,
5 nodejs,
6 fetchYarnDeps,
7 fetchNpmDeps,
8 fetchpatch,
9 fixup-yarn-lock,
10 npmHooks,
11 yarn,
12 libnotify,
13 unzip,
14 pkgsBuildHost,
15 pipewire,
16 libsecret,
17 libpulseaudio,
18 speechd-minimal,
19 info,
20 gclient2nix,
21}:
22
23let
24 gclientDeps = gclient2nix.importGclientDeps info.deps;
25in
26
27((chromium.override { upstream-info = info.chromium; }).mkDerivation (base: {
28 packageName = "electron";
29 inherit (info) version;
30 buildTargets = [
31 "electron:copy_node_headers"
32 "electron:electron_dist_zip"
33 ];
34
35 outputs = [
36 "out"
37 "headers"
38 ];
39
40 # don't automatically move the include directory from $headers back into $out
41 moveToDev = false;
42
43 nativeBuildInputs = base.nativeBuildInputs ++ [
44 nodejs
45 yarn
46 fixup-yarn-lock
47 unzip
48 npmHooks.npmConfigHook
49 gclient2nix.gclientUnpackHook
50 ];
51 buildInputs = base.buildInputs ++ [ libnotify ];
52
53 electronOfflineCache = fetchYarnDeps {
54 yarnLock = gclientDeps."src/electron".path + "/yarn.lock";
55 sha256 = info.electron_yarn_hash;
56 };
57 npmDeps = fetchNpmDeps rec {
58 src = gclientDeps."src".path;
59 # Assume that the fetcher always unpack the source,
60 # based on update.py
61 sourceRoot = "${src.name}/third_party/node";
62 hash = info.chromium_npm_hash;
63 };
64 inherit gclientDeps;
65 unpackPhase = null; # prevent chromium's unpackPhase from being used
66 sourceRoot = "src";
67
68 env =
69 base.env
70 // {
71 # Hydra can fail to build electron due to clang spamming deprecation
72 # warnings mid-build, causing the build log to grow beyond the limit
73 # of 64mb and then getting killed by Hydra.
74 # For some reason, the log size limit appears to only be enforced on
75 # aarch64-linux. x86_64-linux happily succeeds to build with ~180mb. To
76 # unbreak the build on h.n.o, we simply disable those warnings for now.
77 # https://hydra.nixos.org/build/283952243
78 NIX_CFLAGS_COMPILE = base.env.NIX_CFLAGS_COMPILE + " -Wno-deprecated";
79 }
80 // lib.optionalAttrs (lib.versionAtLeast info.version "35") {
81 # Needed for header generation in electron 35 and above
82 ELECTRON_OUT_DIR = "Release";
83 };
84
85 src = null;
86
87 patches =
88 base.patches
89 # Fix building with Rust 1.87+
90 # https://issues.chromium.org/issues/407024458
91 ++ lib.optionals (lib.versionOlder info.version "37") [
92 # https://chromium-review.googlesource.com/c/chromium/src/+/6432410
93 # Not using fetchpatch here because it ignores file renames: https://github.com/nixos/nixpkgs/issues/32084
94 ./Reland-Use-global_allocator-to-provide-Rust-allocator-implementation.patch
95
96 # https://chromium-review.googlesource.com/c/chromium/src/+/6434355
97 (fetchpatch {
98 name = "Call-Rust-default-allocator-directly-from-Rust.patch";
99 url = "https://github.com/chromium/chromium/commit/73eef8797a8138f5c26f52a1372644b20613f5ee.patch";
100 hash = "sha256-IcSjPv21xT+l9BwJuzeW2AfwBdKI0dQb3nskk6yeKHU=";
101 })
102
103 # https://chromium-review.googlesource.com/c/chromium/src/+/6439711
104 (fetchpatch {
105 name = "Roll-rust.patch";
106 url = "https://github.com/chromium/chromium/commit/a6c30520486be844735dc646cd5b9b434afa0c6b.patch";
107 includes = [ "build/rust/allocator/*" ];
108 hash = "sha256-MFdR75oSAdFW6telEZt/s0qdUvq/BiYFEHW0vk+RgDk=";
109 })
110
111 # https://chromium-review.googlesource.com/c/chromium/src/+/6456604
112 (fetchpatch {
113 name = "Drop-remap_alloc-dep.patch";
114 url = "https://github.com/chromium/chromium/commit/87d5ad2f621e0d5c81849dde24f3a5347efcb167.patch";
115 hash = "sha256-bEoR6jxEyw6Fzm4Zv4US54Cxa0li/0UTZTU2WUf0Rgo=";
116 })
117
118 # https://chromium-review.googlesource.com/c/chromium/src/+/6454872
119 (fetchpatch {
120 name = "rust-Clean-up-build-rust-allocator-after-a-Rust-tool.patch";
121 url = "https://github.com/chromium/chromium/commit/5c74fcf6fd14491f33dd820022a9ca045f492f68.patch";
122 hash = "sha256-vcD0Zfo4Io/FVpupWOdgurFEqwFCv+oDOtSmHbm+ons=";
123 })
124 ]
125 # Fix building with gperf 3.2+
126 # https://issues.chromium.org/issues/40209959
127 ++ lib.optionals (lib.versionOlder info.version "37") [
128 # https://chromium-review.googlesource.com/c/chromium/src/+/6445471
129 (fetchpatch {
130 name = "Dont-apply-FALLTHROUGH-edit-to-gperf-3-2-output.patch";
131 url = "https://github.com/chromium/chromium/commit/f8f21fb4aa01f75acbb12abf5ea8c263c6817141.patch";
132 hash = "sha256-z/aQ1oQjFZnkUeRnrD6P/WDZiYAI1ncGhOUM+HmjMZA=";
133 })
134 ]
135 # Fix build with Rust 1.89.0
136 ++ lib.optionals (lib.versionOlder info.version "38") [
137 # https://chromium-review.googlesource.com/c/chromium/src/+/6624733
138 (fetchpatch {
139 name = "Define-rust-no-alloc-shim-is-unstable-v2.patch";
140 url = "https://github.com/chromium/chromium/commit/6aae0e2353c857d98980ff677bf304288d7c58de.patch";
141 hash = "sha256-Dd38c/0hiH+PbGPJhhEFuW6kUR45A36XZqOVExoxlhM=";
142 })
143 ];
144
145 npmRoot = "third_party/node";
146
147 postPatch = ''
148 mkdir -p third_party/jdk/current/bin
149
150 echo 'build_with_chromium = true' >> build/config/gclient_args.gni
151 echo 'checkout_google_benchmark = false' >> build/config/gclient_args.gni
152 echo 'checkout_android = false' >> build/config/gclient_args.gni
153 echo 'checkout_android_prebuilts_build_tools = false' >> build/config/gclient_args.gni
154 echo 'checkout_android_native_support = false' >> build/config/gclient_args.gni
155 echo 'checkout_ios_webkit = false' >> build/config/gclient_args.gni
156 echo 'checkout_nacl = false' >> build/config/gclient_args.gni
157 echo 'checkout_openxr = false' >> build/config/gclient_args.gni
158 echo 'checkout_rts_model = false' >> build/config/gclient_args.gni
159 echo 'checkout_src_internal = false' >> build/config/gclient_args.gni
160 echo 'cros_boards = ""' >> build/config/gclient_args.gni
161 echo 'cros_boards_with_qemu_images = ""' >> build/config/gclient_args.gni
162 echo 'generate_location_tags = true' >> build/config/gclient_args.gni
163
164 echo 'LASTCHANGE=${info.deps."src".args.tag}-refs/heads/master@{#0}' > build/util/LASTCHANGE
165 echo "$SOURCE_DATE_EPOCH" > build/util/LASTCHANGE.committime
166
167 cat << EOF > gpu/config/gpu_lists_version.h
168 /* Generated by lastchange.py, do not edit.*/
169 #ifndef GPU_CONFIG_GPU_LISTS_VERSION_H_
170 #define GPU_CONFIG_GPU_LISTS_VERSION_H_
171 #define GPU_LISTS_VERSION "${info.deps."src".args.tag}"
172 #endif // GPU_CONFIG_GPU_LISTS_VERSION_H_
173 EOF
174
175 cat << EOF > skia/ext/skia_commit_hash.h
176 /* Generated by lastchange.py, do not edit.*/
177 #ifndef SKIA_EXT_SKIA_COMMIT_HASH_H_
178 #define SKIA_EXT_SKIA_COMMIT_HASH_H_
179 #define SKIA_COMMIT_HASH "${info.deps."src/third_party/skia".args.rev}-"
180 #endif // SKIA_EXT_SKIA_COMMIT_HASH_H_
181 EOF
182
183 echo -n '${info.deps."src/third_party/dawn".args.rev}' > gpu/webgpu/DAWN_VERSION
184
185 (
186 cd electron
187 export HOME=$TMPDIR/fake_home
188 yarn config --offline set yarn-offline-mirror $electronOfflineCache
189 fixup-yarn-lock yarn.lock
190 yarn install --offline --frozen-lockfile --ignore-scripts --no-progress --non-interactive
191 )
192
193 (
194 cd ..
195 PATH=$PATH:${
196 lib.makeBinPath (
197 with pkgsBuildHost;
198 [
199 jq
200 git
201 ]
202 )
203 }
204 config=src/electron/patches/config.json
205 for entry in $(cat $config | jq -c ".[]")
206 do
207 patch_dir=$(echo $entry | jq -r ".patch_dir")
208 repo=$(echo $entry | jq -r ".repo")
209 for patch in $(cat $patch_dir/.patches)
210 do
211 echo applying in $repo: $patch
212 git apply -p1 --directory=$repo --exclude='src/third_party/blink/web_tests/*' --exclude='src/content/test/data/*' $patch_dir/$patch
213 done
214 done
215 )
216 ''
217 + lib.optionalString (lib.versionAtLeast info.version "36") ''
218 echo 'checkout_glic_e2e_tests = false' >> build/config/gclient_args.gni
219 echo 'checkout_mutter = false' >> build/config/gclient_args.gni
220 ''
221 + lib.optionalString (lib.versionAtLeast info.version "38") ''
222 echo 'checkout_clusterfuzz_data = false' >> build/config/gclient_args.gni
223 ''
224 + base.postPatch;
225
226 preConfigure = ''
227 (
228 cd third_party/node
229 grep patch update_npm_deps | sh
230 )
231 ''
232 + (base.preConfigure or "");
233
234 gnFlags = rec {
235 # build/args/release.gn
236 is_component_build = false;
237 is_official_build = true;
238 rtc_use_h264 = proprietary_codecs;
239 is_component_ffmpeg = true;
240
241 # build/args/all.gn
242 is_electron_build = true;
243 root_extra_deps = [ "//electron" ];
244 node_module_version = lib.toInt info.modules;
245 v8_promise_internal_field_count = 1;
246 v8_embedder_string = "-electron.0";
247 v8_enable_snapshot_native_code_counters = false;
248 v8_enable_javascript_promise_hooks = true;
249 enable_cdm_host_verification = false;
250 proprietary_codecs = true;
251 ffmpeg_branding = "Chrome";
252 enable_printing = true;
253 angle_enable_vulkan_validation_layers = false;
254 dawn_enable_vulkan_validation_layers = false;
255 enable_pseudolocales = false;
256 allow_runtime_configurable_key_storage = true;
257 enable_cet_shadow_stack = false;
258 is_cfi = false;
259 v8_builtins_profiling_log_file = "";
260 enable_dangling_raw_ptr_checks = false;
261 dawn_use_built_dxc = false;
262 v8_enable_private_mapping_fork_optimization = true;
263 v8_expose_public_symbols = true;
264 enable_dangling_raw_ptr_feature_flag = false;
265 clang_unsafe_buffers_paths = "";
266 enterprise_cloud_content_analysis = false;
267
268 # other
269 enable_widevine = false;
270 override_electron_version = info.version;
271 }
272 // lib.optionalAttrs (lib.versionOlder info.version "38") {
273 content_enable_legacy_ipc = true;
274 };
275
276 installPhase = ''
277 runHook preInstall
278
279 mkdir -p $libExecPath
280 unzip -d $libExecPath out/Release/dist.zip
281
282 mkdir -p $headers
283 cp -r out/Release/gen/node_headers/* $headers/
284
285 runHook postInstall
286 '';
287
288 postFixup =
289 let
290 libPath = lib.makeLibraryPath [
291 libnotify
292 pipewire
293 stdenv.cc.cc
294 libsecret
295 libpulseaudio
296 speechd-minimal
297 ];
298 in
299 base.postFixup
300 + ''
301 patchelf \
302 --add-rpath "${libPath}" \
303 $out/libexec/electron/electron
304 '';
305
306 requiredSystemFeatures = [ "big-parallel" ];
307
308 passthru = {
309 inherit info;
310 };
311
312 meta = with lib; {
313 description = "Cross platform desktop application shell";
314 homepage = "https://github.com/electron/electron";
315 platforms = lib.platforms.linux;
316 license = licenses.mit;
317 maintainers = with maintainers; [
318 yayayayaka
319 teutat3s
320 tomasajt
321 ];
322 mainProgram = "electron";
323 hydraPlatforms =
324 lib.optionals (!(hasInfix "alpha" info.version) && !(hasInfix "beta" info.version))
325 [
326 "aarch64-linux"
327 "x86_64-linux"
328 ];
329 timeout = 172800; # 48 hours (increased from the Hydra default of 10h)
330 };
331})).overrideAttrs
332 (
333 finalAttrs: prevAttrs: {
334 # this was the only way I could get the package to properly reference itself
335 passthru = prevAttrs.passthru // {
336 dist = finalAttrs.finalPackage + "/libexec/electron";
337 };
338 }
339 )