Reproducing the Linux builds of Firefox 68
Starting with Firefox 68, the Linux builds shipped by Mozilla should be reproducible (it is not currently automatically validated that it definitely is, but 68.0 is). These builds are optimized with Profile Guided Optimization, and the profile data was not kept and published until recently, which is why they weren't reproducible until now.
The following instructions require running Docker on a Linux host (this may or may not work on a non-Linux host, I don't know what e.g. Docker for Mac does, and if the docker support in the mach command works with it). I'll try to make them generic enough that they may apply to any subsequent release of Firefox.
- Clone either the mozilla-unified or mozilla-release repository. You can use Mercurial or Git (with git-cinnabar), it doesn't matter.
- Checkout the
FIREFOX_68_0_RELEASE
tag and find out what its Mercurial changeset id is (it is 353628fec415324ca6aa333ab6c47d447ecc128e). - Open the Taskcluster index tool in a browser tab.
- In the input field type or copy/paste
gecko.v2.mozilla-release.shippable.revision.353628fec415324ca6aa333ab6c47d447ecc128e.firefox.linux64-opt
and press the Enter key. (replace 353628fec415324ca6aa333ab6c47d447ecc128e with the right revision if you're trying for another release) - This will fill the "Indexed Task" pane, where you will find a TaskId. Follow the link there, it will bring you to the corresponding Task Run Logs
- Switch to the Task Details
- Scroll down to the "Dependencies" list, and check the task name that begins with "build-docker-image". For the Firefox 68 build task, it is
build-docker-image-debian7-amd64-build
. - Take that name, remove the "build-docker-image-" prefix, and run the following command, from inside the repository, to download the corresponding docker image:
$ ./mach taskcluster-load-image debian7-amd64-build
Obviously, replace
debian7-amd64-build
with whatever you found in the task dependencies. The image can also be built from the source tree, but this is out of scope for this post. - The command output will give you a
docker run -ti ...
command to try. Run it. It will open a shell in the docker image. - From the docker shell, run the following commands:
$ echo no-api-key > /builds/mozilla-desktop-geoloc-api.key $ echo no-api-key > /builds/sb-gapi.data $ echo no-api-key > /builds/gls-gapi.data
Or replace
no-api-key
with the actual keys if you have them. - Back to the Task Details, check the
env
part of the "Payload". You'll need to export all these variables with the corresponding values. e.g.$ export EXTRA_MOZHARNESS_CONFIG='{"update_channel": "release", "mozconfig_variant": "release"}' $ export GECKO_BASE_REPOSITORY='https://hg.mozilla.org/mozilla-unified' $ export GECKO_HEAD_REPOSITORY='https://hg.mozilla.org/releases/mozilla-release' ...
- Set the missing
TASKCLUSTER_ROOT_URL
environment variable:$ export TASKCLUSTER_ROOT_URL='https://taskcluster.net'
- Change the value of
MOZHARNESS_ACTIONS
to:$ export MOZHARNESS_ACTIONS='build'
The original value contains
get-secrets
, which will try to download fromhttp://taskcluster/
, which will fail with a DNS error, andcheck-test
, which runsmake check
, which is not necessary to get a working Firefox. - Take
command
part of the "Payload", and run that in the docker shell:$ /builds/worker/bin/run-task --gecko-checkout /builds/worker/workspace/build/src -- /builds/worker/workspace/build/src/taskcluster/scripts/builder/build-linux.sh
- Once the build is finished, in another terminal, check what the container id of your running docker container is, and extract the build artifact from there:
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES d234383ba9c7 debian7-amd64-build:be96d1b734e1a152a861ce786861fca6e70bcb996bf67347f5af4f146db157ec "bash" 2 hours ago Up 2 hours nifty_hermann $ docker cp d234383ba9c7:/builds/worker/artifacts/target.tar.bz2 .
(replace
d234383ba9c7
with your container id) - Now you can exit the docker shell. That will remove the container.
After all the above, you can finally compare your target.tar.bz2
to the Linux64 Firefox 68 release. You will find a few inevitable differences:
- The
.chk
files will be different, because they are self-signatures for FIPS mode that are generated with one-time throw-away keys. - The Firefox 68 release contains
.sig
files that your build won't contain. They are signature files, which aren't reproducible outside Mozilla automation for obvious reasons. - Consequently, the
precomplete
file contains instructions for the.sig
files in the Firefox 68 release that won't be in your build. - The
omni.ja
files are different. If you extract them (they are uncompressed zip files with a few tweaks to the format), you'll see the only difference is inmodules/AppConstants.jsm
, for the three API keys you created a file for earlier.
Everything else is identical bit for bit.
All the above is a rather long list of manual steps. Ideally, most of it would be automated. We're not there yet. We only recently got to the point where the profile data is available to make it possible at all. In other words, this is a starting point. It's valuable to know it does work but requires manual steps and what those are.
It is also worth noting that while the above downloads and uses pre-built compilers and other tools, it is also possible to rebuild those, although they likely won't be bit-for-bit identical. But differences in those shouldn't incur differences in Firefox. Replacing the pre-built ones with ones you'd build yourself unfortunately currently requires some more manual work.
As for Windows and Mac builds, long story short, they are not reproducible as of writing. Mac builds are not optimized with PGO, but Windows builds are, and their profile data won't be available until Firefox 69. Both platforms require SDKs that Mozilla can't redistribute per their license (but are otherwise available for download from Microsoft or Apple, respectively), which makes the setup more complex. And in all likeliness, for both platforms, the toolchains are not deterministic yet (that's at least true for Mac). Also, binary signatures would need to be tripped off the executables and libraries before any comparison.
2019-07-11 11:31:22+0900