lol
1{ pname
2, version
3, packageVersion ? version
4, meta
5, updateScript ? null
6, binaryName ? "firefox"
7, application ? "browser"
8, applicationName ? "Mozilla Firefox"
9, branding ? null
10, requireSigning ? true
11, allowAddonSideload ? false
12, src
13, unpackPhase ? null
14, extraPatches ? []
15, extraPostPatch ? ""
16, extraNativeBuildInputs ? []
17, extraConfigureFlags ? []
18, extraBuildInputs ? []
19, extraMakeFlags ? []
20, extraPassthru ? {}
21, tests ? []
22}:
23
24
25{ lib
26, pkgs
27, stdenv
28, fetchpatch
29, patchelf
30
31# build time
32, autoconf
33, cargo
34, dump_syms
35, makeWrapper
36, mimalloc
37, nodejs
38, perl
39, pkg-config
40, pkgsCross # wasm32 rlbox
41, python3
42, runCommand
43, rustc
44, rust-cbindgen
45, rustPlatform
46, unzip
47, which
48, wrapGAppsHook
49
50# runtime
51, bzip2
52, dbus
53, dbus-glib
54, file
55, fontconfig
56, freetype
57, glib
58, gnum4
59, gtk3
60, icu
61, icu72
62, libGL
63, libGLU
64, libevent
65, libffi
66, libjpeg
67, libpng
68, libstartup_notification
69, libvpx
70, libwebp
71, nasm
72, nspr
73, nss_esr
74, nss_latest
75, pango
76, xorg
77, zip
78, zlib
79, pkgsBuildBuild
80
81# optionals
82
83## debugging
84
85, debugBuild ? false
86
87# On 32bit platforms, we disable adding "-g" for easier linking.
88, enableDebugSymbols ? !stdenv.is32bit
89
90## optional libraries
91
92, alsaSupport ? stdenv.isLinux, alsa-lib
93, ffmpegSupport ? true
94, gssSupport ? true, libkrb5
95, jackSupport ? stdenv.isLinux, libjack2
96, jemallocSupport ? !stdenv.hostPlatform.isMusl, jemalloc
97, ltoSupport ? (stdenv.isLinux && stdenv.is64bit && !stdenv.hostPlatform.isRiscV), overrideCC, buildPackages
98, pgoSupport ? (stdenv.isLinux && stdenv.hostPlatform == stdenv.buildPlatform), xvfb-run
99, pipewireSupport ? waylandSupport && webrtcSupport
100, pulseaudioSupport ? stdenv.isLinux, libpulseaudio
101, sndioSupport ? stdenv.isLinux, sndio
102, waylandSupport ? true, libxkbcommon, libdrm
103
104## privacy-related options
105
106, privacySupport ? false
107
108# WARNING: NEVER set any of the options below to `true` by default.
109# Set to `!privacySupport` or `false`.
110
111, crashreporterSupport ? !privacySupport && !stdenv.hostPlatform.isRiscV && !stdenv.hostPlatform.isMusl, curl
112, geolocationSupport ? !privacySupport
113, googleAPISupport ? geolocationSupport
114, mlsAPISupport ? geolocationSupport
115, webrtcSupport ? !privacySupport && !stdenv.hostPlatform.isRiscV
116
117# digital rights managemewnt
118
119# This flag controls whether Firefox will show the nagbar, that allows
120# users at runtime the choice to enable Widevine CDM support when a site
121# requests it.
122# Controlling the nagbar and widevine CDM at runtime is possible by setting
123# `browser.eme.ui.enabled` and `media.gmp-widevinecdm.enabled` accordingly
124, drmSupport ? true
125
126# As stated by Sylvestre Ledru (@sylvestre) on Nov 22, 2017 at
127# https://github.com/NixOS/nixpkgs/issues/31843#issuecomment-346372756 we
128# have permission to use the official firefox branding.
129#
130# For purposes of documentation the statement of @sylvestre:
131# > As the person who did part of the work described in the LWN article
132# > and release manager working for Mozilla, I can confirm the statement
133# > that I made in
134# > https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=815006
135# >
136# > @garbas shared with me the list of patches applied for the Nix package.
137# > As they are just for portability and tiny modifications, they don't
138# > alter the experience of the product. In parallel, Rok also shared the
139# > build options. They seem good (even if I cannot judge the quality of the
140# > packaging of the underlying dependencies like sqlite, png, etc).
141# > Therefor, as long as you keep the patch queue sane and you don't alter
142# > the experience of Firefox users, you won't have any issues using the
143# > official branding.
144, enableOfficialBranding ? true
145}:
146
147assert stdenv.cc.libc or null != null;
148assert pipewireSupport -> !waylandSupport || !webrtcSupport -> throw "${pname}: pipewireSupport requires both wayland and webrtc support.";
149
150let
151 inherit (lib) enableFeature;
152
153 # Target the LLVM version that rustc is built with for LTO.
154 llvmPackages0 = rustc.llvmPackages;
155 llvmPackagesBuildBuild0 = pkgsBuildBuild.rustc.llvmPackages;
156
157 # Force the use of lld and other llvm tools for LTO
158 llvmPackages = llvmPackages0.override {
159 bootBintoolsNoLibc = null;
160 bootBintools = null;
161 };
162 llvmPackagesBuildBuild = llvmPackagesBuildBuild0.override {
163 bootBintoolsNoLibc = null;
164 bootBintools = null;
165 };
166
167 # LTO requires LLVM bintools including ld.lld and llvm-ar.
168 buildStdenv = overrideCC llvmPackages.stdenv (llvmPackages.stdenv.cc.override {
169 bintools = if ltoSupport then buildPackages.rustc.llvmPackages.bintools else stdenv.cc.bintools;
170 });
171
172 # Compile the wasm32 sysroot to build the RLBox Sandbox
173 # https://hacks.mozilla.org/2021/12/webassembly-and-back-again-fine-grained-sandboxing-in-firefox-95/
174 # We only link c++ libs here, our compiler wrapper can find wasi libc and crt itself.
175 wasiSysRoot = runCommand "wasi-sysroot" {} ''
176 mkdir -p $out/lib/wasm32-wasi
177 for lib in ${pkgsCross.wasi32.llvmPackages.libcxx}/lib/* ${pkgsCross.wasi32.llvmPackages.libcxxabi}/lib/*; do
178 ln -s $lib $out/lib/wasm32-wasi
179 done
180 '';
181
182 distributionIni = pkgs.writeText "distribution.ini" (lib.generators.toINI {} {
183 # Some light branding indicating this build uses our distro preferences
184 Global = {
185 id = "nixos";
186 version = "1.0";
187 about = "${applicationName} for NixOS";
188 };
189 Preferences = {
190 # These values are exposed through telemetry
191 "app.distributor" = "nixos";
192 "app.distributor.channel" = "nixpkgs";
193 };
194 });
195
196 defaultPrefs = {
197 "geo.provider.network.url" = {
198 value = "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%";
199 reason = "Use MLS by default for geolocation, since our Google API Keys are not working";
200 };
201 };
202
203 defaultPrefsFile = pkgs.writeText "nixos-default-prefs.js" (lib.concatStringsSep "\n" (lib.mapAttrsToList (key: value: ''
204 // ${value.reason}
205 pref("${key}", ${builtins.toJSON value.value});
206 '') defaultPrefs));
207
208in
209
210buildStdenv.mkDerivation {
211 pname = "${pname}-unwrapped";
212 version = packageVersion;
213
214 inherit src unpackPhase meta;
215
216 outputs = [
217 "out"
218 ]
219 ++ lib.optionals crashreporterSupport [ "symbols" ];
220
221 # Add another configure-build-profiling run before the final configure phase if we build with pgo
222 preConfigurePhases = lib.optionals pgoSupport [
223 "configurePhase"
224 "buildPhase"
225 "profilingPhase"
226 ];
227
228 patches = lib.optionals (lib.versionAtLeast version "112.0" && lib.versionOlder version "113.0") [
229 (fetchpatch {
230 # Crash when desktop scaling does not divide window scale on Wayland
231 # https://bugzilla.mozilla.org/show_bug.cgi?id=1803016
232 name = "mozbz1803016.patch";
233 url = "https://hg.mozilla.org/mozilla-central/raw-rev/1068e0955cfb";
234 hash = "sha256-iPqmofsmgvlFNm+mqVPbdgMKmP68ANuzYu+PzfCpoNA=";
235 })
236 ] ++ lib.optionals (lib.versionOlder version "114.0") [
237 # https://bugzilla.mozilla.org/show_bug.cgi?id=1830040
238 # https://hg.mozilla.org/mozilla-central/rev/cddb250a28d8
239 (fetchpatch {
240 url = "https://git.alpinelinux.org/aports/plain/community/firefox/avoid-redefinition.patch?id=2f620d205ed0f9072bbd7714b5ec1b7bf6911c12";
241 hash = "sha256-fLUYaJwhrC/wF24HkuWn2PHqz7LlAaIZ1HYjRDB2w9A=";
242 })
243 ]
244 ++ lib.optionals (lib.versionOlder version "102.13") [
245 # cherry-pick bindgen change to fix build with clang 16
246 (fetchpatch {
247 url = "https://git.alpinelinux.org/aports/plain/community/firefox-esr/bindgen.patch?id=4c4b0c01c808657fffc5b796c56108c57301b28f";
248 hash = "sha256-lTvgT358M4M2vedZ+A6xSKsBYhSN+McdmEeR9t75MLU=";
249 })
250 # cherry-pick mp4parse change fixing build with Rust 1.70+
251 # original change: https://github.com/mozilla/mp4parse-rust/commit/8b5b652d38e007e736bb442ccd5aa5ed699db100
252 # vendored to update checksums
253 ./mp4parse-rust-170.patch
254 ]
255 ++ lib.optional (lib.versionOlder version "111") ./env_var_for_system_dir-ff86.patch
256 ++ lib.optional (lib.versionAtLeast version "111") ./env_var_for_system_dir-ff111.patch
257 ++ lib.optional (lib.versionAtLeast version "96") ./no-buildconfig-ffx96.patch
258 ++ extraPatches;
259
260 postPatch = ''
261 rm -rf obj-x86_64-pc-linux-gnu
262 patchShebangs mach build
263 ''
264 + extraPostPatch;
265
266 # Ignore trivial whitespace changes in patches, this fixes compatibility of
267 # ./env_var_for_system_dir.patch with Firefox >=65 without having to track
268 # two patches.
269 patchFlags = [ "-p1" "-l" ];
270
271 # if not explicitly set, wrong cc from buildStdenv would be used
272 HOST_CC = "${llvmPackagesBuildBuild.stdenv.cc}/bin/cc";
273 HOST_CXX = "${llvmPackagesBuildBuild.stdenv.cc}/bin/c++";
274
275 nativeBuildInputs = [
276 autoconf
277 cargo
278 gnum4
279 llvmPackagesBuildBuild.bintools
280 makeWrapper
281 nodejs
282 perl
283 pkg-config
284 python3
285 rust-cbindgen
286 rustPlatform.bindgenHook
287 rustc
288 unzip
289 which
290 wrapGAppsHook
291 ]
292 ++ lib.optionals crashreporterSupport [ dump_syms patchelf ]
293 ++ lib.optionals pgoSupport [ xvfb-run ]
294 ++ extraNativeBuildInputs;
295
296 setOutputFlags = false; # `./mach configure` doesn't understand `--*dir=` flags.
297
298 preConfigure = ''
299 # remove distributed configuration files
300 rm -f configure js/src/configure .mozconfig*
301
302 # Runs autoconf through ./mach configure in configurePhase
303 configureScript="$(realpath ./mach) configure"
304
305 # Set predictable directories for build and state
306 export MOZ_OBJDIR=$(pwd)/mozobj
307 export MOZBUILD_STATE_PATH=$(pwd)/mozbuild
308
309 # Don't try to send libnotify notifications during build
310 export MOZ_NOSPAM=1
311
312 # Set consistent remoting name to ensure wmclass matches with desktop file
313 export MOZ_APP_REMOTINGNAME="${binaryName}"
314
315 # AS=as in the environment causes build failure
316 # https://bugzilla.mozilla.org/show_bug.cgi?id=1497286
317 unset AS
318
319 # Use our own python
320 export MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE=system
321
322 # RBox WASM Sandboxing
323 export WASM_CC=${pkgsCross.wasi32.stdenv.cc}/bin/${pkgsCross.wasi32.stdenv.cc.targetPrefix}cc
324 export WASM_CXX=${pkgsCross.wasi32.stdenv.cc}/bin/${pkgsCross.wasi32.stdenv.cc.targetPrefix}c++
325 '' + lib.optionalString pgoSupport ''
326 if [ -e "$TMPDIR/merged.profdata" ]; then
327 echo "Configuring with profiling data"
328 for i in "''${!configureFlagsArray[@]}"; do
329 if [[ ''${configureFlagsArray[i]} = "--enable-profile-generate=cross" ]]; then
330 unset 'configureFlagsArray[i]'
331 fi
332 done
333 configureFlagsArray+=(
334 "--enable-profile-use=cross"
335 "--with-pgo-profile-path="$TMPDIR/merged.profdata""
336 "--with-pgo-jarlog="$TMPDIR/jarlog""
337 )
338 ${lib.optionalString stdenv.hostPlatform.isMusl ''
339 LDFLAGS="$OLD_LDFLAGS"
340 unset OLD_LDFLAGS
341 ''}
342 else
343 echo "Configuring to generate profiling data"
344 configureFlagsArray+=(
345 "--enable-profile-generate=cross"
346 )
347 ${lib.optionalString stdenv.hostPlatform.isMusl
348 # Set the rpath appropriately for the profiling run
349 # During the profiling run, loading libraries from $out would fail,
350 # since the profiling build has not been installed to $out
351 ''
352 OLD_LDFLAGS="$LDFLAGS"
353 LDFLAGS="-Wl,-rpath,$(pwd)/mozobj/dist/${binaryName}"
354 ''}
355 fi
356 '' + lib.optionalString googleAPISupport ''
357 # Google API key used by Chromium and Firefox.
358 # Note: These are for NixOS/nixpkgs use ONLY. For your own distribution,
359 # please get your own set of keys at https://www.chromium.org/developers/how-tos/api-keys/.
360 echo "AIzaSyDGi15Zwl11UNe6Y-5XW_upsfyw31qwZPI" > $TMPDIR/google-api-key
361 # 60.5+ & 66+ did split the google API key arguments: https://bugzilla.mozilla.org/show_bug.cgi?id=1531176
362 configureFlagsArray+=("--with-google-location-service-api-keyfile=$TMPDIR/google-api-key")
363 configureFlagsArray+=("--with-google-safebrowsing-api-keyfile=$TMPDIR/google-api-key")
364 '' + lib.optionalString mlsAPISupport ''
365 # Mozilla Location services API key
366 # Note: These are for NixOS/nixpkgs use ONLY. For your own distribution,
367 # please get your own set of keys at https://location.services.mozilla.com/api.
368 echo "dfd7836c-d458-4917-98bb-421c82d3c8a0" > $TMPDIR/mls-api-key
369 configureFlagsArray+=("--with-mozilla-api-keyfile=$TMPDIR/mls-api-key")
370 '' + lib.optionalString (enableOfficialBranding && !stdenv.is32bit) ''
371 export MOZILLA_OFFICIAL=1
372 '' + lib.optionalString (!requireSigning) ''
373 export MOZ_REQUIRE_SIGNING=
374 '' + lib.optionalString stdenv.hostPlatform.isMusl ''
375 # linking firefox hits the vm.max_map_count kernel limit with the default musl allocator
376 # TODO: Default vm.max_map_count has been increased, retest without this
377 export LD_PRELOAD=${mimalloc}/lib/libmimalloc.so
378 '';
379
380 # firefox has a different definition of configurePlatforms from nixpkgs, see configureFlags
381 configurePlatforms = [ ];
382
383 configureFlags = [
384 "--disable-tests"
385 "--disable-updater"
386 "--enable-application=${application}"
387 "--enable-default-toolkit=cairo-gtk3${lib.optionalString waylandSupport "-wayland"}"
388 "--enable-system-pixman"
389 "--with-distribution-id=org.nixos"
390 "--with-libclang-path=${llvmPackagesBuildBuild.libclang.lib}/lib"
391 "--with-system-ffi"
392 "--with-system-icu"
393 "--with-system-jpeg"
394 "--with-system-libevent"
395 "--with-system-libvpx"
396 "--with-system-nspr"
397 "--with-system-nss"
398 "--with-system-png" # needs APNG support
399 "--with-system-webp"
400 "--with-system-zlib"
401 "--with-wasi-sysroot=${wasiSysRoot}"
402 # for firefox, host is buildPlatform, target is hostPlatform
403 "--host=${buildStdenv.buildPlatform.config}"
404 "--target=${buildStdenv.hostPlatform.config}"
405 ]
406 # LTO is done using clang and lld on Linux.
407 ++ lib.optionals ltoSupport [
408 "--enable-lto=cross" # Cross-Language LTO
409 "--enable-linker=lld"
410 ]
411 # elf-hack is broken when using clang+lld:
412 # https://bugzilla.mozilla.org/show_bug.cgi?id=1482204
413 ++ lib.optional (ltoSupport && (buildStdenv.isAarch32 || buildStdenv.isi686 || buildStdenv.isx86_64)) "--disable-elf-hack"
414 ++ lib.optional (!drmSupport) "--disable-eme"
415 ++ lib.optional (allowAddonSideload) "--allow-addon-sideload"
416 ++ [
417 (enableFeature alsaSupport "alsa")
418 (enableFeature crashreporterSupport "crashreporter")
419 (enableFeature ffmpegSupport "ffmpeg")
420 (enableFeature geolocationSupport "necko-wifi")
421 (enableFeature gssSupport "negotiateauth")
422 (enableFeature jackSupport "jack")
423 (enableFeature jemallocSupport "jemalloc")
424 (enableFeature pulseaudioSupport "pulseaudio")
425 (enableFeature sndioSupport "sndio")
426 (enableFeature webrtcSupport "webrtc")
427 (enableFeature debugBuild "debug")
428 (if debugBuild then "--enable-profiling" else "--enable-optimize")
429 # --enable-release adds -ffunction-sections & LTO that require a big amount
430 # of RAM, and the 32-bit memory space cannot handle that linking
431 (enableFeature (!debugBuild && !stdenv.is32bit) "release")
432 (enableFeature enableDebugSymbols "debug-symbols")
433 ]
434 ++ lib.optionals enableDebugSymbols [ "--disable-strip" "--disable-install-strip" ]
435 ++ lib.optional enableOfficialBranding "--enable-official-branding"
436 ++ lib.optional (branding != null) "--with-branding=${branding}"
437 ++ extraConfigureFlags;
438
439 buildInputs = [
440 bzip2
441 dbus
442 dbus-glib
443 file
444 fontconfig
445 freetype
446 glib
447 gtk3
448 libffi
449 libGL
450 libGLU
451 libevent
452 libjpeg
453 libpng
454 libstartup_notification
455 libvpx
456 libwebp
457 nasm
458 nspr
459 pango
460 perl
461 xorg.libX11
462 xorg.libXcursor
463 xorg.libXdamage
464 xorg.libXext
465 xorg.libXft
466 xorg.libXi
467 xorg.libXrender
468 xorg.libXt
469 xorg.libXtst
470 xorg.pixman
471 xorg.xorgproto
472 zip
473 zlib
474 ]
475 # icu73 changed how it follows symlinks which breaks in the firefox sandbox
476 # https://bugzilla.mozilla.org/show_bug.cgi?id=1839287
477 ++ [ (if (lib.versionAtLeast version "115") then icu else icu72) ]
478 ++ [ (if (lib.versionAtLeast version "116") then nss_latest else nss_esr/*3.90*/) ]
479 ++ lib.optional alsaSupport alsa-lib
480 ++ lib.optional jackSupport libjack2
481 ++ lib.optional pulseaudioSupport libpulseaudio # only headers are needed
482 ++ lib.optional sndioSupport sndio
483 ++ lib.optional gssSupport libkrb5
484 ++ lib.optionals waylandSupport [ libxkbcommon libdrm ]
485 ++ lib.optional jemallocSupport jemalloc
486 ++ extraBuildInputs;
487
488 profilingPhase = lib.optionalString pgoSupport ''
489 # Package up Firefox for profiling
490 ./mach package
491
492 # Run profiling
493 (
494 export HOME=$TMPDIR
495 export LLVM_PROFDATA=llvm-profdata
496 export JARLOG_FILE="$TMPDIR/jarlog"
497
498 xvfb-run -w 10 -s "-screen 0 1920x1080x24" \
499 ./mach python ./build/pgo/profileserver.py
500 )
501
502 # Copy profiling data to a place we can easily reference
503 cp ./merged.profdata $TMPDIR/merged.profdata
504
505 # Clean build dir
506 ./mach clobber
507 '';
508
509 preBuild = ''
510 cd mozobj
511 '' + lib.optionalString (lib.versionAtLeast version "120") ''
512 # https://bugzilla.mozilla.org/show_bug.cgi?id=1864083
513 export NIX_CFLAGS_COMPILE="$NIX_CFLAGS_COMPILE $(pkg-config dbus-1 --cflags)"
514 '';
515
516 postBuild = ''
517 cd ..
518 '';
519
520 makeFlags = extraMakeFlags;
521 separateDebugInfo = enableDebugSymbols;
522 enableParallelBuilding = true;
523 env = lib.optionalAttrs stdenv.hostPlatform.isMusl {
524 # Firefox relies on nonstandard behavior of the glibc dynamic linker. It re-uses
525 # previously loaded libraries even though they are not in the rpath of the newly loaded binary.
526 # On musl we have to explicity set the rpath to include these libraries.
527 LDFLAGS = "-Wl,-rpath,${placeholder "out"}/lib/${binaryName}";
528 };
529
530 # tests were disabled in configureFlags
531 doCheck = false;
532
533 # Generate build symbols once after the final build
534 # https://firefox-source-docs.mozilla.org/crash-reporting/uploading_symbol.html
535 preInstall = lib.optionalString crashreporterSupport ''
536 ./mach buildsymbols
537 mkdir -p $symbols/
538 cp mozobj/dist/*.crashreporter-symbols.zip $symbols/
539 '' + ''
540 cd mozobj
541 '';
542
543 postInstall = ''
544 # Install distribution customizations
545 install -Dvm644 ${distributionIni} $out/lib/${binaryName}/distribution/distribution.ini
546 install -Dvm644 ${defaultPrefsFile} $out/lib/${binaryName}/browser/defaults/preferences/nixos-default-prefs.js
547
548 '' + lib.optionalString buildStdenv.isLinux ''
549 # Remove SDK cruft. FIXME: move to a separate output?
550 rm -rf $out/share/idl $out/include $out/lib/${binaryName}-devel-*
551
552 # Needed to find Mozilla runtime
553 gappsWrapperArgs+=(--argv0 "$out/bin/.${binaryName}-wrapped")
554 '';
555
556 postFixup = lib.optionalString crashreporterSupport ''
557 patchelf --add-rpath "${lib.makeLibraryPath [ curl ]}" $out/lib/${binaryName}/crashreporter
558 '';
559
560 doInstallCheck = true;
561 installCheckPhase = ''
562 # Some basic testing
563 "$out/bin/${binaryName}" --version
564 '';
565
566 passthru = {
567 inherit application extraPatches;
568 inherit updateScript;
569 inherit alsaSupport;
570 inherit binaryName;
571 inherit jackSupport;
572 inherit pipewireSupport;
573 inherit sndioSupport;
574 inherit nspr;
575 inherit ffmpegSupport;
576 inherit gssSupport;
577 inherit tests;
578 inherit gtk3;
579 inherit wasiSysRoot;
580 version = packageVersion;
581 } // extraPassthru;
582
583 hardeningDisable = [ "format" ]; # -Werror=format-security
584
585 # the build system verifies checksums of the bundled rust sources
586 # ./third_party/rust is be patched by our libtool fixup code in stdenv
587 # unfortunately we can't just set this to `false` when we do not want it.
588 # See https://github.com/NixOS/nixpkgs/issues/77289 for more details
589 # Ideally we would figure out how to tell the build system to not
590 # care about changed hashes as we are already doing that when we
591 # fetch the sources. Any further modifications of the source tree
592 # is on purpose by some of our tool (or by accident and a bug?).
593 dontFixLibtool = true;
594
595 # on aarch64 this is also required
596 dontUpdateAutotoolsGnuConfigScripts = true;
597
598 requiredSystemFeatures = [ "big-parallel" ];
599}