Home / Alt manpages / ninja(1)

  • ninja(1)
  • User command
  • linux

Run a Predictable First Build with Ninja

Ninja is fast because it does one job and refuses to guess, which means it also refuses to explain itself unless you ask with the right flag. This guide gets you a repeatable Ninja build workflow: check the generated build file, preview what would run, build one target, and inspect the dependency graph when something goes wrong. The examples use Ninja 1.11.1 from the installed ninja-build package.

Allow 10 to 15 minutes. You need a shell, a project that already has a build.ninja file, and permission to read and write that project's build outputs. This guide assumes the build file was generated by a tool such as CMake or another project generator. Ninja is an execution engine, not a compiler or a general project configuration tool.

Checkpoint

All commands below are ordinary user commands. Do not use sudo for a normal build. Elevated privileges can leave root-owned outputs behind and can let a build recipe touch things it should not.

1. Confirm the program and build directory

Check the installed version, then move to the directory holding the generated manifest. Substitute your real build directory for /path/to/build:

$ ninja --version
1.11.1
$ test -f /path/to/build/build.ninja && echo 'build.ninja found'
build.ninja found

Ninja 1.11.1 reads build.ninja in the current directory by default. The -C option is a useful alternative when you want to stay in your source directory:

$ ninja -C /path/to/build --version
1.11.1

-C changes directory before Ninja does anything else. It is easy to forget that a relative target name is then resolved from the build directory, not from wherever you typed the command.

2. Preview the default build

With no target named, Ninja builds the manifest's default target. Preview it first with -n:

$ ninja -C /path/to/build -n
[1/3] cc -c src/main.c -o obj/main.o
[2/3] cc -c src/util.c -o obj/util.o
[3/3] cc obj/main.o obj/util.o -o app

Dry-run mode does not run the commands, but Ninja acts as if they succeeded so it can show you the planned work. The exact progress count and command descriptions depend on the project. A dry run is a checkpoint, not proof the compiler, linker or other tools will actually succeed.

If the output contains a command you did not expect, stop and inspect the generated files or the generator's configuration. Do not edit a generated manifest casually, the next configuration step may overwrite your change.

3. Build one target

When the dry run looks right, name the output you need. This limits the work and makes the result easier to verify:

$ ninja -C /path/to/build app
[1/3] cc -c src/main.c -o obj/main.o
[2/3] cc -c src/util.c -o obj/util.o
[3/3] cc obj/main.o obj/util.o -o app

A later run usually reports that there is nothing to do if the inputs and command descriptions have not changed:

$ ninja -C /path/to/build app
ninja: no work to do.

Verify the output independently when that matters. For an executable, for example:

$ test -x /path/to/build/app && echo 'app is executable'
app is executable

Ninja decides what is out of date from the dependency information in the manifest and its build logs. A successful Ninja exit status only means the declared commands completed, it does not certify the application's runtime behaviour.

4. Control parallel work deliberately

Ninja runs jobs in parallel by default, using the available CPU count, and usually that is the fastest choice. Use -j when you need a predictable limit, for example on a shared machine or a memory-heavy link:

$ ninja -C /path/to/build -j2 app

The value is the maximum number of jobs Ninja starts concurrently. -j0 means unlimited, which is rarely a good first response to a slow build. The -l option stops new jobs from starting when the system load average is above the value you give it:

$ ninja -C /path/to/build -j4 -l8 app

These options only affect this invocation. If the project generator has already encoded a pool or another concurrency constraint in build.ninja, that constraint still applies.

5. See full commands and keep going after a failure

Ninja normally prints a short description for each job. Add -v when you need the complete command line, including flags and expanded paths:

$ ninja -C /path/to/build -v app
[1/1] cc -O2 -Iinclude -c src/main.c -o obj/main.o

When one command fails, Ninja normally stops after that failure. Use -k to let it continue until a chosen number of jobs have failed, useful for collecting several independent compiler errors in one pass:

$ ninja -C /path/to/build -k5 app
ninja: build stopped: subcommand failed.

-k0 means keep going without a failure limit. It can produce a lot of output, and it does not make dependent jobs safe to run when their prerequisites failed. Read the first actionable compiler or generator error rather than jumping straight to the final summary.

6. Inspect targets before changing anything

The -t option runs a Ninja subtool. List the tools available in this installed version:

$ ninja -t list
ninja subtools:
     browse  browse dependency graph in a web browser
     clean   clean built files
     commands list all commands required to rebuild given targets
     inputs  list all inputs required to rebuild given targets
     ...

The exact spacing and full list can vary, so treat the local output as authoritative. Two read-only tools are particularly useful:

$ ninja -C /path/to/build -t commands app
cc -c src/main.c -o obj/main.o
cc -c src/util.c -o obj/util.o
cc obj/main.o obj/util.o -o app
$ ninja -C /path/to/build -t query app
app:
  input: link
    obj/main.o
    obj/util.o
  outputs:
  • commands prints the commands Ninja would use to rebuild a target.
  • query shows the target's direct inputs and outputs.

Use both before modifying a manifest or deleting an output. They help you tell a missing input apart from a stale or incorrectly generated dependency.

7. Handle failure without making it worse

Do not run a clean subtool as a first troubleshooting step. Cleaning removes generated files and can make the next diagnosis harder. If you genuinely need to remove built files, check the available help first:

$ ninja -C /path/to/build -t clean -h

Confirm the directory and the cleanup scope before accepting a destructive operation. Keep source files and generated configuration available until you have a reproducible replacement build. There is no undo command for files a clean operation removes; restore them by rebuilding, regenerating, or recovering them from version control as appropriate.

For a missing compiler or command, rerun with -v and test the named program with command -v. For a missing input, use the path -t query showed you and check it without changing state:

$ command -v cc
/usr/bin/cc
$ test -r /path/to/build/src/main.c && echo readable

If the manifest itself is stale, rerun the project generator using that project's documented command, then repeat the dry run. Do not guess generator flags from Ninja's command-line options, Ninja cannot repair a configuration decision made by another tool.

Done means

  • Version confirmed: ninja --version reports the installed version you expected, here 1.11.1.
  • Directory checked: the build directory and build.ninja were checked before any work ran.
  • Dry run reviewed: before the real build ran.
  • Target verified: the required target completed, and its output was checked independently.
  • Parallelism controlled: limited deliberately where CPU or memory pressure required it.
  • Diagnostics ready: -v, -t commands and -t query are available for the next failure.
  • No unnecessary risk taken: no elevated privilege or destructive clean operation without a specific reason.