2014-05-15
Firefox Development on NixOS
Now that I've got NixOS installed I needed a way to build and make changes to Firefox and Firefox OS. This post goes through the approach I've taken to work on the Firefox codebase. In a later post I'll build on this to do Firefox OS development.
Building Firefox isn't difficult as NixOS has definitions for standard Firefox builds to follow as examples. To build from a local source repository it requires all the pre-requisite packages to be installed. I don't want to pollute my local user environment with all these packages though as I develop on other things which may have version clashes. As an example, Firefox requires autoconf-2.13
whereas other systems I develop with require different verisons.
NixOS (through the Nix package manager) allows setting up build environments that contain specific packages and versions. Switching between these is easy. The file ~/.nixpkgs/config.nix
can contain definitions specific for a user. I add the definitions as a packageOverride
in this file. The structure of the file looks like:
{
packageOverrides = pkgs : with pkgs; rec {
..new definitions here..
};
}
My definition for a build environment for Firefox is:
firefoxEnv = pkgs.myEnvFun {
name = "firefoxEnv";
buildInputs = [ stdenv pkgconfig gtk glib gobjectIntrospection
dbus_libs dbus_glib alsaLib gcc xlibs.libXrender
xlibs.libX11 xlibs.libXext xlibs.libXft xlibs.libXt
ats pango freetype fontconfig gdk_pixbuf cairo python
git autoconf213 unzip zip yasm alsaLib dbus_libs which atk
gstreamer gst_plugins_base pulseaudio
];
extraCmds = ''
export C_INCLUDE_PATH=${dbus_libs}/include/dbus-1.0:${dbus_libs}/lib/dbus-1.0/include
export CPLUS_INCLUDE_PATH=${dbus_libs}/include/dbus-1.0:${dbus_libs}/lib/dbus-1.0/include
LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:${gcc.gcc}/lib64
for i in $nativeBuildInputs; do
LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:\$i/lib
done
export LD_LIBRARY_PATH
export AUTOCONF=autoconf
'';
};
The Nix function pkgs.myEnvFun
creates a program that can be run by the user to set up the environment such that the listed packages are available. This is done using symlinks and environment variables. The resulting shell can then be used for normal development. By creating special environments for development tasks it becomes possible to build with different versions of packages. For example, replace gcc
with gcc46
and the environment will use that C compiler version. Environments for different versions of pango, gstreamer and other libraries can easily be created for testing Firefox builds with those specific versions.
The buildInputs
field contains an array of the packages to be avaliable. These are all the pre-requisites as listed in the Mozilla build documentation. This could be modified by adding developer tools to be used (Vim, Emacs, Mercurial, etc) if desired.
When creating definitions that have a build product Nix will arrange the dynamic loader and paths to link to the correct versions of the libraries so that they can be found at runtime. When building an environment we need to change LD_LIBRARY_PATH
to include the paths to the libraries for all the packages we are using. This is what the extraCmds
section does. It is a shell script that is run to setup additional things for the environment.
The extraCmds
in this definition adds to LD_LIBRARY_PATH
the lib
directory of all the packages in buildInputs
. It exports an AUTOCONF
environment variable to be the autoconf
executable we are using. This variable is used in the Mozilla build system to find autoconf-2.13
. It also adds to the C and C++ include path to find the DBus libraries which are in a nested dbus-1.0
directory.
To build and install this new package use nix-env
:
$ nix-env -i env-firefoxEnv
Running the resulting load-env-firefoxEnv
command will create a shell environment that can be used to build Firefox:
$ load-env-firefoxEnv
...
env-firefoxEnv loaded
$ git clone git://github.com/mozilla/gecko-dev
...
$ cd gecko-dev
$ ./mach build
Exiting the shell will remove access to the pre-requisite libraries and tools needed to build Firefox. This keeps your global user environment free and minimizes the chance of clashes.