As part of my work on the Stylo / Quantum CSS team at Mozilla, I needed to be able to test changes to Firefox that only affect Linux 32-bit builds. These days, I believe you essentially have to use a 64-bit host to build Firefox to avoid OOM issues during linking and potentially other steps, so this means some form of cross-compiling from a Linux 64-bit host to a Linux 32-bit target.
I already had a Linux 64-bit machine running Ubuntu 16.04 LTS, so I set about attempting to make it build Firefox targeting Linux 32-bit.
I should note that I only use Linux occasionally at the moment, so there could certainly be a better solution than the one I describe. Also, I recreated these steps after the fact, so I might have missed something. Please let me know in the comments.
This article assumes you are already set up to build Firefox when targeting 64-bit.
Multiarch Packages (Or: How It’s Supposed to Work)
Recent versions of Debian and Ubuntu support the concept of “multiarch packages” which are intended to allow installing multiple architectures together to support use cases including… cross-compiling! Great, sounds like just the thing we need.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
Well, that doesn’t look good. It appears some of the Gecko libraries we need aren’t happy about being installed for multiple architectures.
Switch Approaches to
Since multiarch packages don’t appear to be working here, I looked around for other approaches. Ideally, I would have something fairly self-contained so that it would be easy to remove when I no longer need 32-bit support.
One approach to multiple architectures that has been around for a while is to
create a chroot environment: effectively, a separate installation of
Linux for a different architecture. A utility like
schroot can then be used
to issue the
chroot(2) system call which makes the current session believe
this sub-installation is the root filesystem.
schroot so we’ll be able to enter the chroot once it’s set up:
There are several different types of chroots you can use with
We’ll use the
directory type, as it’s the simplest to understand (just another
directory on the existing filesystem), and it will make it simpler to expose a
few things to the host later on.
You can place the directory wherever, but some existing filesystems are mapped
into the chroot for convenience, so avoiding
/home is probably a good idea. I
We need to update
schroot.conf to configure the new chroot:
1 2 3 4 5 6 7 8 9 10 11
personality is important to set for this multi-arch use case.
(Make sure to replace the user names with your own!)
Firefox will want access to shared memory as well, so we’ll need to add that to the set of mapped filesystems in the chroot:
1 2 3
Now we need to install the 32-bit system inside the chroot. We can do
that with a utility called
This will fetch all the packages for a 32-bit installation and place them in the
chroot. For a cross-arch bootstrap, we need to add
--foreign to skip the
unpacking step, which we will do momentarily from inside the chroot.
--variant=buildd will help us out a bit by including common build tools.
To finish installation, we have to enter the chroot. You can enter the chroot
schroot and it remains active until you
exit. Any snippets that say
(chroot) instead of
(host) are meant to be run inside the chroot.
So, inside the chroot, run the second stage of
debootstrap to actually unpack
Let’s double-check that things are working like we expect:
Great, we’re getting closer!
Now that we have a basic 32-bit installation, let’s install the packages we need
for development. The
apt source list inside the chroot is pretty bare bones,
so we’ll want to expand it a bit to reach everything we need:
1 2 3 4 5
Let’s grab the same packages from before (without
:i386 since that’s the
default inside the chroot):
You may need to install the 32-bit version of your graphics card’s GL library to get reasonable graphics output when running in the 32-bit environment.
We’ll also want to have access to the X display inside the chroot. The simple way to achieve this is to disable X security in the host and expose the same display in the chroot:
We can verify that we have accelerated graphics:
1 2 3
In order for the host to build Firefox for the 32-bit target, it needs to access various 32-bit libraries and include files. We already have these installed in the chroot, so let’s cheat and expose them to the host via symlinks into the chroot’s file structure:
1 2 3
We also need Rust to be able to target 32-bit from the host, so let’s install support for that:
We’ll need a specialized
.mozconfig for Firefox to target 32-bit. Something
like the following:
1 2 3 4 5 6 7 8 9 10 11 12 13
This was adapted from the
mozconfig.linux32 used for official 32-bit
builds. I modified the
PKG_CONFIG_PATH to point at more 32-bit files
installed inside the chroot, similar to the library and include changes above.
Now, we should be able to build successfully:
Then, from the chroot, you can run Firefox and other tests:
1. It’s commonly suggested that people should use
bootstrap to install the Firefox build dependencies, so feel free to try that
if you wish. I dislike scripts that install system packages, so I’ve done it
manually here. The bootstrap script would likely need various adjustments to
support this use case. ↩