3 , packageVersion ? version
6 , binaryName ? "firefox"
7 , application ? "browser"
8 , applicationName ? "Mozilla Firefox"
10 , requireSigning ? true
11 , allowAddonSideload ? false
16 , extraNativeBuildInputs ? []
17 , extraConfigureFlags ? []
18 , extraBuildInputs ? []
25 # Rename the variables to prevent infinite recursion
26 requireSigningDefault = requireSigning;
27 allowAddonSideloadDefault = allowAddonSideload;
29 # Specifying --(dis|en)able-elf-hack on a platform for which it's not implemented will give `--disable-elf-hack is not available in this configuration`
30 # This is declared here because it's used in the default value of elfhackSupport
31 isElfhackPlatform = stdenv: stdenv.hostPlatform.isElf &&
32 (stdenv.hostPlatform.isi686 || stdenv.hostPlatform.isx86_64 || stdenv.hostPlatform.isAarch32 || stdenv.hostPlatform.isAarch64);
50 , pkgsCross # wasm32 rlbox
78 , libstartup_notification
94 , rsync # used when preparing .app directory
98 ## addon signing/sideloading
99 , requireSigning ? requireSigningDefault
100 , allowAddonSideload ? allowAddonSideloadDefault
106 # On 32bit platforms, we disable adding "-g" for easier linking.
107 , enableDebugSymbols ? !stdenv.hostPlatform.is32bit
109 ## optional libraries
111 , alsaSupport ? stdenv.hostPlatform.isLinux, alsa-lib
112 , ffmpegSupport ? true
113 , gssSupport ? true, libkrb5
114 , jackSupport ? stdenv.hostPlatform.isLinux, libjack2
115 , jemallocSupport ? !stdenv.hostPlatform.isMusl, jemalloc
116 , ltoSupport ? (stdenv.hostPlatform.isLinux && stdenv.hostPlatform.is64bit && !stdenv.hostPlatform.isRiscV), overrideCC, buildPackages
117 , pgoSupport ? (stdenv.hostPlatform.isLinux && stdenv.hostPlatform == stdenv.buildPlatform), xvfb-run
118 , elfhackSupport ? isElfhackPlatform stdenv && !(stdenv.hostPlatform.isMusl && stdenv.hostPlatform.isAarch64)
119 , pipewireSupport ? waylandSupport && webrtcSupport
120 , pulseaudioSupport ? stdenv.hostPlatform.isLinux, libpulseaudio
121 , sndioSupport ? stdenv.hostPlatform.isLinux, sndio
122 , waylandSupport ? true, libxkbcommon, libdrm
124 ## privacy-related options
126 , privacySupport ? false
128 # WARNING: NEVER set any of the options below to `true` by default.
129 # Set to `!privacySupport` or `false`.
131 , crashreporterSupport ? !privacySupport && !stdenv.hostPlatform.isRiscV && !stdenv.hostPlatform.isMusl, curl
132 , geolocationSupport ? !privacySupport
133 , googleAPISupport ? geolocationSupport
134 , mlsAPISupport ? geolocationSupport
135 , webrtcSupport ? !privacySupport
137 # digital rights managemewnt
139 # This flag controls whether Firefox will show the nagbar, that allows
140 # users at runtime the choice to enable Widevine CDM support when a site
142 # Controlling the nagbar and widevine CDM at runtime is possible by setting
143 # `browser.eme.ui.enabled` and `media.gmp-widevinecdm.enabled` accordingly
146 # As stated by Sylvestre Ledru (@sylvestre) on Nov 22, 2017 at
147 # https://github.com/NixOS/nixpkgs/issues/31843#issuecomment-346372756 we
148 # have permission to use the official firefox branding.
150 # For purposes of documentation the statement of @sylvestre:
151 # > As the person who did part of the work described in the LWN article
152 # > and release manager working for Mozilla, I can confirm the statement
154 # > https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=815006
156 # > @garbas shared with me the list of patches applied for the Nix package.
157 # > As they are just for portability and tiny modifications, they don't
158 # > alter the experience of the product. In parallel, Rok also shared the
159 # > build options. They seem good (even if I cannot judge the quality of the
160 # > packaging of the underlying dependencies like sqlite, png, etc).
161 # > Therefor, as long as you keep the patch queue sane and you don't alter
162 # > the experience of Firefox users, you won't have any issues using the
163 # > official branding.
164 , enableOfficialBranding ? true
167 assert stdenv.cc.libc or null != null;
168 assert pipewireSupport -> !waylandSupport || !webrtcSupport -> throw "${pname}: pipewireSupport requires both wayland and webrtc support.";
169 assert elfhackSupport -> isElfhackPlatform stdenv;
172 inherit (lib) enableFeature;
174 # Target the LLVM version that rustc is built with for LTO.
175 llvmPackages0 = rustc.llvmPackages;
176 llvmPackagesBuildBuild0 = pkgsBuildBuild.rustc.llvmPackages;
178 # Force the use of lld and other llvm tools for LTO
179 llvmPackages = llvmPackages0.override {
180 bootBintoolsNoLibc = null;
183 llvmPackagesBuildBuild = llvmPackagesBuildBuild0.override {
184 bootBintoolsNoLibc = null;
188 # LTO requires LLVM bintools including ld.lld and llvm-ar.
189 buildStdenv = overrideCC llvmPackages.stdenv (llvmPackages.stdenv.cc.override {
190 bintools = if ltoSupport then buildPackages.rustc.llvmPackages.bintools else stdenv.cc.bintools;
193 # Compile the wasm32 sysroot to build the RLBox Sandbox
194 # https://hacks.mozilla.org/2021/12/webassembly-and-back-again-fine-grained-sandboxing-in-firefox-95/
195 # We only link c++ libs here, our compiler wrapper can find wasi libc and crt itself.
196 wasiSysRoot = runCommand "wasi-sysroot" {} ''
197 mkdir -p $out/lib/wasm32-wasi
198 for lib in ${pkgsCross.wasi32.llvmPackages.libcxx}/lib/*; do
199 ln -s $lib $out/lib/wasm32-wasi
203 distributionIni = pkgs.writeText "distribution.ini" (lib.generators.toINI {} {
204 # Some light branding indicating this build uses our distro preferences
208 about = "${applicationName} for NixOS";
211 # These values are exposed through telemetry
212 "app.distributor" = "nixos";
213 "app.distributor.channel" = "nixpkgs";
218 "geo.provider.network.url" = {
219 value = "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%";
220 reason = "Use MLS by default for geolocation, since our Google API Keys are not working";
224 defaultPrefsFile = pkgs.writeText "nixos-default-prefs.js" (lib.concatStringsSep "\n" (lib.mapAttrsToList (key: value: ''
226 pref("${key}", ${builtins.toJSON value.value});
229 toolkit = if stdenv.hostPlatform.isDarwin then "cairo-cocoa" else "cairo-gtk3${lib.optionalString waylandSupport "-wayland"}";
233 buildStdenv.mkDerivation {
234 pname = "${pname}-unwrapped";
235 version = packageVersion;
237 inherit src unpackPhase meta;
242 ++ lib.optionals crashreporterSupport [ "symbols" ];
244 # Add another configure-build-profiling run before the final configure phase if we build with pgo
245 preConfigurePhases = lib.optionals pgoSupport [
251 patches = lib.optionals (lib.versionAtLeast version "111" && lib.versionOlder version "133") [ ./env_var_for_system_dir-ff111.patch ]
252 ++ lib.optionals (lib.versionAtLeast version "133") [ ./env_var_for_system_dir-ff133.patch ]
253 ++ lib.optionals (lib.versionAtLeast version "96" && lib.versionOlder version "121") [ ./no-buildconfig-ffx96.patch ]
254 ++ lib.optionals (lib.versionAtLeast version "121") [ ./no-buildconfig-ffx121.patch ]
255 ++ lib.optionals (lib.versionOlder version "128.2" || (lib.versionAtLeast version "129" && lib.versionOlder version "130")) [
257 # https://bugzilla.mozilla.org/show_bug.cgi?id=1912663
258 name = "cbindgen-0.27.0-compat.patch";
259 url = "https://hg.mozilla.org/integration/autoland/raw-rev/98cd34c7ff57";
260 hash = "sha256-MqgWHgbDedVzDOqY2/fvCCp+bGwFBHqmaJLi/mllZug=";
263 ++ lib.optionals (lib.versionOlder version "122") [ ./bindgen-0.64-clang-18.patch ]
264 ++ lib.optionals (lib.versionOlder version "123") [
266 name = "clang-18.patch";
267 url = "https://hg.mozilla.org/mozilla-central/raw-rev/ba6abbd36b496501cea141e17b61af674a18e279";
268 hash = "sha256-2IpdSyye3VT4VB95WurnyRFtdN1lfVtYpgEiUVhfNjw=";
271 ++ lib.optionals ((lib.versionAtLeast version "129" && lib.versionOlder version "134") || lib.versionOlder version "128.6.0") [
272 # Python 3.12.8 compat
273 # https://bugzilla.mozilla.org/show_bug.cgi?id=1935621
274 # https://phabricator.services.mozilla.com/D231480
275 ./mozbz-1935621-attachment-9442305.patch
278 # LLVM 19 turned on WASM reference types by default, exposing a bug
279 # that broke the Mozilla WASI build. Supposedly, it has been fixed
280 # upstream in LLVM, but the build fails in the same way for us even
281 # with LLVM 19 versions that contain the upstream patch.
283 # Apply the temporary patch Mozilla used to work around this bug
284 # for now until someone can investigate what’s going on here.
286 # TODO: Please someone figure out what’s up with this.
288 # See: <https://bugzilla.mozilla.org/show_bug.cgi?id=1905251>
289 # See: <https://github.com/llvm/llvm-project/pull/97451>
291 name = "wasi-sdk-disable-reference-types.patch";
292 url = "https://hg.mozilla.org/integration/autoland/raw-rev/23a9f6555c7c";
293 hash = "sha256-CRywalJlRMFVLITEYXxpSq3jLPbUlWKNRHuKLwXqQfU=";
295 # Fix for missing vector header on macOS
296 # https://bugzilla.mozilla.org/show_bug.cgi?id=1939405
297 ./firefox-mac-missing-vector-header.patch
302 rm -rf obj-x86_64-pc-linux-gnu
303 patchShebangs mach build
307 # Ignore trivial whitespace changes in patches, this fixes compatibility of
308 # ./env_var_for_system_dir-*.patch with Firefox >=65 without having to track
310 patchFlags = [ "-p1" "-l" ];
312 # if not explicitly set, wrong cc from buildStdenv would be used
313 HOST_CC = "${llvmPackagesBuildBuild.stdenv.cc}/bin/cc";
314 HOST_CXX = "${llvmPackagesBuildBuild.stdenv.cc}/bin/c++";
316 nativeBuildInputs = [
320 llvmPackagesBuildBuild.bintools
326 rustPlatform.bindgenHook
332 ++ lib.optionals (!stdenv.hostPlatform.isDarwin) [ pkg-config ]
333 ++ lib.optionals stdenv.hostPlatform.isDarwin [ rsync ]
334 ++ lib.optionals crashreporterSupport [ dump_syms patchelf ]
335 ++ lib.optionals pgoSupport [ xvfb-run ]
336 ++ extraNativeBuildInputs;
338 setOutputFlags = false; # `./mach configure` doesn't understand `--*dir=` flags.
341 # Runs autoconf through ./mach configure in configurePhase
342 configureScript="$(realpath ./mach) configure"
344 # Set reproducible build date; https://bugzilla.mozilla.org/show_bug.cgi?id=885777#c21
345 export MOZ_BUILD_DATE=$(head -n1 sourcestamp.txt)
347 # Set predictable directories for build and state
348 export MOZ_OBJDIR=$(pwd)/objdir
349 export MOZBUILD_STATE_PATH=$TMPDIR/mozbuild
351 # Don't try to send libnotify notifications during build
354 # Set consistent remoting name to ensure wmclass matches with desktop file
355 export MOZ_APP_REMOTINGNAME="${binaryName}"
357 # AS=as in the environment causes build failure
358 # https://bugzilla.mozilla.org/show_bug.cgi?id=1497286
362 export MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE=system
364 # RBox WASM Sandboxing
365 export WASM_CC=${pkgsCross.wasi32.stdenv.cc}/bin/${pkgsCross.wasi32.stdenv.cc.targetPrefix}cc
366 export WASM_CXX=${pkgsCross.wasi32.stdenv.cc}/bin/${pkgsCross.wasi32.stdenv.cc.targetPrefix}c++
367 '' + lib.optionalString pgoSupport ''
368 if [ -e "$TMPDIR/merged.profdata" ]; then
369 echo "Configuring with profiling data"
370 for i in "''${!configureFlagsArray[@]}"; do
371 if [[ ''${configureFlagsArray[i]} = "--enable-profile-generate=cross" ]]; then
372 unset 'configureFlagsArray[i]'
375 appendToVar configureFlags --enable-profile-use=cross
376 appendToVar configureFlags --with-pgo-profile-path=$TMPDIR/merged.profdata
377 appendToVar configureFlags --with-pgo-jarlog=$TMPDIR/jarlog
378 ${lib.optionalString stdenv.hostPlatform.isMusl ''
379 LDFLAGS="$OLD_LDFLAGS"
383 echo "Configuring to generate profiling data"
384 configureFlagsArray+=(
385 "--enable-profile-generate=cross"
387 ${lib.optionalString stdenv.hostPlatform.isMusl
388 # Set the rpath appropriately for the profiling run
389 # During the profiling run, loading libraries from $out would fail,
390 # since the profiling build has not been installed to $out
392 OLD_LDFLAGS="$LDFLAGS"
393 LDFLAGS="-Wl,-rpath,$(pwd)/objdir/dist/${binaryName}"
396 '' + lib.optionalString googleAPISupport ''
397 # Google API key used by Chromium and Firefox.
398 # Note: These are for NixOS/nixpkgs use ONLY. For your own distribution,
399 # please get your own set of keys at https://www.chromium.org/developers/how-tos/api-keys/.
400 echo "AIzaSyDGi15Zwl11UNe6Y-5XW_upsfyw31qwZPI" > $TMPDIR/google-api-key
401 # 60.5+ & 66+ did split the google API key arguments: https://bugzilla.mozilla.org/show_bug.cgi?id=1531176
402 configureFlagsArray+=("--with-google-location-service-api-keyfile=$TMPDIR/google-api-key")
403 configureFlagsArray+=("--with-google-safebrowsing-api-keyfile=$TMPDIR/google-api-key")
404 '' + lib.optionalString mlsAPISupport ''
405 # Mozilla Location services API key
406 # Note: These are for NixOS/nixpkgs use ONLY. For your own distribution,
407 # please get your own set of keys at https://location.services.mozilla.com/api.
408 echo "dfd7836c-d458-4917-98bb-421c82d3c8a0" > $TMPDIR/mls-api-key
409 configureFlagsArray+=("--with-mozilla-api-keyfile=$TMPDIR/mls-api-key")
410 '' + lib.optionalString (enableOfficialBranding && !stdenv.hostPlatform.is32bit) ''
411 export MOZILLA_OFFICIAL=1
412 '' + lib.optionalString (!requireSigning) ''
413 export MOZ_REQUIRE_SIGNING=
414 '' + lib.optionalString stdenv.hostPlatform.isMusl ''
415 # linking firefox hits the vm.max_map_count kernel limit with the default musl allocator
416 # TODO: Default vm.max_map_count has been increased, retest without this
417 export LD_PRELOAD=${mimalloc}/lib/libmimalloc.so
420 # firefox has a different definition of configurePlatforms from nixpkgs, see configureFlags
421 configurePlatforms = [ ];
426 "--enable-application=${application}"
427 "--enable-default-toolkit=${toolkit}"
428 "--with-distribution-id=org.nixos"
429 "--with-libclang-path=${lib.getLib llvmPackagesBuildBuild.libclang}/lib"
430 "--with-wasi-sysroot=${wasiSysRoot}"
431 # for firefox, host is buildPlatform, target is hostPlatform
432 "--host=${buildStdenv.buildPlatform.config}"
433 "--target=${buildStdenv.hostPlatform.config}"
435 # LTO is done using clang and lld on Linux.
436 ++ lib.optionals ltoSupport [
437 "--enable-lto=cross,full" # Cross-Language LTO
438 "--enable-linker=lld"
440 ++ lib.optional (isElfhackPlatform stdenv) (enableFeature elfhackSupport "elf-hack")
441 ++ lib.optional (!drmSupport) "--disable-eme"
442 ++ lib.optional (allowAddonSideload) "--allow-addon-sideload"
443 ++ lib.optionals (!stdenv.hostPlatform.isDarwin) [
444 # MacOS builds use bundled versions of libraries: https://bugzilla.mozilla.org/show_bug.cgi?id=1776255
445 "--enable-system-pixman"
449 "--with-system-libevent"
450 "--with-system-libvpx"
453 "--with-system-png" # needs APNG support
457 # These options are not available on MacOS, even --disable-*
458 (enableFeature alsaSupport "alsa")
459 (enableFeature jackSupport "jack")
460 (enableFeature pulseaudioSupport "pulseaudio")
461 (enableFeature sndioSupport "sndio")
464 (enableFeature crashreporterSupport "crashreporter")
465 (enableFeature ffmpegSupport "ffmpeg")
466 (enableFeature geolocationSupport "necko-wifi")
467 (enableFeature gssSupport "negotiateauth")
468 (enableFeature jemallocSupport "jemalloc")
469 (enableFeature webrtcSupport "webrtc")
471 (enableFeature debugBuild "debug")
472 (if debugBuild then "--enable-profiling" else "--enable-optimize")
473 # --enable-release adds -ffunction-sections & LTO that require a big amount
474 # of RAM, and the 32-bit memory space cannot handle that linking
475 (enableFeature (!debugBuild && !stdenv.hostPlatform.is32bit) "release")
476 (enableFeature enableDebugSymbols "debug-symbols")
478 ++ lib.optionals enableDebugSymbols [ "--disable-strip" "--disable-install-strip" ]
479 ++ lib.optional enableOfficialBranding "--enable-official-branding"
480 ++ lib.optional (branding != null) "--with-branding=${branding}"
481 ++ extraConfigureFlags;
488 libstartup_notification
493 ++ lib.optionals stdenv.hostPlatform.isDarwin [
497 ++ (lib.optionals (!stdenv.hostPlatform.isDarwin) ([
524 (if (lib.versionAtLeast version "116") then nss_latest else nss_esr/*3.90*/)
525 ] ++ lib.optional alsaSupport alsa-lib
526 ++ lib.optional jackSupport libjack2
527 ++ lib.optional pulseaudioSupport libpulseaudio # only headers are needed
528 ++ lib.optional sndioSupport sndio
529 ++ lib.optionals waylandSupport [ libxkbcommon libdrm ]
531 # icu74 fails to build on 127 and older
532 # https://bugzilla.mozilla.org/show_bug.cgi?id=1862601
533 ++ [ (if (lib.versionAtLeast version "134") then icu74 else icu73) ]
534 ++ lib.optional gssSupport libkrb5
535 ++ lib.optional jemallocSupport jemalloc
538 profilingPhase = lib.optionalString pgoSupport ''
539 # Package up Firefox for profiling
545 export LLVM_PROFDATA=llvm-profdata
546 export JARLOG_FILE="$TMPDIR/jarlog"
548 xvfb-run -w 10 -s "-screen 0 1920x1080x24" \
549 ./mach python ./build/pgo/profileserver.py
552 # Copy profiling data to a place we can easily reference
553 cp ./merged.profdata $TMPDIR/merged.profdata
567 makeFlags = extraMakeFlags;
568 separateDebugInfo = enableDebugSymbols;
569 enableParallelBuilding = true;
570 env = lib.optionalAttrs stdenv.hostPlatform.isMusl {
571 # Firefox relies on nonstandard behavior of the glibc dynamic linker. It re-uses
572 # previously loaded libraries even though they are not in the rpath of the newly loaded binary.
573 # On musl we have to explicity set the rpath to include these libraries.
574 LDFLAGS = "-Wl,-rpath,${placeholder "out"}/lib/${binaryName}";
577 # tests were disabled in configureFlags
580 # Generate build symbols once after the final build
581 # https://firefox-source-docs.mozilla.org/crash-reporting/uploading_symbol.html
582 preInstall = lib.optionalString crashreporterSupport ''
585 cp objdir/dist/*.crashreporter-symbols.zip $symbols/
590 # The target will prepare .app bundle
591 installTargets = lib.optionalString stdenv.hostPlatform.isDarwin "stage-package";
593 postInstall = lib.optionalString stdenv.hostPlatform.isDarwin ''
594 mkdir -p $out/Applications
595 cp -r dist/${binaryName}/*.app $out/Applications
597 appBundlePath=(dist/${binaryName}/*.app)
598 appBundle=''${appBundlePath[0]#dist/${binaryName}}
599 resourceDir=$out/Applications/$appBundle/Contents/Resources
601 '' + lib.optionalString (!stdenv.hostPlatform.isDarwin) ''
602 # Remove SDK cruft. FIXME: move to a separate output?
603 rm -rf $out/share/idl $out/include $out/lib/${binaryName}-devel-*
605 # Needed to find Mozilla runtime
606 gappsWrapperArgs+=(--argv0 "$out/bin/.${binaryName}-wrapped")
608 resourceDir=$out/lib/${binaryName}
610 # Install distribution customizations
611 install -Dvm644 ${distributionIni} "$resourceDir/distribution/distribution.ini"
612 install -Dvm644 ${defaultPrefsFile} "$resourceDir/browser/defaults/preferences/nixos-default-prefs.js"
617 postFixup = lib.optionalString (crashreporterSupport && buildStdenv.hostPlatform.isLinux) ''
618 patchelf --add-rpath "${lib.makeLibraryPath [ curl ]}" $out/lib/${binaryName}/crashreporter
622 doInstallCheck = true;
623 installCheckPhase = lib.optionalString buildStdenv.hostPlatform.isDarwin ''
624 bindir=$out/Applications/$appBundle/Contents/MacOS
625 '' + lib.optionalString (!buildStdenv.hostPlatform.isDarwin) ''
628 "$bindir/${binaryName}" --version
632 inherit application extraPatches;
633 inherit updateScript;
636 inherit requireSigning allowAddonSideload;
638 inherit pipewireSupport;
639 inherit sndioSupport;
641 inherit ffmpegSupport;
646 version = packageVersion;
649 hardeningDisable = [ "format" ]; # -Werror=format-security
651 # the build system verifies checksums of the bundled rust sources
652 # ./third_party/rust is be patched by our libtool fixup code in stdenv
653 # unfortunately we can't just set this to `false` when we do not want it.
654 # See https://github.com/NixOS/nixpkgs/issues/77289 for more details
655 # Ideally we would figure out how to tell the build system to not
656 # care about changed hashes as we are already doing that when we
657 # fetch the sources. Any further modifications of the source tree
658 # is on purpose by some of our tool (or by accident and a bug?).
659 dontFixLibtool = true;
661 # on aarch64 this is also required
662 dontUpdateAutotoolsGnuConfigScripts = true;
664 requiredSystemFeatures = [ "big-parallel" ];