Visit Mozilla.org

How Mozilla's build system works

From MDC

This document is targeted at Mozilla developers who need to use Mozilla's GNU Make-based build system. It explains the basic concepts and terminology of the build system, and how to do common tasks such as compiling components and creating jar files.

This document is not intended for people who just want to build Mozilla. For that, see the Build Documentation.

Contents

[edit] Concepts

Mozilla's build system is based around GNU Make. At its most basic level, make is a tool to automate generation of targets, given the target's dependencies and rules to generate the target.

In Mozilla, make is used to compile libraries and executables, create jar files for chrome, and copy files around. We use a 2-pass build system:

  • The export phase copies public header files to dist/include, and generates C++ header files from IDL files.
  • The libs phase compiles libraries, creates jar files, and creates typelib files from IDL files.

Each of these phases is just a make target. That is, each directory is traversed once with the export target, and then again later with the libs target. The two-stage build exists because of circular dependencies among modules - exporting all of the headers at the start allows module A to include public headers from module B, and module B to include public headers from module A.

Another important tool is the configure script, which is run as the first step in the build. The configure script determines characteristics of the system and compiler, and processes options that are given to the configure script. There are two main products from running the configure script:

  • The autoconf.mk file is generated from config/autoconf.mk.in. This file contains make variables which control global build options.
  • Makefile files are created from Makefile.in files all over the tree. The source directory location is substitued into Makefile.in to allow the build to work correctly.

The configure script is a bash shell script; the file is generated from a file called configure.in which is written with M4 and processed using Autoconf 2.13 to create the final script. Note: Mozilla uses an old version of autoconf, because modern versions removed features that are necessary for our build system. Autoconf 2.13 may be named autoconf-2.13, autoconf213 or even autoconf, depending on platform. See the Mac/Linux/OS/2 pages for more information.

[edit] Makefile basics

Makefiles can be quite complicated, but Mozilla provides a number of built-in rules that should enable most Makefiles to be quite simple. Complete documentation for make is beyond the scope of this document, but is available here.

One concept you will need be familiar with is variables in make. Variables are defined by the syntax VARIABLE = VALUE, and the value of a variable is referenced by writing $(VARIABLE). All variables are strings.

All Makefile.in files in Mozilla have the same basic format:


DEPTH           = ../../../..
topsrcdir       = @top_srcdir@
srcdir          = @srcdir@
VPATH           = @srcdir@

include $(DEPTH)/config/autoconf.mk

# ... Main body of Makefile goes here ...

include $(topsrcdir)/config/rules.mk

# ... Additional rules go here ...
  • The DEPTH variable should be set to the relative path from your Makefile.in to the toplevel Mozilla directory.
  • topsrcdir is substituted in by configure, and points to the toplevel mozilla directory.
  • srcdir is also substituted in by configure, and points to the source directory for the current directory. In source tree builds, this will simply point to "." (the current directory).
  • VPATH is a list of directories where make will look for prerequisites (i.e. source files).

One other frequently used variable not specific to a particular build target is DIRS. DIRS is a list of subdirectories of the current directory to recursively build in. Subdirectories are traversed after their parent directories. For example, you could have:

DIRS = \
  public \
  resources \
  src \
  $(NULL)

This example demonstrates another concept, continuation lines. A backslash as the last character on a line allows the variable definition to be continued on the next line. The extra whitespace is compressed. The terminating $(NULL) is a method for consistency; it allows you to add and remove lines without worrying about whether the last line has an ending backslash or not.

[edit] Makefile examples

[edit] Building libraries

There are three main types of libraries that are built in Mozilla:

  • Components are shared libraries (except in static builds) which are installed to dist/bin/components. Components are not linked against by any other library.
  • Non-component shared libraries includes libraries such as libxpcom, libmozjs. These libraries are installed to dist/bin and are linked against. You will probably not need to create a new library of this type.
  • Static libraries are often used as intermediate steps to building a shared library, if there are source files from several directories that are part of the shared library. Static libraries may also be linked into an executable.


[edit] Non-component shared libraries

A non-component shared library is useful when there is common code that several components need to share, and sharing it through XPCOM is not appropriate or not possible. As an example, let's look at a portion of the Makefile for libmsgbaseutil, which is linked against by all of the mailnews components:

 DEPTH           = ../../..
 topsrcdir       = @top_srcdir@
 srcdir          = @srcdir@
 VPATH           = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE          = msgbaseutil
 LIBRARY_NAME    = msgbaseutil
 EXPORT_LIBRARY = 1
 SHORT_LIBNAME   = msgbsutl

Notice that the only real change from the component example above is that IS_COMPONENT is not set. When this is not set, a shared library will be created and installed to dist/bin.

[edit] Static libraries

As mentioned above, static libraries are most commonly used as intermediate steps to building a larger library (usually a component). This allows you to spread out the source files in multiple subdirectories. Static libraries may also be linked into an executable. As an example, here is a portion of the Makefile from layout/base/src:

 DEPTH           = ../../..
 topsrcdir       = @top_srcdir@
 srcdir          = @srcdir@
 VPATH           = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE          = layout
 LIBRARY_NAME    = gkbase_s
 
 # REQUIRES and CPPSRCS omitted here for brevity #
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk

The key here is setting FORCE_STATIC_LIB = 1. This creates libgkbase_s.a (on unix) and gkbase_s.lib on Windows, and copies it to dist/lib. Now, let's take a look at how to link several static libraries together to create a component:

 DEPTH           = ../..
 topsrcdir       = @top_srcdir@
 srcdir          = @srcdir@
 VPATH           = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE          = layout
 LIBRARY_NAME    = gklayout
 EXPORT_LIBRARY = 1
 IS_COMPONENT    = 1
 MODULE_NAME     = nsLayoutModule
 
 CPPSRCS         = \
                 nsLayoutModule.cpp \
                 $(NULL)
 
 SHARED_LIBRARY_LIBS = \
                 $(DIST)/lib/$(LIB_PREFIX)gkhtmlbase_s.$(LIB_SUFFIX) \
                 $(DIST)/lib/$(LIB_PREFIX)gkhtmldoc_s.$(LIB_SUFFIX) \
                 $(DIST)/lib/$(LIB_PREFIX)gkhtmlforms_s.$(LIB_SUFFIX) \
                 $(DIST)/lib/$(LIB_PREFIX)gkhtmlstyle_s.$(LIB_SUFFIX) \
                 $(DIST)/lib/$(LIB_PREFIX)gkhtmltable_s.$(LIB_SUFFIX) \
                 $(DIST)/lib/$(LIB_PREFIX)gkxulbase_s.$(LIB_SUFFIX) \
                 $(DIST)/lib/$(LIB_PREFIX)gkbase_s.$(LIB_SUFFIX) \
                 $(DIST)/lib/$(LIB_PREFIX)gkconshared_s.$(LIB_SUFFIX) \
                 $(DIST)/lib/$(LIB_PREFIX)gkxultree_s.$(LIB_SUFFIX) \
                 $(DIST)/lib/$(LIB_PREFIX)gkxulgrid_s.$(LIB_SUFFIX) \
                 $(NULL)
 
 include $(topsrcdir)/config/rules.mk

SHARED_LIBRARY_LIBS is set to a list of static libraries which should be linked into this shared library. Note the use of LIB_PREFIX and LIB_SUFFIX to make this work on all platforms.

[edit] Building jar files

Jar files are used for packaging chrome files (XUL, JavaScript, and CSS). For more information on Jar packaging, you can read this document. Here we will only cover how to set up a Makefile to package jars. Here is an example:

 DEPTH           = ../../../..
 topsrcdir       = @top_srcdir@
 srcdir          = @srcdir@
 VPATH           = @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 include $(topsrcdir)/config/rules.mk

That's right, there are no extra variables to define. If a jar.mn file exists in the same directory as this Makefile.in, it will automatically be processed. Although the common practice is to have a resources directory that contains the jar.mn and chrome files, you may also put a jar.mn in a directory that creates a library, and it will be processed.

[edit] Build Tiers

The Mozilla build system divides the source tree into "tiers", where a tier is a list of subdirectories containing makefiles of their own. For example, there is a tier for the Netscape Portable Runtime (named nspr) and one for the Gecko layout engine (named gecko). The project you're building — Firefox, Thunderbird, or whatever — determines the list of tiers to include in the build process.

In the root Makefile.in, the TIERS variable holds the list of tiers to build. We start it off with some small tiers required by the build system itself, and then include a build.mk file for the application we're building (say, browser/build.mk) to add the rest. The application's build.mk file may include others, depending on which code the application needs.

For each tier named t in the final value of TIERS, the build.mk file that added that tier sets variables named tier_t_dirs and tier_t_staticdirs to the lists of source directories for that tier. For example, config/nspr/build.mk adds nspr to TIERS, and sets tier_nspr_dirs and tier_nspr_staticdirs to the source directories for the Netscape Portable Runtime.

The root Makefile.in includes config/rules.mk to define much of its standard behavior. Among other things, config/rules.mk uses TIERS and the tier_t_dirs and tier_t_staticdirs variables to set DIRS and STATIC_DIRS; many of config/rules.mk's targets, including all and libs, iterate over the values of those variables automatically.

In particular, the main loop of the build process simply invokes make tier_t for each tier in TIERS. This, in turn, invokes make in each of the tier's static directories, and then make export and make libs in each non-static directory.

The config/rules.mk file defines some standard targets for debugging this process. You can run these at the top of an object directory tree.

Command Effect
make echo-tiers Show the final list of tiers.
make echo-dirs Show the list of non-static source directories to iterate over, as determined by the tier list.
make echo-variable-STATIC_DIRS Show the list of static source directories to iterate over, as determined by the tier list.

[edit] Related Links

See the glossary of Makefile variables for information about specific variables and how to use them.


Original Document Information:

  • Author: Brian Ryner
  • Copyright Information: Portions of this content are © 1998–2006 by individual mozilla.org contributors; content available under a Creative Commons license