Ninja Build System

repository·master·Indexed 10 days ago

https://github.com/ninja-build/ninja

A small, high-performance build system designed as a low-level 'assembler' for higher-level build tools like CMake. It focuses on speed and minimalism, utilizing a generator pattern to execute dependency graphs in parallel.

Tokens
4.8K
Snippets
13
Records
20
Agent score
46%

What's inside Ninja

  1. Use escape characters in Ninja build files

    master

    Ninja uses the $ character for escaping and variable expansion. The following behaviors are supported:

    • $ followed by a newline: Escapes the newline to continue the current line across a line breaks.
    • $varname or ${varname}: Variable reference.
    • $ followed by a space: Inserts a literal space (useful in path lists).
    • $:: Inserts a literal colon (useful in build lines to avoid terminating the output list).
    • $^: Inserts a newline \n (available since Ninja 1.14; requires ninja_required_version >= 1.14).
    • $$: Inserts a literal $.
    # Example of using $ to handle spaces and newlines
    spaced = foo bar
    build $spaced/baz other$ file: ...
    # Results in outputs: "foo bar/baz" and "other file"
    
    # Example of line continuation
    two_words_with_one_space = foo $
        bar
  2. Use Pools to limit concurrency

    master

    Pools allow you to restrict the number of concurrent jobs for specific rules or build statements. This is useful for resource-intensive tasks like linking large binaries.

    1. Define a pool with a depth.
    2. Assign the pool to a rule or a build statement.

    Note: Ninja will never run more concurrent jobs than the total allowed by the command line -j flag or the system CPU count, even if pools are defined.

    The console pool: A special pre-defined pool with depth = 1. Tasks in this pool have direct access to the standard input/output/error streams, and Ninja buffers other output until the task completes. This is ideal for interactive tasks or long-running tests.

    # Limit linking to 4 concurrent jobs
    pool link_pool
      depth = 4
    
    rule link
      command = ld $in -o $out
      pool = link_pool
    
    # This build uses the link_pool
    build app: link app.o
    
    # This build is exempted from the rule's pool and uses the default pool
    build extra_app: link extra.o
      pool =
  3. Use validations for non-artifact tasks

    master

    Available since Ninja 1.11, validations allow you to run rules that perform error checking (like static analysis) without producing build artifacts.

    Validations are added to the build graph as if they were specified on the command line. They allow the main build to proceed in parallel with the validation task. If the validation fails, the build is considered failed, but the validation itself does not affect the 'dirty' state of the files it checks.

  4. Understand variable scoping and expansion

    master

    Variables are expanded immediately when encountered, except for variables in rule blocks, which are expanded when the rule is used.

    Lookup Order for a build block:

    1. Special built-in variables ($in, $out).
    2. Variables declared within the build block.
    3. Rule-level variables (from the rule being used).
    4. File-level variables from the current file.
    5. Variables from the file that included the current file via subninja.

    Inclusion Types:

    • subninja: Includes another .ninja file in a new scope. The included file can see and shadow parent variables, but cannot affect the parent.
    • include: Includes another .ninja file in the current scope (similar to C #include).
  5. Understand command execution on Unix vs Windows

    master

    The interpretation of the command variable depends on the operating system:

    • Unix: Commands are treated as arrays of arguments. The command string is passed to sh -c. You can use standard shell operators like && or set environment variables (e.g., VAR=value cmd).
    • Windows: Commands are strings passed directly to CreateProcess. Quoting rules are determined by the called program's C library. To use shell operators like &&, prefix the command with cmd /c.
  6. Use explicit, implicit, and order-only dependencies

    master

    Ninja supports three types of dependencies in a build line:

    1. Explicit dependencies: Listed normally. Changes trigger a rebuild. Available via $in in rules.
    2. Implicit dependencies:
      • Defined via depfile in a rule.
      • Defined using the | syntax: build out: in | imp-in. Changes trigger a rebuild, but they do not appear in the $in variable.
    3. Order-only dependencies: Defined using the || syntax: build out: in || ord-only. When an order-only dependency is out of date, the output is rebuilt only after the dependency is built. However, changes to order-only dependencies alone do not trigger a rebuild of the output.
    # Explicit dependency
    build out: in
    
    # Implicit dependency (not in $in)
    build out: in | imp-in
    
    # Order-only dependency (not in $in)
    build out: in || ord-only
  7. How Ninja works and its design philosophy

    master

    Ninja is a low-level build system designed for speed. Unlike high-level build systems (like Make or CMake) that are intended to be written by humans, Ninja is intended to be an "assembler"—a target for a generator program.

    Key Concepts:

    • Generator Pattern: You should not write .ninja files by hand. Instead, use a meta-build system (like CMake, GN, or a custom script) to generate them. This allows complex logic (conditionals, system discovery) to happen during generation, keeping the actual build phase instant.
    • Minimalism: Ninja lacks built-in rules (e.g., no default C compiler rule) and complex syntax (no conditionals or search paths) to ensure it does the minimum work necessary to execute the dependency graph.
    • Parallelism: Builds run in parallel by default, scaled to your system's CPU count.
    • Correctness: Ninja handles difficult dependency scenarios, such as implicit dependencies on command-line flags and automatic creation of output directories.
  8. Run Ninja builds

    master

    To run a build, execute the ninja command in the directory containing your build.ninja file.

    By default, Ninja builds all out-of-date targets. You can specify specific targets as arguments.

    Special Syntax: Use target^ to specify a target as the first output of some rule containing the source you provide. For example, ninja foo.c^ will build foo.o if a rule exists that maps foo.c to foo.o.

    # Build all targets
    ninja
    
    # Build a specific target
    ninja my_executable
    
    # Change directory and run with specific job count
    ninja -C build -j 20
    
    # Use the special target syntax to build an object from a source
    ninja foo.c^
  9. Build Ninja using the Python bootstrap script

    master

    You can build Ninja using the provided Python configuration script. This method generates the ninja binary and a build.ninja file, allowing Ninja to build itself.

    To build the tests, you must provide a path to a GoogleTest source directory using the --gtest-source-dir flag or the GTEST_SOURCE_DIR environment variable.

    Steps:

    1. Bootstrap the project.
    2. Build the all target.
    3. Run the ninja_test binary to execute the unit-test suite.
    ./configure.py --bootstrap --gtest-source-dir=/path/to/googletest
    ./ninja all     # build ninja_test and other auxiliary binaries
    ./ninja_test    # run the unit-test suite.
  10. Generate the Ninja Manual (HTML or PDF)

    master

    To generate the official Ninja manual, you must have asciidoc and xsltproc installed in your PATH.

    HTML version: Generates doc/manual.html.

    PDF version: Requires dblatext in your PATH in addition to the HTML requirements. Generates doc/manual.pdf.

    Note: You must run ./configure.py before running the ninja commands if you haven't already.

    # Generate HTML
    ./configure.py
    ninja manual doc/manual.html
    
    # Generate PDF
    ./configure.py
    ninja doc/manual.pdf
  11. Install Ninja via binaries

    master

    Ninja is a standalone executable. You do not need to perform a formal installation; you only need the resulting ninja binary. Binaries for Linux, Mac, and Windows are available on the GitHub releases page.

    To enable advanced features like Bash completion or Emacs and Vim editing modes, you must manually copy the relevant files from the misc/ directory in the source repository to their appropriate locations on your system.

  12. Build Ninja using CMake

    master

    If you prefer CMake or want to use a preinstalled version of the library, you can build the binary using the following commands.

    To build without unit tests: Set BUILD_TESTING to OFF to skip test compilation.

    To build with unit tests: Omit the BUILD_TESTING=OFF flag. After the build completes, run the ninja_test binary located in your build directory.

    # Build without tests
    cmake -Bbuild-cmake -DBUILD_TESTING=OFF
    cmake --build build-cmake
    
    # Build with tests
    cmake -Bbuild-cmake
    cmake --build build-cmake
    build-cmake/ninja_test