Compiling Firefox for a RHEL Shared Host

These are the steps I took to compile Firefox so it can run on a RHEL shared hosting server which doesn’t have D-Bus installed and only has GLibc 2.12.

Situation

You want to run headless Firefox on a shared host running RHEL

You don’t have privileged access (e.g. no root)

Your shared host only has GLibc 2.12

Your shared host doesn’t have D-Bus

Why would someone want to run Firefox on a shared host? Firefox can be run as a headless browser (without a GUI) in conjunction with Xvfb to automate interaction in web pages and take screenshots (similar to PhantomJS, but better).

Without yum or rpm available – because the target box is a shared server – uploading the official pre-compiled Firefox binary and support folders (from here) results in an intractable D-Bus problem:

A shared host likely won’t have D-Bus installed, or even the required /var/lib/dbus/machine-id, and it cannot be created by an unprivileged user. Firefox doesn’t actually need D-Bus, but the official pre-compiled binary was compiled with a mode that requires it. The only option is to compile Firefox ourselves with D-Bus support disabled.

If you have elevated privileges on the shared host, you can install dbus, or just do the following with a D-Bus utility: dbus-uuidgen > /var/lib/dbus/machine-id. Having your shared host create this file may allow Firefox to run.

Here are the steps I took to compile Firefox on 64-bit CentOS (essentially identical to RHEL) with D-Bus support disabled, and get it running on a RHEL shared host. Unfortunately this shared host still uses GLibc 2.12 (introduced in 2010) so I had to work around that.

Prerequisites:

To make the compiling easier without negatively affecting an existing system, obtain a VMWare image of CentOS 6.8 from osboxes.org. It already has Firefox pre-installed, but that installation will be removed.

The VMWare image of CentOS doesn’t have internet enabled. Run dhclient -v from root to fix this. Also, be sure VMWare Tools is installed if you use the VMWare image of CentOS.

In my case, I needed to verify the Glibc version with ldd --version to make sure it matches that of the shared host (in this case 2.12).

1

2

[osboxes@localhost~]$ldd--version

ldd(GNU libc)2.12

Before going any further, it’s best to yum update all the packages.

Running yum update on the VMWare image above may take a long time and could require 500+ MB. You may have to reinstall VMWare Tools afterwards.

Firefox sources (5 min)

Let’s first remove the existing Firefox. As root throughout, run this command:

1

yum remove firefox

To get started, download the Firefox Linux source from https://archive.mozilla.org/pub/firefox/releases/. Select the latest stable version (v49.0.1 at this time) and download the tarball from the sources/ folder. As the root user throughout we’ll set up the source files like so:

We’ll eventually, but not yet, run ./mach build from this folder and Firefox will be built in /tmp/firefox-49.0.1/firefox-build-dir.

Mozconfig configuration file (10 s)

To disable D-Bus support, let’s first create the configuration file1 which is used to customize the Firefox build. Still in /tmp/firefox-49.0.1, run the following command which will save a file called mozconfig. Enable or disable settings as desired. Here is what I used:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

cat>mozconfig<<"EOF"

# If you have a multicore machine, all cores will be used by default.

# If desired, you can reduce the number of cores used, e.g. to 1, by

# uncommenting the next line and setting a valid number of CPU cores.

mk_add_options MOZ_MAKE_FLAGS="-j1"

# If you have installed dbus-glib, comment out this line:

ac_add_options--disable-dbus

# If you have installed dbus-glib, and you have installed (or will install)

# wireless-tools, and you wish to use geolocation web services, comment out

# this line

ac_add_options--disable-necko-wifi

# Uncomment this option if you wish to build with gtk+-2

ac_add_options--enable-default-toolkit=cairo-gtk2

# Uncomment these lines if you have installed optional dependencies:

#ac_add_options --enable-system-hunspell

#ac_add_options --enable-startup-notification

# Comment out following option if you have PulseAudio installed

ac_add_options--disable-pulseaudio

# If you have installed GConf, comment out this line

ac_add_options--disable-gconf

# Comment out following options if you have not installed

# recommended dependencies:

#ac_add_options --enable-system-sqlite

#ac_add_options --with-system-libevent

#ac_add_options --with-system-libvpx

#ac_add_options --with-system-nspr

#ac_add_options --with-system-nss

#ac_add_options --with-system-icu

# If you are going to apply the patch for system graphite

# and system harfbuzz, uncomment these lines:

#ac_add_options --with-system-graphite2

#ac_add_options --with-system-harfbuzz

# Stripping is now enabled by default.

# Uncomment these lines if you need to run a debugger:

#ac_add_options --disable-strip

#ac_add_options --disable-install-strip

# The BLFS editors recommend not changing anything below this line:

ac_add_options--prefix=/user/ff

ac_add_options--enable-application=browser

ac_add_options--disable-crashreporter

ac_add_options--disable-updater

ac_add_options--disable-tests

ac_add_options--enable-optimize

ac_add_options--enable-gio

ac_add_options--enable-official-branding

ac_add_options--enable-safe-browsing

ac_add_options--enable-url-classifier

# From firefox-40, using system cairo causes firefox to crash

# frequently when it is doing background rendering in a tab.

#ac_add_options --enable-system-cairo

ac_add_options--enable-system-ffi

ac_add_options--enable-system-pixman

ac_add_options--with-pthreads

ac_add_options--with-system-bz2

ac_add_options--with-system-jpeg

#ac_add_options --with-system-png # System PNG doesn't support APNG

ac_add_options--with-system-zlib

mk_add_options MOZ_OBJDIR=@TOPSRCDIR@/firefox-build-dir

EOF

Python (10 min)

Next we will need at least Python 2.7.10 installed because Firefox uses it in their build system. On my CentOS 6.8 VMWare machine the highest version that can be installed is 2.6.6.

By changing the Python version number in the above command you may be able to get an even higher version, but this is sufficient. Do not go lower than 2.7.10 because it is a dependency of GLib which we have to upgrade later. Also note that if you enable RHSCL you can only get 2.7.8 or 3.3.2

GCC (5 min)

Once Python 2.7.10 is installed, configure will report that it needs GCC 4.8 installed. The GCC distributed with CentOS 6 is unfortunately only 4.4.7. Let’s work around that.

1

ERROR:Only GCC4.8ornewer issupported(found version4.4.7).

We need to use the RHSCL (Red Hat Software Collection) repo to get at least GCC 4.8 installed. We will install GCC 4.9.2 via the devtoolset-3 package. Run the following command:

1

2

3

4

yum install-ycentos-release-scl&&

yum-config-manager--enable rhel-server-rhscl-7-rpms&&

yum install-ydevtoolset-3-toolchain&&

scl enable devtoolset-3bash

After we set the environment above in the last command which enables GCC 4.9.2 immediately, let’s confirm the new GCC version:

1

2

[root@localhost osboxes]# gcc --version

gcc(GCC)4.9.220150212(Red Hat4.9.2-6)

Autoconf (30 s)

Next, configure reports that it needs Autoconf 2.13 to do some more configuration tasks. Install Autoconf 2.13 with this command:

1

yum install-yautoconf213.noarch

Libffi (20 s)

The next obstacle to compiling Firefox on the CentOS 6.8 box is libffi:

We need another side channel install to get libffi >= 3.0.9 on this system.

There is a guide here. The latest library can be downloaded here, and it can be configured and compiled with the following shell command. To avoid a make error later (see the end of this article), we will install the latest version (3.2.1 at this time).

Firefox reports that it needs libffi 3.0.9 or higher. We will actually install 3.2.1 because it is a dependency of GLib which we will upgrade later.

1

2

3

4

5

6

7

cd/tmp&&

wget ftp://sourceware.org/pub/libffi/libffi-3.2.1.tar.gz&&

tar-xvf libffi-3.2.1.tar.gz&&

cdlibffi-3.2.1&&

./configure--prefix=/usr--libdir=/usr/lib64--disable-static&&

make&&

makeinstall

GTK+ 2 (1 min)

Firefox will be using GIMP Toolkit 2 (GTK+ 2), so let’s install that now.

1

yum install-ygtk2-devel.x86_64

Yasm (1.5 min)

Next we are going to need the Yasm assembler as configure points out (only if we want WebM videos to play, which we do):

Yum-searching for “yasm” is initially non-resultant. Since EPEL (Extra Packages for Enterprise Linux, including RHEL) has yasm for CentOS 7, we can quickly install Yasm. Here are the commands:

1

2

yum--enablerepo=extras install-yepel-release&&

yum install-yyasm-devel.x86_64

Alsa & libXt (1 min)

We have to install a couple more packages as pointed out by configure for sound3, and some X headers:

Sound (alsa) – yum install -y alsa-lib-devel.x86_64

X headers (libXt) – yum install -y libXt-devel.x86_64

Firefox doesn’t display helpful messages for CentOS/RHEL users. For example, “Can’t find X headers (install libxt-dev (Debian/Ubuntu), libXt-devel (Fedora), or xorg-x11-libXt-devel (SuSE))“. If you enable more options in mozconfig, you can search for the right packages with yum search or yum whatprovides.

Glib & Readline (4 min)

I’ll save you the trouble of compiling Firefox only to discover after 24 minutes that you need to upgrade GLib. A make error may happen related to GLib (not Glibc). There is no warning in the configure stage, but GLib version 2.30 or higher is required. I know this because the symbol g_unicode_script_from_iso15924 is new in version 2.30. This took a bit of research.

When installing glib-devel.x86_64 via yum, the highest version on CentOS 6.8 available is 2.28. We need 2.30 or higher. Just to be safe we’ll install GLib 2.44.14 because it itself requires libffi 3.2.1 and Python 2.7.10, both of which we just installed.

But first, Glib needs the readline library. Run this command to install that library:

1

yum install-yreadline-devel.x86_64

If you install glib > 2.44.1, you will need a higher version of Python than we installed earlier, and may need a higher version of libffi as well.

This command will install Glib 2.44.1. Leave --with-pcre=internal as it is otherwise you will need to install PCRE too which requires another side channel install:

You may have noticed the installation of docbook-style-xsl. This took a while to investigate, but installing it solves a build error related to needing to download an XSLT stylesheet that cannot be found as it creates a local copy instead.

This took some research too, but long story short, run yum install -y libXdamage-devel.x86_64 to install the Xdamage headers.

Building Firefox (1.5 hours)

Finally we can build Firefox. This is going to take a very long time5. First, configure Firefox to check for any additional dependencies that are missing.

1

2

cd/tmp/firefox-49.0.1&&

./mach configure

If there are any missing dependencies, please add them as needed. Hopefully there wont be any more unless you are compiling a different version of Firefox, or the mozconfig settings have changed. Let’s build Firefox now.

1

2

cd/tmp/firefox-49.0.1&&

./mach-lmachlog.txtbuild

./mach -l LOGNAME build will save to disk all the make activity including any errors which may reveal missing dependencies. Also, if you have a failed build, run ./mach clobber to clean the previous attempt (the same as make clean)

Hopefully you will get a message like the following. It took over 1.5 hours to build Firefox on an i7 with just one core dedicated to the VMWare machine.

Packaging Firefox (2 min)

You may notice as I did that the build folder is about 2 GB. Yikes. Mozilla explains,

Our official builds are packaged before shipping, which entails stripping (among many other things). You can produce a packaged build by running “./mach package” in your source directory or “make package” in your object directory.

Thus, run ./mach package. You should find something similar to the following.

Firefox package distribution

The uncompressed Firefox build we just created is only about 100 MB. Much more reasonable. Upload the whole /dist folder to the shared host.

Running Firefox on the shared server

Now let’s see the shared libraries our shiny new build of Firefox requires.

So we know right away the main binary requires us to bring over libstdc++.so.6 to the shared server because it is in the /usr/lib64 folder. You can try to dereference the symlink to that binary and upload it manually now, or you can wait a few moments for a more automated way.

On your shared server you can set the LD_LIBRARY_PATH environment variable to some location in your home folder where you will store your libraries (e.g. ~/lib64).

Packaging libxul.so dependencies (10 s)

The Firefox binary’s dependencies are covered, but libxul.so, which is present in the Firefox binary directory (because you copied the whole /dist folder over), reports many missing libraries. The great news is that if you follow my guide on transplanting Linux binaries then the libxul.so dependencies can be copied over to the LD_LIBRARY_PATH easily. Here is the command you can use6:

All the dependent shared libraries will be combined into the base of a tarball named libxul.so.tar.gz. Notice that /usr/lib64/libstdc++.so.6 is included as well, so that is why we skipped copying it earlier.