Buck: cxx_precompiled_header()

cxx_precompiled_header()

This is liable to change in the future.

A cxx_precompiled_header rule specifies a single header file that can be precompiled and made available for use in other build rules such as a cxx_library or a cxx_binary.

This header file is precompiled by the preprocessor on behalf of the C, C++, Objective-C, or Objective-C++ rule using it, via its precompiled_header parameter. Afterwards the precompiled header is applied during the rule's own compilation (often with an appreciable reduction in build time, the main benefit of PCH).

This PCH is built once per combination of build flags which might affect the PCH's compatibility. For example, a distinct pre-compilation of the header occurs per combination of flags related to optimization, debug, architecture, and so on, used by rules which employ PCH. The flags used during the build of the dependent rule (that is, the "PCH-using rule") are in effect while building the PCH itself. Similarly, to the same end, the include paths used when building the PCH are applied to the dependent rule. For example, deps in the PCH rule are propagated back to the dependent rule, and the PCH's header search paths (e.g. -I or -isystem options) are prefixed onto the list of include paths for the dependent rule.

Arguments

  • name (required) #

    A descriptive name for the rule.

  • src (required) #

    The path to the header file that should be precompiled. Only one header file can be specified. But of course this header could include any number of other headers. The included headers could belong to -- that is, be exported_headers from -- another rule, in which case, the rule would have to be added to deps as usual.

  • deps (defaults to None) #

    Dependency rules which export headers used by the header specified in src.

  • visibility (defaults to []) #

    List of build target patterns that identify the build rules that can include this rule in its deps.

  • licenses (defaults to []) #

    Set of license files for this library. To get the list of license files for a given build rule and all of its dependencies, you can use buck query.

  • labels (defaults to []) #

    Set of arbitrary strings which allow you to annotate a build rule with tags that can be searched for over an entire dependency tree using buck query attrfilter.

Examples

The best way to see how the cxx_precompiled_header() rule works is with an example. Let there be a header called common.h which has the following:

#pragma once

/* Include common C++ files. */
#include <string>
#include <map>
#include <set>
#include <type_traits>
#include <vector>

/* Some frequently-used headers from the Folly project. */
#include <folly/Conv.h>
#include <folly/Executor.h>
#include <folly/io/async/EventBase.h>
cxx_precompiled_header(
  name = 'common_pch',
  src = 'common.h',
  deps = [
    # Needed for standard C++ headers:
    '//external/libcxx:headers',
    # Needed for the Folly includes:
    '//folly:folly',
    '//folly/io/async:async',
  ],
)

cxx_binary(
  name = 'main',
  srcs = ['main.cpp'],
  precompiled_header = ':common_pch',
  deps = [ ... ],
  compiler_flags = ['-g', '-O2', '-fPIC'],
)

The cxx_precompiled_header rule declares a precompiled header "template" containing the header file path, and dependencies. In this example we indicate that common.h is to be precompiled when used by another build rule.

Note that, by itself, this cxx_precompiled_header rule will not result in anything being built. The usage of this rule from another rule -- an "instantiation" of this precompiled header template -- is what will trigger the PCH build.

In the example above, the build for the binary named "main" will depend on the header being precompiled in a separate step, prior to compiling main.cpp, and the resulting PCH will be used in main's compilation.

The dependencies specified in this precompiled header rule's deps are transitive; they will propagate to rules using this PCH, so that during link time, any libraries which are required by the code made available in the header will be included in the final binary build.

The precompiled header dynamically created from the "template" will be built with flags which would be used in the dependent rule. In this case, main's use of specific compiler flags -g -O2 -fPIC will result in the production of a precompiled header with the same flags. This is so the precompiled code fully jives with rules using the PCH, i.e. they will have the same debug, optimization, CPU, etc. options. (The compiler is usually smart enough to reject a bad PCH, fortunately. But we want to ensure we take the appropriate steps to ensure we always have a PCH which works with any build that uses it.)

Another effect of a rule using a precompiled header is that the rule's list of build flags will change; not just to employ PCH with e.g. -include-pch (if using Clang), but also, to alter the sequence of header search paths. The rule using the precompiled header will "inherit" the lists of paths used during the PCH build, applying them first in its own search paths. This is to ensure that an #include directive will resolve in exactly the same way in this build as it would have in the PCH, to ensure full compatibility between the PCH and other rule's builds. For example, if the PCH were to use one version of stdcxx and another rule use a different version, the version differences won't clash, thereby avoiding different versions of the <cstring> header used between the precompiled header and the dependent rule, and preventing confused structure definitions, ABI incompatibility, and so on (catastrophe, in other words).