When To Use ifdefs

The mozilla codebase is used for many different projects and products, including Firefox, Thunderbird, XULRunner, and many others. Sometimes the same basic code is used for multiple projects, but there are small differences needed. "ifdefs", or conditional instructions, are used to build different code

What are ifdefs

ifdefs are conditional directives to a text preprocessor which mark that certain blocks of code are used only in certain conditions. In this document, the term is used more loosely to discuss any kind of conditional that differentiates between different build configurations.

When are ifdefs used?

There are three major kinds of ifdefs in use in the mozilla tree: platform/widget ifdefs, feature ifdefs, and application-specific ifdefs:

Platform/widget ifdefs

The mozilla code will frequently need to differentiate between code for different platforms or widget sets. These ifdefs are generally always acceptable. The only time when they might be a problem is in cross-platform extension code and locales: since this code is downloaded on multiple platforms, platform-specific ifdefs are generally out of the question.

For an example of platform-specfic ifdefs, see nsCRT.h.

Feature ifdefs

The mozilla code has many features that can be enabled or disabled by configure flags. For instance, it is possible to disable most of the XUL rendering engine by specifying --disable-xul when configuring the build. When adding ifdefs that implement these configure flags, care must be taken to obey the build dependencies. For instance, XPCOM, the SpiderMonkey JavaScript engine, and the networking engine do not know anything about XUL and should not have any ifdefs based on --disable-xul.

One special "feature ifdef" that deserves special attention is "MOZ_XUL_APP". This variable marks any application that is using the "toolkit". MOZ_XUL_APP ifdefs are not acceptable in tier 9, but are acceptable (even necessary) in later tiers.

For an example of feature ifdefs, see layout/Makefile.in.

Application-specific ifdefs

Finally, each application/project needs to build different pieces of code. Application ifdefs should only be made in application-specific code. This is the trickiest kind of ifdef, because it is frequently hard to determine what code is "shared" and what code is "application-specific". As a general rule, any code in tier 2, tier 9, or tier 50 is shared code, and should not have application-specific ifdefs. Any code in later tiers is application-specific. This rule has many exceptions, some of which are listed here:

  • The code in editor/ui/ is built by the suite, standalone composer, and thunderbird, but it is considered application-specific.
  • The code in xpfe/ (except for xpfe/appshell/ and xpfe/components/shistory/) is a hodgepodge mess of "toolkit" and "application-specific" code. This code is all going to be moved elsewhere (most of it to toolkit/ or suite/), but for the time being most application-specific ifdefs are allowed because we can't help it. If you're not sure, ask Benjamin Smedberg.

For an example of an application-specific ifdef that is bad and should be removed, see nsNativeAppSupportWin.cpp.

Types of ifdef

There are two major types of ifdef: preprocessor ifdefs and makefile ifdefs. Preprocessor ifdefs are generally easy to spot: in C, C++, and plaintext preprocessed code there will be an #ifdef or #if instruction.

Makefile ifdefs, however, are sometimes harder to spot and can cause hidden issues that are much more serious. Makefile ifdefs are used to build or not-build certain directories. This can mean that there are completely different interfaces with the same name which are built conditionally. For example (at the time of writing) there are two nsIExtensionManager interfaces: toolkit version and suite version. The makefile ifdefs that choose which one to build are not obvious (see Makefile.in and xpfe/components/Makefile.in). If you are introducing a makefile ifdef of any sort, please ask review from one of the build-config peers: Benjamin Smedberg is generally happy to review these changes.