├── .clang-format
├── .clang-tidy
├── .editorconfig
├── .github
├── dependabot.yml
└── workflows
│ ├── linux-musl.yml
│ ├── linux.yml
│ ├── macos.yml
│ └── windows.yml
├── .gitignore
├── CMakeLists.txt
├── CONTRIBUTING.md
├── COPYING
├── README.md
├── RELEASING.md
├── appveyor.yml
├── configure.py
├── doc
├── README.md
├── dblatex.xsl
├── docbook.xsl
├── doxygen.config
├── manual.asciidoc
└── style.css
├── misc
├── afl-fuzz-tokens
│ ├── kw_build
│ ├── kw_default
│ ├── kw_include
│ ├── kw_pool
│ ├── kw_rule
│ ├── kw_subninja
│ ├── misc_a
│ ├── misc_b
│ ├── misc_colon
│ ├── misc_cont
│ ├── misc_dollar
│ ├── misc_eq
│ ├── misc_indent
│ ├── misc_pipe
│ ├── misc_pipepipe
│ └── misc_space
├── afl-fuzz
│ └── build.ninja
├── bash-completion
├── ci.py
├── inherited-fds.ninja
├── jobserver_pool.py
├── jobserver_pool_test.py
├── jobserver_test.py
├── jobserver_test_helper.py
├── long-slow-build.ninja
├── manifest_fuzzer.cc
├── measure.py
├── ninja.vim
├── ninja_syntax.py
├── ninja_syntax_test.py
├── oss-fuzz
│ ├── build.sh
│ └── sample_ninja_build
├── output_test.py
├── packaging
│ ├── ninja.spec
│ └── rpmbuild.sh
├── write_fake_manifests.py
└── zsh-completion
├── src
├── browse.cc
├── browse.h
├── browse.py
├── build.cc
├── build.h
├── build_log.cc
├── build_log.h
├── build_log_perftest.cc
├── build_log_test.cc
├── build_test.cc
├── canon_perftest.cc
├── clean.cc
├── clean.h
├── clean_test.cc
├── clparser.cc
├── clparser.h
├── clparser_perftest.cc
├── clparser_test.cc
├── command_collector.h
├── debug_flags.cc
├── debug_flags.h
├── depfile_parser.cc
├── depfile_parser.h
├── depfile_parser.in.cc
├── depfile_parser_perftest.cc
├── depfile_parser_test.cc
├── deps_log.cc
├── deps_log.h
├── deps_log_test.cc
├── disk_interface.cc
├── disk_interface.h
├── disk_interface_test.cc
├── dyndep.cc
├── dyndep.h
├── dyndep_parser.cc
├── dyndep_parser.h
├── dyndep_parser_test.cc
├── edit_distance.cc
├── edit_distance.h
├── edit_distance_test.cc
├── elide_middle.cc
├── elide_middle.h
├── elide_middle_perftest.cc
├── elide_middle_test.cc
├── eval_env.cc
├── eval_env.h
├── exit_status.h
├── explanations.h
├── explanations_test.cc
├── gen_doxygen_mainpage.sh
├── getopt.c
├── getopt.h
├── graph.cc
├── graph.h
├── graph_test.cc
├── graphviz.cc
├── graphviz.h
├── hash_collision_bench.cc
├── hash_map.h
├── includes_normalize-win32.cc
├── includes_normalize.h
├── includes_normalize_test.cc
├── inline.sh
├── jobserver-posix.cc
├── jobserver-win32.cc
├── jobserver.cc
├── jobserver.h
├── jobserver_test.cc
├── json.cc
├── json.h
├── json_test.cc
├── lexer.cc
├── lexer.h
├── lexer.in.cc
├── lexer_test.cc
├── line_printer.cc
├── line_printer.h
├── load_status.h
├── manifest_parser.cc
├── manifest_parser.h
├── manifest_parser_perftest.cc
├── manifest_parser_test.cc
├── metrics.cc
├── metrics.h
├── minidump-win32.cc
├── missing_deps.cc
├── missing_deps.h
├── missing_deps_test.cc
├── msvc_helper-win32.cc
├── msvc_helper.h
├── msvc_helper_main-win32.cc
├── msvc_helper_test.cc
├── ninja.cc
├── ninja_test.cc
├── parser.cc
├── parser.h
├── real_command_runner.cc
├── state.cc
├── state.h
├── state_test.cc
├── status.h
├── status_printer.cc
├── status_printer.h
├── status_test.cc
├── string_piece.h
├── string_piece_util.cc
├── string_piece_util.h
├── string_piece_util_test.cc
├── subprocess-posix.cc
├── subprocess-win32.cc
├── subprocess.h
├── subprocess_test.cc
├── test.cc
├── test.h
├── third_party
│ ├── emhash
│ │ ├── README.ninja
│ │ └── hash_table8.hpp
│ └── rapidhash
│ │ ├── README.ninja
│ │ └── rapidhash.h
├── timestamp.h
├── util.cc
├── util.h
├── util_test.cc
├── version.cc
├── version.h
└── win32port.h
└── windows
└── ninja.manifest
/.clang-format:
--------------------------------------------------------------------------------
1 | # Copyright 2014 Google Inc. All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | # This isn't meant to be authoritative, but it's good enough to be useful.
16 | # Still use your best judgement for formatting decisions: clang-format
17 | # sometimes makes strange choices.
18 |
19 | BasedOnStyle: Google
20 | AllowShortFunctionsOnASingleLine: Inline
21 | AllowShortIfStatementsOnASingleLine: false
22 | AllowShortLoopsOnASingleLine: false
23 | ConstructorInitializerAllOnOneLineOrOnePerLine: false
24 | Cpp11BracedListStyle: false
25 | IndentCaseLabels: false
26 | DerivePointerBinding: false
27 |
--------------------------------------------------------------------------------
/.clang-tidy:
--------------------------------------------------------------------------------
1 | ---
2 | Checks: '
3 | ,readability-avoid-const-params-in-decls,
4 | ,readability-inconsistent-declaration-parameter-name,
5 | ,readability-non-const-parameter,
6 | ,readability-redundant-string-cstr,
7 | ,readability-redundant-string-init,
8 | ,readability-simplify-boolean-expr,
9 | ,cppcoreguidelines-pro-type-cstyle-cast,
10 | '
11 | WarningsAsErrors: '
12 | ,readability-avoid-const-params-in-decls,
13 | ,readability-inconsistent-declaration-parameter-name,
14 | ,readability-non-const-parameter,
15 | ,readability-redundant-string-cstr,
16 | ,readability-redundant-string-init,
17 | ,readability-simplify-boolean-expr,
18 | ,cppcoreguidelines-pro-type-cstyle-cast,
19 | '
20 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | indent_style = space
6 | indent_size = 2
7 | insert_final_newline = true
8 | end_of_line = lf
9 |
10 | [CMakeLists.txt]
11 | indent_style = tab
12 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | # Maintain dependencies for GitHub Actions
4 | - package-ecosystem: "github-actions"
5 | directory: "/"
6 | schedule:
7 | interval: "weekly"
8 |
--------------------------------------------------------------------------------
/.github/workflows/linux-musl.yml:
--------------------------------------------------------------------------------
1 | name: ci-linux-musl
2 |
3 | on:
4 | workflow_dispatch:
5 | pull_request:
6 | push:
7 | release:
8 | types: [published]
9 |
10 | concurrency:
11 | group: ${{ github.workflow }}-${{ github.ref }}
12 | cancel-in-progress: true
13 |
14 | permissions: {}
15 |
16 | jobs:
17 | build:
18 | runs-on: ubuntu-24.04
19 | container: alpine:edge
20 | permissions:
21 | contents: read
22 | strategy:
23 | fail-fast: false
24 | matrix:
25 | build_method: ["python", "cmake"]
26 |
27 | steps:
28 | - name: Host - checkout
29 | uses: actions/checkout@v4
30 | with:
31 | fetch-depth: 0
32 | persist-credentials: false
33 |
34 | - name: Install ninja build optional dependencies
35 | run: apk update && apk add -u --no-cache python3 build-base cmake re2c
36 |
37 | - name: Configure ninja build
38 | if: matrix.build_method == 'cmake'
39 | run: cmake -B build -D CMAKE_BUILD_TYPE="Release"
40 |
41 | - name: Cmake Build ninja
42 | if: matrix.build_method == 'cmake'
43 | run: cmake --build build --parallel --config Release
44 |
45 | - name: Cmake test ninja
46 | if: matrix.build_method == 'cmake'
47 | run: build/ninja_test --gtest_color=yes
48 |
49 | - name: Python Build ninja
50 | if: matrix.build_method == 'python'
51 | run: python3 configure.py --bootstrap --verbose
52 |
53 | - name: Python test ninja
54 | if: matrix.build_method == 'python'
55 | run: |
56 | ./ninja all
57 | python3 misc/ninja_syntax_test.py
58 | # python3 misc/output_test.py
59 |
60 | - name: Move ninja binary
61 | if: matrix.build_method == 'cmake'
62 | run: mv -f build/ninja ninja
63 |
64 | - name: ninja-ninja --version
65 | run: ./ninja --version >> $GITHUB_STEP_SUMMARY
66 |
67 | - name: binary info via file
68 | run: file ./ninja >> $GITHUB_STEP_SUMMARY
69 |
--------------------------------------------------------------------------------
/.github/workflows/macos.yml:
--------------------------------------------------------------------------------
1 | name: macOS
2 |
3 | on:
4 | pull_request:
5 | push:
6 | release:
7 | types: published
8 |
9 | jobs:
10 | build:
11 | runs-on: macos-13
12 |
13 | steps:
14 | - uses: actions/checkout@v4
15 |
16 | - name: Install dependencies
17 | run: brew install re2c p7zip cmake
18 |
19 | - name: Build ninja
20 | shell: bash
21 | env:
22 | MACOSX_DEPLOYMENT_TARGET: 10.15
23 | run: |
24 | cmake -Bbuild -GXcode '-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64'
25 | cmake --build build --config Release
26 |
27 | - name: Test ninja (Release)
28 | run: ./ninja_test
29 | working-directory: build/Release
30 |
31 | - name: Create ninja archive
32 | shell: bash
33 | run: |
34 | mkdir artifact
35 | 7z a artifact/ninja-mac.zip ./build/Release/ninja
36 |
37 | # Upload ninja binary archive as an artifact
38 | - name: Upload artifact
39 | uses: actions/upload-artifact@v4
40 | with:
41 | name: ninja-binary-archives
42 | path: artifact
43 |
44 | - name: Upload release asset
45 | if: github.event.action == 'published'
46 | uses: actions/upload-release-asset@v1
47 | env:
48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
49 | with:
50 | upload_url: ${{ github.event.release.upload_url }}
51 | asset_path: ./artifact/ninja-mac.zip
52 | asset_name: ninja-mac.zip
53 | asset_content_type: application/zip
54 |
--------------------------------------------------------------------------------
/.github/workflows/windows.yml:
--------------------------------------------------------------------------------
1 | name: Windows
2 |
3 | on:
4 | pull_request:
5 | push:
6 | release:
7 | types: published
8 |
9 | jobs:
10 | build:
11 | runs-on: windows-latest
12 |
13 | strategy:
14 | fail-fast: false
15 | matrix:
16 | include:
17 | - arch: 'x64'
18 | suffix: ''
19 | - arch: 'arm64'
20 | suffix: 'arm64'
21 |
22 | steps:
23 | - uses: actions/checkout@v4
24 |
25 | - name: Install dependencies
26 | run: choco install re2c
27 |
28 | - name: Build ninja
29 | shell: bash
30 | run: |
31 | cmake -Bbuild -A ${{ matrix.arch }}
32 | cmake --build build --parallel --config Debug
33 | cmake --build build --parallel --config Release
34 |
35 | - name: Test ninja (Debug)
36 | if: matrix.arch != 'arm64'
37 | run: .\ninja_test.exe
38 | working-directory: build/Debug
39 |
40 | - name: Test ninja (Release)
41 | if: matrix.arch != 'arm64'
42 | run: .\ninja_test.exe
43 | working-directory: build/Release
44 |
45 | - name: Create ninja archive
46 | shell: bash
47 | run: |
48 | mkdir artifact
49 | 7z a artifact/ninja-win${{ matrix.suffix }}.zip ./build/Release/ninja.exe
50 |
51 | # Upload ninja binary archive as an artifact
52 | - name: Upload artifact
53 | uses: actions/upload-artifact@v4
54 | with:
55 | name: ninja-binary-archives${{ matrix.suffix }}
56 | path: artifact
57 |
58 | - name: Upload release asset
59 | if: github.event.action == 'published'
60 | uses: actions/upload-release-asset@v1
61 | env:
62 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63 | with:
64 | upload_url: ${{ github.event.release.upload_url }}
65 | asset_path: ./artifact/ninja-win${{ matrix.suffix }}.zip
66 | asset_name: ninja-win${{ matrix.suffix }}.zip
67 | asset_content_type: application/zip
68 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.obj
3 | *.exe
4 | *.pdb
5 | *.ilk
6 | /build*/
7 | /build.ninja
8 | /ninja
9 | /ninja.bootstrap
10 | /build_log_perftest
11 | /canon_perftest
12 | /clparser_perftest
13 | /elide_middle_perftest
14 | /depfile_parser_perftest
15 | /hash_collision_bench
16 | /ninja_test
17 | /manifest_parser_perftest
18 | /graph.png
19 | /doc/manual.html
20 | /doc/doxygen
21 | *.patch
22 | .DS_Store
23 |
24 | # Eclipse project files
25 | .project
26 | .cproject
27 |
28 | # SublimeText project files
29 | *.sublime-project
30 | *.sublime-workspace
31 |
32 | # Ninja output
33 | .ninja_deps
34 | .ninja_log
35 |
36 | # Visual Studio Code project files
37 | /.vscode/
38 | /.ccls-cache/
39 |
40 | # Qt Creator project files
41 | /CMakeLists.txt.user
42 |
43 | # clangd
44 | /.clangd/
45 | /compile_commands.json
46 | /.cache/
47 |
48 | # Visual Studio files
49 | /.vs/
50 | /out/
51 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # How to successfully make changes to Ninja
2 |
3 | We're very wary of changes that increase the complexity of Ninja (in particular,
4 | new build file syntax or command-line flags) or increase the maintenance burden
5 | of Ninja. Ninja is already successfully used by hundreds of developers for large
6 | projects and it already achieves (most of) the goals we set out for it to do.
7 | It's probably best to discuss new feature ideas on the
8 | [mailing list](https://groups.google.com/forum/#!forum/ninja-build) or in an
9 | issue before creating a PR.
10 |
11 | ## Coding guidelines
12 |
13 | Generally it's the
14 | [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) with
15 | a few additions:
16 |
17 | * We have used `using namespace std;` a lot in the past. For new contributions,
18 | please try to avoid relying on it and instead whenever possible use `std::`.
19 | However, please do not change existing code simply to add `std::` unless your
20 | contribution already needs to change that line of code anyway.
21 | * Use `///` for [Doxygen](http://www.doxygen.nl/) (use `\a` to refer to
22 | arguments).
23 | * It's not necessary to document each argument, especially when they're
24 | relatively self-evident (e.g. in
25 | `CanonicalizePath(string* path, string* err)`, the arguments are hopefully
26 | obvious).
27 |
28 | If you're unsure about code formatting, please use
29 | [clang-format](https://clang.llvm.org/docs/ClangFormat.html). However, please do
30 | not format code that is not otherwise part of your contribution.
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ninja
2 |
3 | Ninja is a small build system with a focus on speed.
4 | https://ninja-build.org/
5 |
6 | See [the manual](https://ninja-build.org/manual.html) or
7 | `doc/manual.asciidoc` included in the distribution for background
8 | and more details.
9 |
10 | Binaries for Linux, Mac and Windows are available on
11 | [GitHub](https://github.com/ninja-build/ninja/releases).
12 | Run `./ninja -h` for Ninja help.
13 |
14 | Installation is not necessary because the only required file is the
15 | resulting ninja binary. However, to enable features like Bash
16 | completion and Emacs and Vim editing modes, some files in misc/ must be
17 | copied to appropriate locations.
18 |
19 | If you're interested in making changes to Ninja, read
20 | [CONTRIBUTING.md](CONTRIBUTING.md) first.
21 |
22 | ## Building Ninja itself
23 |
24 | You can either build Ninja via the custom generator script written in Python or
25 | via CMake. For more details see
26 | [the wiki](https://github.com/ninja-build/ninja/wiki).
27 |
28 | ### Python
29 |
30 | ```
31 | ./configure.py --bootstrap
32 | ```
33 |
34 | This will generate the `ninja` binary and a `build.ninja` file you can now use
35 | to build Ninja with itself.
36 |
37 | If you have a GoogleTest source directory, you can build the tests
38 | by passing its path with `--gtest-source-dir=PATH` option, or the
39 | `GTEST_SOURCE_DIR` environment variable, e.g.:
40 |
41 | ```
42 | ./configure.py --bootstrap --gtest-source-dir=/path/to/googletest
43 | ./ninja all # build ninja_test and other auxiliary binaries
44 | ./ninja_test` # run the unit-test suite.
45 | ```
46 |
47 | Use the CMake build below if you want to use a preinstalled binary
48 | version of the library.
49 |
50 | ### CMake
51 |
52 | To build the ninja binary without building the unit tests, disable test building by setting `BUILD_TESTING` to `OFF`:
53 |
54 | ```
55 | cmake -Bbuild-cmake -DBUILD_TESTING=OFF
56 | cmake --build build-cmake
57 | ```
58 |
59 | The `ninja` binary will now be inside the `build-cmake` directory (you can
60 | choose any other name you like).
61 |
62 | To run the unit tests, omit the `-DBUILD_TESTING=OFF` option, and after building, run:
63 |
64 | ```
65 | ./build-cmake/ninja_test
66 | ```
67 |
68 | ## Generating documentation
69 |
70 | ### Ninja Manual
71 |
72 | You must have `asciidoc` and `xsltproc` in your PATH, then do:
73 |
74 | ```
75 | ./configure.py
76 | ninja manual doc/manual.html
77 | ```
78 |
79 | Which will generate `doc/manual.html`.
80 |
81 | To generate the PDF version of the manual, you must have `dblatext` in your PATH then do:
82 |
83 | ```
84 | ./configure.py # only if you didn't do it previously.
85 | ninja doc/manual.pdf
86 | ```
87 |
88 | Which will generate `doc/manual.pdf`.
89 |
90 | ### Doxygen documentation
91 |
92 | If you have `doxygen` installed, you can build documentation extracted from C++
93 | declarations and comments to help you navigate the code. Note that Ninja is a standalone
94 | executable, not a library, so there is no public API, all details exposed here are
95 | internal.
96 |
97 | ```
98 | ./configure.py # if needed
99 | ninja doxygen
100 | ```
101 |
102 | Then open `doc/doxygen/html/index.html` in a browser to look at it.
103 |
--------------------------------------------------------------------------------
/RELEASING.md:
--------------------------------------------------------------------------------
1 | Notes to myself on all the steps to make for a Ninja release.
2 |
3 | ### Push new release branch:
4 | 1. Run afl-fuzz for a day or so and run ninja_test
5 | 2. Consider sending a heads-up to the ninja-build mailing list first
6 | 3. Make sure branches 'master' and 'release' are synced up locally
7 | 4. Update src/version.cc with new version (with ".git"), then
8 | ```
9 | git commit -am 'mark this 1.5.0.git'
10 | ```
11 | 5. git checkout release; git merge master
12 | 6. Fix version number in src/version.cc (it will likely conflict in the above)
13 | 7. Fix version in doc/manual.asciidoc (exists only on release branch)
14 | 8. commit, tag, push (don't forget to push --tags)
15 | ```
16 | git commit -am v1.5.0; git push origin release
17 | git tag v1.5.0; git push --tags
18 | # Push the 1.5.0.git change on master too:
19 | git checkout master; git push origin master
20 | ```
21 | 9. Construct release notes from prior notes
22 |
23 | credits: `git shortlog -s --no-merges REV..`
24 |
25 |
26 | ### Release on GitHub:
27 | 1. Go to [Tags](https://github.com/ninja-build/ninja/tags)
28 | 2. Open the newly created tag and select "Create release from tag"
29 | 3. Create the release which will trigger a build which automatically attaches
30 | the binaries
31 |
32 | ### Make announcement on mailing list:
33 | 1. copy old mail
34 |
35 | ### Update website:
36 | 1. Make sure your ninja checkout is on the v1.5.0 tag
37 | 2. Clone https://github.com/ninja-build/ninja-build.github.io
38 | 3. In that repo, `./update-docs.sh`
39 | 4. Update index.html with newest version and link to release notes
40 | 5. `git commit -m 'run update-docs.sh, 1.5.0 release'`
41 | 6. `git push origin master`
42 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 1.0.{build}
2 | image:
3 | - Visual Studio 2017
4 | - Ubuntu2204
5 |
6 | environment:
7 | CLICOLOR_FORCE: 1
8 | CHERE_INVOKING: 1 # Tell Bash to inherit the current working directory
9 | matrix:
10 | - MSYSTEM: MINGW64
11 | - MSYSTEM: LINUX
12 |
13 | matrix:
14 | exclude:
15 | - image: Visual Studio 2017
16 | MSYSTEM: LINUX
17 | - image: Ubuntu2204
18 | MSYSTEM: MINGW64
19 |
20 | for:
21 | -
22 | matrix:
23 | only:
24 | - MSYSTEM: MINGW64
25 | build_script:
26 | ps: "C:\\msys64\\usr\\bin\\bash -lc @\"\n
27 | pacman -S --quiet --noconfirm --needed re2c 2>&1\n
28 | ./configure.py --bootstrap --platform mingw 2>&1\n
29 | ./ninja all\n
30 | ./misc/ninja_syntax_test.py 2>&1\n\"@"
31 | - matrix:
32 | only:
33 | - image: Ubuntu2204
34 | build_script:
35 | - ./configure.py --bootstrap
36 | - ./ninja all
37 | - misc/ninja_syntax_test.py
38 | - misc/output_test.py
39 |
40 | test: off
41 |
--------------------------------------------------------------------------------
/doc/README.md:
--------------------------------------------------------------------------------
1 | This directory contains the Ninja manual and support files used in
2 | building it. Here's a brief overview of how it works.
3 |
4 | The source text, `manual.asciidoc`, is written in the AsciiDoc format.
5 | AsciiDoc can generate HTML but it doesn't look great; instead, we use
6 | AsciiDoc to generate the Docbook XML format and then provide our own
7 | Docbook XSL tweaks to produce HTML from that.
8 |
9 | In theory using AsciiDoc and DocBook allows us to produce nice PDF
10 | documentation etc. In reality it's not clear anyone wants that, but the
11 | build rules are in place to generate it if you install dblatex.
12 |
--------------------------------------------------------------------------------
/doc/dblatex.xsl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | 0
6 | 0
7 |
8 |
--------------------------------------------------------------------------------
/doc/docbook.xsl:
--------------------------------------------------------------------------------
1 |
3 |
5 | ]>
6 |
8 |
9 |
10 |
11 |
12 |
13 |
15 |
16 |
17 |
19 | book toc
20 |
21 |
22 | 0
23 |
24 |
25 | 1
26 |
27 |
30 | ul
31 |
32 |
34 |
35 |
--------------------------------------------------------------------------------
/doc/style.css:
--------------------------------------------------------------------------------
1 | :root {
2 | color-scheme: light dark;
3 | }
4 |
5 | body {
6 | margin: 5ex 10ex;
7 | max-width: 80ex;
8 | line-height: 1.5;
9 | font-family: sans-serif;
10 | }
11 |
12 | h1, h2, h3 {
13 | font-weight: normal;
14 | }
15 |
16 | pre, code {
17 | font-family: x, monospace;
18 | }
19 |
20 | pre {
21 | padding: 1ex;
22 | background: #eee;
23 | border: solid 1px #ddd;
24 | min-width: 0;
25 | font-size: 90%;
26 | }
27 | @media (prefers-color-scheme: dark) {
28 | pre {
29 | background: #333;
30 | border: solid 1px #444;
31 | }
32 | }
33 |
34 | code {
35 | color: #007;
36 | }
37 | @media (prefers-color-scheme: dark) {
38 | code {
39 | color: #a7cec8;
40 | }
41 | }
42 |
43 | div.chapter {
44 | margin-top: 4em;
45 | border-top: solid 2px black;
46 | }
47 | @media (prefers-color-scheme: dark) {
48 | div.chapter {
49 | border-top: solid 2px white;
50 | }
51 | }
52 |
53 | p {
54 | margin-top: 0;
55 | }
56 |
57 | /* The following applies to the left column of a [horizontal] labeled list: */
58 | table.horizontal > tbody > tr > td:nth-child(1) {
59 |
60 | /* prevent the insertion of a line-break in the middle of a label: */
61 | white-space: nowrap;
62 |
63 | /* insert a little horizontal padding between the two columns: */
64 | padding-right: 1.5em;
65 |
66 | /* right-justify labels: */
67 | text-align: end;
68 | }
69 |
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/kw_build:
--------------------------------------------------------------------------------
1 | build
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/kw_default:
--------------------------------------------------------------------------------
1 | default
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/kw_include:
--------------------------------------------------------------------------------
1 | include
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/kw_pool:
--------------------------------------------------------------------------------
1 | pool
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/kw_rule:
--------------------------------------------------------------------------------
1 | rule
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/kw_subninja:
--------------------------------------------------------------------------------
1 | subninja
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/misc_a:
--------------------------------------------------------------------------------
1 | a
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/misc_b:
--------------------------------------------------------------------------------
1 | b
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/misc_colon:
--------------------------------------------------------------------------------
1 | :
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/misc_cont:
--------------------------------------------------------------------------------
1 | $
2 |
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/misc_dollar:
--------------------------------------------------------------------------------
1 | $
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/misc_eq:
--------------------------------------------------------------------------------
1 | =
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/misc_indent:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/misc_pipe:
--------------------------------------------------------------------------------
1 | |
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/misc_pipepipe:
--------------------------------------------------------------------------------
1 | ||
--------------------------------------------------------------------------------
/misc/afl-fuzz-tokens/misc_space:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/misc/afl-fuzz/build.ninja:
--------------------------------------------------------------------------------
1 | rule b
2 | command = clang -MMD -MF $out.d -o $out -c $in
3 | description = building $out
4 |
5 | build a.o: b a.c
6 |
--------------------------------------------------------------------------------
/misc/bash-completion:
--------------------------------------------------------------------------------
1 | # Copyright 2011 Google Inc. All Rights Reserved.
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | # Add the following to your .bashrc to tab-complete ninja targets
16 | # . path/to/ninja/misc/bash-completion
17 |
18 | _ninja_target() {
19 | local cur prev targets dir line targets_command OPTIND
20 |
21 | # When available, use bash_completion to:
22 | # 1) Complete words when the cursor is in the middle of the word
23 | # 2) Complete paths with files or directories, as appropriate
24 | if _get_comp_words_by_ref cur prev &>/dev/null ; then
25 | case $prev in
26 | -f)
27 | _filedir
28 | return 0
29 | ;;
30 | -C)
31 | _filedir -d
32 | return 0
33 | ;;
34 | esac
35 | else
36 | cur="${COMP_WORDS[COMP_CWORD]}"
37 | fi
38 |
39 | if [[ "$cur" == "--"* ]]; then
40 | # there is currently only one argument that takes --
41 | COMPREPLY=($(compgen -P '--' -W 'version' -- "${cur:2}"))
42 | else
43 | dir="."
44 | line=$(echo ${COMP_LINE} | cut -d" " -f 2-)
45 | # filter out all non relevant arguments but keep C for dirs
46 | while getopts :C:f:j:l:k:nvd:t: opt $line; do
47 | case $opt in
48 | # eval for tilde expansion
49 | C) eval dir="$OPTARG" ;;
50 | esac
51 | done;
52 | targets_command="eval ninja -C \"${dir}\" -t targets all 2>/dev/null | cut -d: -f1"
53 | COMPREPLY=($(compgen -W '`${targets_command}`' -- "$cur"))
54 | fi
55 | return
56 | }
57 | complete -F _ninja_target ninja
58 |
--------------------------------------------------------------------------------
/misc/ci.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import os
4 |
5 | ignores = [
6 | '.git/',
7 | 'misc/afl-fuzz-tokens/',
8 | 'src/depfile_parser.cc',
9 | 'src/lexer.cc',
10 | ]
11 |
12 | error_count = 0
13 |
14 | def error(path: str, msg: str) -> None:
15 | global error_count
16 | error_count += 1
17 | print('\x1b[1;31m{}\x1b[0;31m{}\x1b[0m'.format(path, msg))
18 |
19 | try:
20 | import git
21 | repo = git.Repo('.')
22 | except:
23 | repo = None
24 |
25 | for root, directory, filenames in os.walk('.'):
26 | for filename in filenames:
27 | path = os.path.join(root, filename)[2:]
28 | if any([path.startswith(x) for x in ignores]) or (repo is not None and repo.ignored(path)):
29 | continue
30 | with open(path, 'rb') as file:
31 | line_nr = 1
32 | try:
33 | for line in [x.decode() for x in file.readlines()]:
34 | if len(line) == 0 or line[-1] != '\n':
35 | error(path, ' missing newline at end of file.')
36 | if len(line) > 1:
37 | if line[-2] == '\r':
38 | error(path, ' has Windows line endings.')
39 | break
40 | if line[-2] == ' ' or line[-2] == '\t':
41 | error(path, ':{} has trailing whitespace.'.format(line_nr))
42 | line_nr += 1
43 | except UnicodeError:
44 | pass # binary file
45 |
46 | exit(error_count)
47 |
--------------------------------------------------------------------------------
/misc/inherited-fds.ninja:
--------------------------------------------------------------------------------
1 | # This build file prints out a list of open file descriptors in
2 | # Ninja subprocesses, to help verify we don't accidentally leak
3 | # any.
4 |
5 | # Because one fd leak was in the code managing multiple subprocesses,
6 | # this test brings up multiple subprocesses and then dumps the fd
7 | # table of the last one.
8 |
9 | # Use like: ./ninja -f misc/inherited-fds.ninja
10 |
11 | rule sleep
12 | command = sleep 10000
13 |
14 | rule dump
15 | command = sleep 1; ls -l /proc/self/fd; exit 1
16 |
17 | build all: phony a b c d e
18 |
19 | build a: sleep
20 | build b: sleep
21 | build c: sleep
22 | build d: sleep
23 | build e: dump
24 |
--------------------------------------------------------------------------------
/misc/jobserver_test_helper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # Copyright 2024 Google Inc. All Rights Reserved.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | """Simple utility used by the jobserver test. Wait for specific time, then write start/stop times to output file."""
17 |
18 | import argparse
19 | import time
20 | import sys
21 | from pathlib import Path
22 |
23 |
24 | def main():
25 | parser = argparse.ArgumentParser(description=__doc__)
26 | parser.add_argument(
27 | "--duration-ms",
28 | default="50",
29 | help="sleep duration in milliseconds (default 50)",
30 | )
31 | parser.add_argument("output_file", type=Path, help="output file name.")
32 | args = parser.parse_args()
33 |
34 | now_time_ns = time.time_ns()
35 | time.sleep(int(args.duration_ms) / 1000.0)
36 | args.output_file.write_text(f"{now_time_ns}\n{time.time_ns()}\n")
37 |
38 | return 0
39 |
40 |
41 | if __name__ == "__main__":
42 | sys.exit(main())
43 |
--------------------------------------------------------------------------------
/misc/long-slow-build.ninja:
--------------------------------------------------------------------------------
1 | # An input file for running a "slow" build.
2 | # Use like: ninja -f misc/long-slow-build.ninja all
3 |
4 | rule sleep
5 | command = sleep 1
6 | description = SLEEP $out
7 |
8 | build 0: sleep README
9 | build 1: sleep README
10 | build 2: sleep README
11 | build 3: sleep README
12 | build 4: sleep README
13 | build 5: sleep README
14 | build 6: sleep README
15 | build 7: sleep README
16 | build 8: sleep README
17 | build 9: sleep README
18 | build 10: sleep 0
19 | build 11: sleep 1
20 | build 12: sleep 2
21 | build 13: sleep 3
22 | build 14: sleep 4
23 | build 15: sleep 5
24 | build 16: sleep 6
25 | build 17: sleep 7
26 | build 18: sleep 8
27 | build 19: sleep 9
28 | build 20: sleep 10
29 | build 21: sleep 11
30 | build 22: sleep 12
31 | build 23: sleep 13
32 | build 24: sleep 14
33 | build 25: sleep 15
34 | build 26: sleep 16
35 | build 27: sleep 17
36 | build 28: sleep 18
37 | build 29: sleep 19
38 | build all: phony 20 21 22 23 24 25 26 27 28 29
39 |
--------------------------------------------------------------------------------
/misc/manifest_fuzzer.cc:
--------------------------------------------------------------------------------
1 | // Copyright 2020 Google Inc. All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include "stdint.h"
16 | #include
17 | #include "disk_interface.h"
18 | #include "state.h"
19 | #include "manifest_parser.h"
20 | #include
21 |
22 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
23 | {
24 | char build_file[256];
25 | sprintf(build_file, "/tmp/build.ninja");
26 | FILE *fp = fopen(build_file, "wb");
27 | if (!fp)
28 | return 0;
29 | fwrite(data, size, 1, fp);
30 | fclose(fp);
31 |
32 | std::string err;
33 | RealDiskInterface disk_interface;
34 | State state;
35 | ManifestParser parser(&state, &disk_interface);
36 |
37 | parser.Load("/tmp/build.ninja", &err);
38 |
39 | std::__fs::filesystem::remove_all("/tmp/build.ninja");
40 | return 0;
41 | }
42 |
--------------------------------------------------------------------------------
/misc/measure.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | # Copyright 2011 Google Inc. All Rights Reserved.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 |
17 | """measure the runtime of a command by repeatedly running it.
18 | """
19 |
20 | import time
21 | import subprocess
22 | import sys
23 | from typing import Union, List
24 |
25 | devnull = open('/dev/null', 'w')
26 |
27 | def run(cmd: Union[str, List[str]], repeat: int = 10) -> None:
28 | print('sampling:', end=' ')
29 | sys.stdout.flush()
30 |
31 | samples = []
32 | for _ in range(repeat):
33 | start = time.time()
34 | subprocess.call(cmd, stdout=devnull, stderr=devnull)
35 | end = time.time()
36 | dt = (end - start) * 1000
37 | print('%dms' % int(dt), end=' ')
38 | sys.stdout.flush()
39 | samples.append(dt)
40 | print()
41 |
42 | # We're interested in the 'pure' runtime of the code, which is
43 | # conceptually the smallest time we'd see if we ran it enough times
44 | # such that it got the perfect time slices / disk cache hits.
45 | best = min(samples)
46 | # Also print how varied the outputs were in an attempt to make it
47 | # more obvious if something has gone terribly wrong.
48 | err = sum(s - best for s in samples) / float(len(samples))
49 | print('estimate: %dms (mean err %.1fms)' % (best, err))
50 |
51 | if __name__ == '__main__':
52 | if len(sys.argv) < 2:
53 | print('usage: measure.py command args...')
54 | sys.exit(1)
55 | run(cmd=sys.argv[1:])
56 |
--------------------------------------------------------------------------------
/misc/ninja.vim:
--------------------------------------------------------------------------------
1 | " ninja build file syntax.
2 | " Language: ninja build file as described at
3 | " http://ninja-build.org/manual.html
4 | " Version: 1.5
5 | " Last Change: 2018/04/05
6 | " Maintainer: Nicolas Weber
7 | " Version 1.4 of this script is in the upstream vim repository and will be
8 | " included in the next vim release. If you change this, please send your change
9 | " upstream.
10 |
11 | " ninja lexer and parser are at
12 | " https://github.com/ninja-build/ninja/blob/master/src/lexer.in.cc
13 | " https://github.com/ninja-build/ninja/blob/master/src/manifest_parser.cc
14 |
15 | if exists("b:current_syntax")
16 | finish
17 | endif
18 |
19 | let s:cpo_save = &cpo
20 | set cpo&vim
21 |
22 | syn case match
23 |
24 | " Comments are only matched when the # is at the beginning of the line (with
25 | " optional whitespace), as long as the prior line didn't end with a $
26 | " continuation.
27 | syn match ninjaComment /\(\$\n\)\@"
33 | syn match ninjaKeyword "^rule\>"
34 | syn match ninjaKeyword "^pool\>"
35 | syn match ninjaKeyword "^default\>"
36 | syn match ninjaKeyword "^include\>"
37 | syn match ninjaKeyword "^subninja\>"
38 |
39 | " Both 'build' and 'rule' begin a variable scope that ends
40 | " on the first line without indent. 'rule' allows only a
41 | " limited set of magic variables, 'build' allows general
42 | " let assignments.
43 | " manifest_parser.cc, ParseRule()
44 | syn region ninjaRule start="^rule" end="^\ze\S" contains=TOP transparent
45 | syn keyword ninjaRuleCommand contained containedin=ninjaRule command
46 | \ deps depfile description generator
47 | \ pool restat rspfile rspfile_content
48 |
49 | syn region ninjaPool start="^pool" end="^\ze\S" contains=TOP transparent
50 | syn keyword ninjaPoolCommand contained containedin=ninjaPool depth
51 |
52 | " Strings are parsed as follows:
53 | " lexer.in.cc, ReadEvalString()
54 | " simple_varname = [a-zA-Z0-9_-]+;
55 | " varname = [a-zA-Z0-9_.-]+;
56 | " $$ -> $
57 | " $\n -> line continuation
58 | " '$ ' -> escaped space
59 | " $simple_varname -> variable
60 | " ${varname} -> variable
61 |
62 | syn match ninjaDollar "\$\$"
63 | syn match ninjaWrapLineOperator "\$$"
64 | syn match ninjaSimpleVar "\$[a-zA-Z0-9_-]\+"
65 | syn match ninjaVar "\${[a-zA-Z0-9_.-]\+}"
66 |
67 | " operators are:
68 | " variable assignment =
69 | " rule definition :
70 | " implicit dependency |
71 | " order-only dependency ||
72 | syn match ninjaOperator "\(=\|:\||\|||\)\ze\s"
73 |
74 | hi def link ninjaComment Comment
75 | hi def link ninjaKeyword Keyword
76 | hi def link ninjaRuleCommand Statement
77 | hi def link ninjaPoolCommand Statement
78 | hi def link ninjaDollar ninjaOperator
79 | hi def link ninjaWrapLineOperator ninjaOperator
80 | hi def link ninjaOperator Operator
81 | hi def link ninjaSimpleVar ninjaVar
82 | hi def link ninjaVar Identifier
83 |
84 | let b:current_syntax = "ninja"
85 |
86 | let &cpo = s:cpo_save
87 | unlet s:cpo_save
88 |
--------------------------------------------------------------------------------
/misc/oss-fuzz/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -eu
2 | # Copyright 2020 Google Inc.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 | ################################################################################
17 |
18 | cmake -Bbuild-cmake -H.
19 | cmake --build build-cmake
20 |
21 | cd $SRC/ninja/misc
22 |
23 | $CXX $CXXFLAGS -fdiagnostics-color -I/src/ninja/src -o fuzzer.o -c manifest_fuzzer.cc
24 |
25 | find .. -name "*.o" -exec ar rcs fuzz_lib.a {} \;
26 |
27 | $CXX $CXXFLAGS $LIB_FUZZING_ENGINE fuzzer.o -o $OUT/fuzzer fuzz_lib.a
28 |
29 | zip $OUT/fuzzer_seed_corpus.zip $SRC/sample_ninja_build
30 |
--------------------------------------------------------------------------------
/misc/oss-fuzz/sample_ninja_build:
--------------------------------------------------------------------------------
1 | # build.ninja
2 | cc = clang
3 | cflags = -Weverything
4 |
5 | rule compile
6 | command = $cc $cflags -c $in -o $out
7 |
8 | rule link
9 | command = $cc $in -o $out
10 |
11 | build hello.o: compile hello.c
12 | build hello: link hello.o
13 |
14 | default hello
15 |
--------------------------------------------------------------------------------
/misc/packaging/ninja.spec:
--------------------------------------------------------------------------------
1 | Summary: Ninja is a small build system with a focus on speed.
2 | Name: ninja
3 | Version: %{ver}
4 | Release: %{rel}%{?dist}
5 | Group: Development/Tools
6 | License: Apache 2.0
7 | URL: https://github.com/ninja-build/ninja
8 | Source0: %{name}-%{version}-%{rel}.tar.gz
9 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{rel}
10 |
11 | BuildRequires: asciidoc
12 |
13 | %description
14 | Ninja is yet another build system. It takes as input the interdependencies of files (typically source code and output executables) and
15 | orchestrates building them, quickly.
16 |
17 | Ninja joins a sea of other build systems. Its distinguishing goal is to be fast. It is born from my work on the Chromium browser project,
18 | which has over 30,000 source files and whose other build systems (including one built from custom non-recursive Makefiles) can take ten
19 | seconds to start building after changing one file. Ninja is under a second.
20 |
21 | %prep
22 | %setup -q -n %{name}-%{version}-%{rel}
23 |
24 | %build
25 | echo Building..
26 | ./configure.py --bootstrap
27 | ./ninja manual
28 |
29 | %install
30 | mkdir -p %{buildroot}%{_bindir} %{buildroot}%{_docdir}
31 | cp -p ninja %{buildroot}%{_bindir}/
32 |
33 | %files
34 | %defattr(-, root, root)
35 | %doc COPYING README.md doc/manual.html
36 | %{_bindir}/*
37 |
38 | %clean
39 | rm -rf %{buildroot}
40 |
41 | #The changelog is built automatically from Git history
42 | %changelog
43 |
--------------------------------------------------------------------------------
/misc/packaging/rpmbuild.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | echo Building ninja RPMs..
4 | GITROOT=$(git rev-parse --show-toplevel)
5 | cd $GITROOT
6 |
7 | VER=1.0
8 | REL=$(git rev-parse --short HEAD)git
9 | RPMTOPDIR=$GITROOT/rpm-build
10 | echo "Ver: $VER, Release: $REL"
11 |
12 | # Create tarball
13 | mkdir -p $RPMTOPDIR/{SOURCES,SPECS}
14 | git archive --format=tar --prefix=ninja-${VER}-${REL}/ HEAD | gzip -c > $RPMTOPDIR/SOURCES/ninja-${VER}-${REL}.tar.gz
15 |
16 | # Convert git log to RPM's ChangeLog format (shown with rpm -qp --changelog )
17 | sed -e "s/%{ver}/$VER/" -e "s/%{rel}/$REL/" misc/packaging/ninja.spec > $RPMTOPDIR/SPECS/ninja.spec
18 | git log --format="* %cd %aN%n- (%h) %s%d%n" --date=local | sed -r 's/[0-9]+:[0-9]+:[0-9]+ //' >> $RPMTOPDIR/SPECS/ninja.spec
19 |
20 | # Build SRC and binary RPMs
21 | rpmbuild --quiet \
22 | --define "_topdir $RPMTOPDIR" \
23 | --define "_rpmdir $PWD" \
24 | --define "_srcrpmdir $PWD" \
25 | --define '_rpmfilename %%{NAME}-%%{VERSION}-%%{RELEASE}.%%{ARCH}.rpm' \
26 | -ba $RPMTOPDIR/SPECS/ninja.spec &&
27 |
28 | rm -rf $RPMTOPDIR &&
29 | echo Done
30 |
--------------------------------------------------------------------------------
/misc/zsh-completion:
--------------------------------------------------------------------------------
1 | #compdef ninja
2 | # Copyright 2011 Google Inc. All Rights Reserved.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | # Add the following to your .zshrc to tab-complete ninja targets
17 | # fpath=(path/to/ninja/misc/zsh-completion $fpath)
18 |
19 | (( $+functions[_ninja-get-targets] )) || _ninja-get-targets() {
20 | dir="."
21 | if [ -n "${opt_args[-C]}" ];
22 | then
23 | eval dir="${opt_args[-C]}"
24 | fi
25 | file="build.ninja"
26 | if [ -n "${opt_args[-f]}" ];
27 | then
28 | eval file="${opt_args[-f]}"
29 | fi
30 | targets_command="ninja -f \"${file}\" -C \"${dir}\" -t targets all"
31 | eval ${targets_command} 2>/dev/null | cut -d: -f1
32 | }
33 |
34 | (( $+functions[_ninja-get-tools] )) || _ninja-get-tools() {
35 | # remove the first line; remove the leading spaces; replace spaces with colon
36 | ninja -t list 2> /dev/null | sed -e '1d;s/^ *//;s/ \+/:/'
37 | }
38 |
39 | (( $+functions[_ninja-get-modes] )) || _ninja-get-modes() {
40 | # remove the first line; remove the last line; remove the leading spaces; replace spaces with colon
41 | ninja -d list 2> /dev/null | sed -e '1d;$d;s/^ *//;s/ \+/:/'
42 | }
43 |
44 | (( $+functions[_ninja-modes] )) || _ninja-modes() {
45 | local -a modes
46 | modes=(${(fo)"$(_ninja-get-modes)"})
47 | _describe 'modes' modes
48 | }
49 |
50 | (( $+functions[_ninja-tools] )) || _ninja-tools() {
51 | local -a tools
52 | tools=(${(fo)"$(_ninja-get-tools)"})
53 | _describe 'tools' tools
54 | }
55 |
56 | (( $+functions[_ninja-targets] )) || _ninja-targets() {
57 | local -a targets
58 | targets=(${(fo)"$(_ninja-get-targets)"})
59 | _describe 'targets' targets
60 | }
61 |
62 | _arguments \
63 | '(- *)'{-h,--help}'[Show help]' \
64 | '(- *)--version[Print ninja version]' \
65 | '-C+[Change to directory before doing anything else]:directories:_directories' \
66 | '-f+[Specify input build file (default=build.ninja)]:files:_files' \
67 | '-j+[Run N jobs in parallel (default=number of CPUs available)]:number of jobs' \
68 | '-l+[Do not start new jobs if the load average is greater than N]:number of jobs' \
69 | '-k+[Keep going until N jobs fail (default=1)]:number of jobs' \
70 | '-n[Dry run (do not run commands but act like they succeeded)]' \
71 | '(-v --verbose --quiet)'{-v,--verbose}'[Show all command lines while building]' \
72 | "(-v --verbose --quiet)--quiet[Don't show progress status, just command output]" \
73 | '-d+[Enable debugging (use -d list to list modes)]:modes:_ninja-modes' \
74 | '-t+[Run a subtool (use -t list to list subtools)]:tools:_ninja-tools' \
75 | '*::targets:_ninja-targets'
76 |
--------------------------------------------------------------------------------
/src/browse.cc:
--------------------------------------------------------------------------------
1 | // Copyright 2011 Google Inc. All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include "browse.h"
16 |
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | #include "build/browse_py.h"
24 |
25 | using namespace std;
26 |
27 | void RunBrowsePython(State* state, const char* ninja_command,
28 | const char* input_file, int argc, char* argv[]) {
29 | // Fork off a Python process and have it run our code via its stdin.
30 | // (Actually the Python process becomes the parent.)
31 | int pipefd[2];
32 | if (pipe(pipefd) < 0) {
33 | perror("ninja: pipe");
34 | return;
35 | }
36 |
37 | pid_t pid = fork();
38 | if (pid < 0) {
39 | perror("ninja: fork");
40 | return;
41 | }
42 |
43 | if (pid > 0) { // Parent.
44 | close(pipefd[1]);
45 | do {
46 | if (dup2(pipefd[0], 0) < 0) {
47 | perror("ninja: dup2");
48 | break;
49 | }
50 |
51 | std::vector command;
52 | command.push_back(NINJA_PYTHON);
53 | command.push_back("-");
54 | command.push_back("--ninja-command");
55 | command.push_back(ninja_command);
56 | command.push_back("-f");
57 | command.push_back(input_file);
58 | for (int i = 0; i < argc; i++) {
59 | command.push_back(argv[i]);
60 | }
61 | command.push_back(NULL);
62 | execvp(command[0], const_cast(&command[0]));
63 | if (errno == ENOENT) {
64 | printf("ninja: %s is required for the browse tool\n", NINJA_PYTHON);
65 | } else {
66 | perror("ninja: execvp");
67 | }
68 | } while (false);
69 | _exit(1);
70 | } else { // Child.
71 | close(pipefd[0]);
72 |
73 | // Write the script file into the stdin of the Python process.
74 | // Only write n - 1 bytes, because Python 3.11 does not allow null
75 | // bytes in source code anymore, so avoid writing the null string
76 | // terminator.
77 | // See https://github.com/python/cpython/issues/96670
78 | auto kBrowsePyLength = sizeof(kBrowsePy) - 1;
79 | ssize_t len = write(pipefd[1], kBrowsePy, kBrowsePyLength);
80 | if (len < (ssize_t)kBrowsePyLength)
81 | perror("ninja: write");
82 | close(pipefd[1]);
83 | exit(0);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/browse.h:
--------------------------------------------------------------------------------
1 | // Copyright 2011 Google Inc. All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef NINJA_BROWSE_H_
16 | #define NINJA_BROWSE_H_
17 |
18 | struct State;
19 |
20 | /// Run in "browse" mode, which execs a Python webserver.
21 | /// \a ninja_command is the command used to invoke ninja.
22 | /// \a args are the number of arguments to be passed to the Python script.
23 | /// \a argv are arguments to be passed to the Python script.
24 | /// This function does not return if it runs successfully.
25 | void RunBrowsePython(State* state, const char* ninja_command,
26 | const char* input_file, int argc, char* argv[]);
27 |
28 | #endif // NINJA_BROWSE_H_
29 |
--------------------------------------------------------------------------------
/src/build_log.h:
--------------------------------------------------------------------------------
1 | // Copyright 2011 Google Inc. All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef NINJA_BUILD_LOG_H_
16 | #define NINJA_BUILD_LOG_H_
17 |
18 | #include
19 |
20 | #include
21 | #include
22 |
23 | #include "hash_map.h"
24 | #include "load_status.h"
25 | #include "timestamp.h"
26 | #include "util.h" // uint64_t
27 |
28 | struct DiskInterface;
29 | struct Edge;
30 |
31 | /// Can answer questions about the manifest for the BuildLog.
32 | struct BuildLogUser {
33 | /// Return if a given output is no longer part of the build manifest.
34 | /// This is only called during recompaction and doesn't have to be fast.
35 | virtual bool IsPathDead(StringPiece s) const = 0;
36 | };
37 |
38 | /// Store a log of every command ran for every build.
39 | /// It has a few uses:
40 | ///
41 | /// 1) (hashes of) command lines for existing output files, so we know
42 | /// when we need to rebuild due to the command changing
43 | /// 2) timing information, perhaps for generating reports
44 | /// 3) restat information
45 | struct BuildLog {
46 | BuildLog();
47 | ~BuildLog();
48 |
49 | /// Prepares writing to the log file without actually opening it - that will
50 | /// happen when/if it's needed
51 | bool OpenForWrite(const std::string& path, const BuildLogUser& user,
52 | std::string* err);
53 | bool RecordCommand(Edge* edge, int start_time, int end_time,
54 | TimeStamp mtime = 0);
55 | void Close();
56 |
57 | /// Load the on-disk log.
58 | LoadStatus Load(const std::string& path, std::string* err);
59 |
60 | struct LogEntry {
61 | std::string output;
62 | uint64_t command_hash = 0;
63 | int start_time = 0;
64 | int end_time = 0;
65 | TimeStamp mtime = 0;
66 |
67 | static uint64_t HashCommand(StringPiece command);
68 |
69 | // Used by tests.
70 | bool operator==(const LogEntry& o) const {
71 | return output == o.output && command_hash == o.command_hash &&
72 | start_time == o.start_time && end_time == o.end_time &&
73 | mtime == o.mtime;
74 | }
75 |
76 | explicit LogEntry(std::string output);
77 | LogEntry(const std::string& output, uint64_t command_hash,
78 | int start_time, int end_time, TimeStamp mtime);
79 | };
80 |
81 | /// Lookup a previously-run command by its output path.
82 | LogEntry* LookupByOutput(const std::string& path);
83 |
84 | /// Serialize an entry into a log file.
85 | bool WriteEntry(FILE* f, const LogEntry& entry);
86 |
87 | /// Rewrite the known log entries, throwing away old data.
88 | bool Recompact(const std::string& path, const BuildLogUser& user,
89 | std::string* err);
90 |
91 | /// Restat all outputs in the log
92 | bool Restat(StringPiece path, const DiskInterface& disk_interface,
93 | int output_count, char** outputs, std::string* err);
94 |
95 | typedef ExternalStringHashMap>::Type Entries;
96 | const Entries& entries() const { return entries_; }
97 |
98 | private:
99 | /// Should be called before using log_file_. When false is returned, errno
100 | /// will be set.
101 | bool OpenForWriteIfNeeded();
102 |
103 | Entries entries_;
104 | FILE* log_file_ = nullptr;
105 | std::string log_file_path_;
106 | bool needs_recompaction_ = false;
107 | };
108 |
109 | #endif // NINJA_BUILD_LOG_H_
110 |
--------------------------------------------------------------------------------
/src/build_log_perftest.cc:
--------------------------------------------------------------------------------
1 | // Copyright 2012 Google Inc. All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include
16 | #include
17 |
18 | #include "build_log.h"
19 | #include "graph.h"
20 | #include "manifest_parser.h"
21 | #include "state.h"
22 | #include "util.h"
23 | #include "metrics.h"
24 |
25 | #ifndef _WIN32
26 | #include
27 | #endif
28 |
29 | using namespace std;
30 |
31 | const char kTestFilename[] = "BuildLogPerfTest-tempfile";
32 |
33 | struct NoDeadPaths : public BuildLogUser {
34 | virtual bool IsPathDead(StringPiece) const { return false; }
35 | };
36 |
37 | bool WriteTestData(string* err) {
38 | BuildLog log;
39 |
40 | NoDeadPaths no_dead_paths;
41 | if (!log.OpenForWrite(kTestFilename, no_dead_paths, err))
42 | return false;
43 |
44 | /*
45 | A histogram of command lengths in chromium. For example, 407 builds,
46 | 1.4% of all builds, had commands longer than 32 bytes but shorter than 64.
47 | 32 407 1.4%
48 | 64 183 0.6%
49 | 128 1461 5.1%
50 | 256 791 2.8%
51 | 512 1314 4.6%
52 | 1024 6114 21.3%
53 | 2048 11759 41.0%
54 | 4096 2056 7.2%
55 | 8192 4567 15.9%
56 | 16384 13 0.0%
57 | 32768 4 0.0%
58 | 65536 5 0.0%
59 | The average command length is 4.1 kB and there were 28674 commands in total,
60 | which makes for a total log size of ~120 MB (also counting output filenames).
61 |
62 | Based on this, write 30000 many 4 kB long command lines.
63 | */
64 |
65 | // ManifestParser is the only object allowed to create Rules.
66 | const size_t kRuleSize = 4000;
67 | string long_rule_command = "gcc ";
68 | for (int i = 0; long_rule_command.size() < kRuleSize; ++i) {
69 | char buf[80];
70 | sprintf(buf, "-I../../and/arbitrary/but/fairly/long/path/suffixed/%d ", i);
71 | long_rule_command += buf;
72 | }
73 | long_rule_command += "$in -o $out\n";
74 |
75 | State state;
76 | ManifestParser parser(&state, NULL);
77 | if (!parser.ParseTest("rule cxx\n command = " + long_rule_command, err))
78 | return false;
79 |
80 | // Create build edges. Using ManifestParser is as fast as using the State api
81 | // for edge creation, so just use that.
82 | const int kNumCommands = 30000;
83 | string build_rules;
84 | for (int i = 0; i < kNumCommands; ++i) {
85 | char buf[80];
86 | sprintf(buf, "build input%d.o: cxx input%d.cc\n", i, i);
87 | build_rules += buf;
88 | }
89 |
90 | if (!parser.ParseTest(build_rules, err))
91 | return false;
92 |
93 | for (int i = 0; i < kNumCommands; ++i) {
94 | log.RecordCommand(state.edges_[i],
95 | /*start_time=*/100 * i,
96 | /*end_time=*/100 * i + 1,
97 | /*mtime=*/0);
98 | }
99 |
100 | return true;
101 | }
102 |
103 | int main() {
104 | vector times;
105 | string err;
106 |
107 | if (!WriteTestData(&err)) {
108 | fprintf(stderr, "Failed to write test data: %s\n", err.c_str());
109 | return 1;
110 | }
111 |
112 | {
113 | // Read once to warm up disk cache.
114 | BuildLog log;
115 | if (log.Load(kTestFilename, &err) == LOAD_ERROR) {
116 | fprintf(stderr, "Failed to read test data: %s\n", err.c_str());
117 | return 1;
118 | }
119 | }
120 | const int kNumRepetitions = 5;
121 | for (int i = 0; i < kNumRepetitions; ++i) {
122 | int64_t start = GetTimeMillis();
123 | BuildLog log;
124 | if (log.Load(kTestFilename, &err) == LOAD_ERROR) {
125 | fprintf(stderr, "Failed to read test data: %s\n", err.c_str());
126 | return 1;
127 | }
128 | int delta = (int)(GetTimeMillis() - start);
129 | printf("%dms\n", delta);
130 | times.push_back(delta);
131 | }
132 |
133 | int min = times[0];
134 | int max = times[0];
135 | float total = 0;
136 | for (size_t i = 0; i < times.size(); ++i) {
137 | total += times[i];
138 | if (times[i] < min)
139 | min = times[i];
140 | else if (times[i] > max)
141 | max = times[i];
142 | }
143 |
144 | printf("min %dms max %dms avg %.1fms\n",
145 | min, max, total / times.size());
146 |
147 | platformAwareUnlink(kTestFilename);
148 |
149 | return 0;
150 | }
151 |
--------------------------------------------------------------------------------
/src/canon_perftest.cc:
--------------------------------------------------------------------------------
1 | // Copyright 2012 Google Inc. All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include
16 | #include
17 |
18 | #include "util.h"
19 | #include "metrics.h"
20 |
21 | using namespace std;
22 |
23 | const char kPath[] =
24 | "../../third_party/WebKit/Source/WebCore/"
25 | "platform/leveldb/LevelDBWriteBatch.cpp";
26 |
27 | int main() {
28 | vector times;
29 |
30 | char buf[200];
31 | size_t len = strlen(kPath);
32 | strcpy(buf, kPath);
33 |
34 | for (int j = 0; j < 5; ++j) {
35 | const int kNumRepetitions = 2000000;
36 | int64_t start = GetTimeMillis();
37 | uint64_t slash_bits;
38 | for (int i = 0; i < kNumRepetitions; ++i) {
39 | CanonicalizePath(buf, &len, &slash_bits);
40 | }
41 | int delta = (int)(GetTimeMillis() - start);
42 | times.push_back(delta);
43 | }
44 |
45 | int min = times[0];
46 | int max = times[0];
47 | float total = 0;
48 | for (size_t i = 0; i < times.size(); ++i) {
49 | total += times[i];
50 | if (times[i] < min)
51 | min = times[i];
52 | else if (times[i] > max)
53 | max = times[i];
54 | }
55 |
56 | printf("min %dms max %dms avg %.1fms\n",
57 | min, max, total / times.size());
58 | }
59 |
--------------------------------------------------------------------------------
/src/clean.h:
--------------------------------------------------------------------------------
1 | // Copyright 2011 Google Inc. All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef NINJA_CLEAN_H_
16 | #define NINJA_CLEAN_H_
17 |
18 | #include
19 | #include
20 |
21 | #include "build.h"
22 | #include "dyndep.h"
23 | #include "build_log.h"
24 |
25 | struct State;
26 | struct Node;
27 | struct Rule;
28 | struct DiskInterface;
29 |
30 | struct Cleaner {
31 | /// Build a cleaner object with the given @a disk_interface
32 | Cleaner(State* state,
33 | const BuildConfig& config,
34 | DiskInterface* disk_interface);
35 |
36 | /// Clean the given @a target and all the file built for it.
37 | /// @return non-zero if an error occurs.
38 | int CleanTarget(Node* target);
39 | /// Clean the given target @a target.
40 | /// @return non-zero if an error occurs.
41 | int CleanTarget(const char* target);
42 | /// Clean the given target @a targets.
43 | /// @return non-zero if an error occurs.
44 | int CleanTargets(int target_count, char* targets[]);
45 |
46 | /// Clean all built files, except for files created by generator rules.
47 | /// @param generator If set, also clean files created by generator rules.
48 | /// @return non-zero if an error occurs.
49 | int CleanAll(bool generator = false);
50 |
51 | /// Clean all the file built with the given rule @a rule.
52 | /// @return non-zero if an error occurs.
53 | int CleanRule(const Rule* rule);
54 | /// Clean the file produced by the given @a rule.
55 | /// @return non-zero if an error occurs.
56 | int CleanRule(const char* rule);
57 | /// Clean the file produced by the given @a rules.
58 | /// @return non-zero if an error occurs.
59 | int CleanRules(int rule_count, char* rules[]);
60 | /// Clean the files produced by previous builds that are no longer in the
61 | /// manifest.
62 | /// @return non-zero if an error occurs.
63 | int CleanDead(const BuildLog::Entries& entries);
64 |
65 | /// @return the number of file cleaned.
66 | int cleaned_files_count() const {
67 | return cleaned_files_count_;
68 | }
69 |
70 | /// @return whether the cleaner is in verbose mode.
71 | bool IsVerbose() const {
72 | return (config_.verbosity != BuildConfig::QUIET
73 | && (config_.verbosity == BuildConfig::VERBOSE || config_.dry_run));
74 | }
75 |
76 | private:
77 | /// Remove the file @a path.
78 | /// @return whether the file has been removed.
79 | int RemoveFile(const std::string& path);
80 | /// @returns whether the file @a path exists.
81 | bool FileExists(const std::string& path);
82 | void Report(const std::string& path);
83 |
84 | /// Remove the given @a path file only if it has not been already removed.
85 | void Remove(const std::string& path);
86 | /// @return whether the given @a path has already been removed.
87 | bool IsAlreadyRemoved(const std::string& path);
88 | /// Remove the depfile and rspfile for an Edge.
89 | void RemoveEdgeFiles(Edge* edge);
90 |
91 | /// Helper recursive method for CleanTarget().
92 | void DoCleanTarget(Node* target);
93 | void PrintHeader();
94 | void PrintFooter();
95 | void DoCleanRule(const Rule* rule);
96 | void Reset();
97 |
98 | /// Load dependencies from dyndep bindings.
99 | void LoadDyndeps();
100 |
101 | State* state_;
102 | const BuildConfig& config_;
103 | DyndepLoader dyndep_loader_;
104 | std::set removed_;
105 | std::set cleaned_;
106 | int cleaned_files_count_;
107 | DiskInterface* disk_interface_;
108 | int status_;
109 | };
110 |
111 | #endif // NINJA_CLEAN_H_
112 |
--------------------------------------------------------------------------------
/src/clparser.cc:
--------------------------------------------------------------------------------
1 | // Copyright 2015 Google Inc. All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include "clparser.h"
16 |
17 | #include
18 | #include
19 | #include
20 |
21 | #include "metrics.h"
22 | #include "string_piece_util.h"
23 |
24 | #ifdef _WIN32
25 | #include "includes_normalize.h"
26 | #include "string_piece.h"
27 | #else
28 | #include "util.h"
29 | #endif
30 |
31 | using namespace std;
32 |
33 | namespace {
34 |
35 | /// Return true if \a input ends with \a needle.
36 | bool EndsWith(const string& input, const string& needle) {
37 | return (input.size() >= needle.size() &&
38 | input.substr(input.size() - needle.size()) == needle);
39 | }
40 |
41 | } // anonymous namespace
42 |
43 | // static
44 | string CLParser::FilterShowIncludes(const string& line,
45 | const string& deps_prefix) {
46 | const string kDepsPrefixEnglish = "Note: including file: ";
47 | const char* in = line.c_str();
48 | const char* end = in + line.size();
49 | const string& prefix = deps_prefix.empty() ? kDepsPrefixEnglish : deps_prefix;
50 | if (end - in > (int)prefix.size() &&
51 | memcmp(in, prefix.c_str(), (int)prefix.size()) == 0) {
52 | in += prefix.size();
53 | while (*in == ' ')
54 | ++in;
55 | return line.substr(in - line.c_str());
56 | }
57 | return "";
58 | }
59 |
60 | // static
61 | bool CLParser::IsSystemInclude(string path) {
62 | transform(path.begin(), path.end(), path.begin(), ToLowerASCII);
63 | // TODO: this is a heuristic, perhaps there's a better way?
64 | return (path.find("program files") != string::npos ||
65 | path.find("microsoft visual studio") != string::npos);
66 | }
67 |
68 | // static
69 | bool CLParser::FilterInputFilename(string line) {
70 | transform(line.begin(), line.end(), line.begin(), ToLowerASCII);
71 | // TODO: other extensions, like .asm?
72 | return EndsWith(line, ".c") ||
73 | EndsWith(line, ".cc") ||
74 | EndsWith(line, ".cxx") ||
75 | EndsWith(line, ".cpp") ||
76 | EndsWith(line, ".c++");
77 | }
78 |
79 | // static
80 | bool CLParser::Parse(const string& output, const string& deps_prefix,
81 | string* filtered_output, string* err) {
82 | METRIC_RECORD("CLParser::Parse");
83 |
84 | // Loop over all lines in the output to process them.
85 | assert(&output != filtered_output);
86 | size_t start = 0;
87 | bool seen_show_includes = false;
88 | #ifdef _WIN32
89 | IncludesNormalize normalizer(".");
90 | #endif
91 |
92 | while (start < output.size()) {
93 | size_t end = output.find_first_of("\r\n", start);
94 | if (end == string::npos)
95 | end = output.size();
96 | string line = output.substr(start, end - start);
97 |
98 | string include = FilterShowIncludes(line, deps_prefix);
99 | if (!include.empty()) {
100 | seen_show_includes = true;
101 | string normalized;
102 | #ifdef _WIN32
103 | if (!normalizer.Normalize(include, &normalized, err))
104 | return false;
105 | #else
106 | // TODO: should this make the path relative to cwd?
107 | normalized = include;
108 | uint64_t slash_bits;
109 | CanonicalizePath(&normalized, &slash_bits);
110 | #endif
111 | if (!IsSystemInclude(normalized))
112 | includes_.insert(normalized);
113 | } else if (!seen_show_includes && FilterInputFilename(line)) {
114 | // Drop it.
115 | // TODO: if we support compiling multiple output files in a single
116 | // cl.exe invocation, we should stash the filename.
117 | } else {
118 | filtered_output->append(line);
119 | filtered_output->append("\n");
120 | }
121 |
122 | if (end < output.size() && output[end] == '\r')
123 | ++end;
124 | if (end < output.size() && output[end] == '\n')
125 | ++end;
126 | start = end;
127 | }
128 |
129 | return true;
130 | }
131 |
--------------------------------------------------------------------------------
/src/clparser.h:
--------------------------------------------------------------------------------
1 | // Copyright 2015 Google Inc. All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef NINJA_CLPARSER_H_
16 | #define NINJA_CLPARSER_H_
17 |
18 | #include
19 | #include
20 |
21 | /// Visual Studio's cl.exe requires some massaging to work with Ninja;
22 | /// for example, it emits include information on stderr in a funny
23 | /// format when building with /showIncludes. This class parses this
24 | /// output.
25 | struct CLParser {
26 | /// Parse a line of cl.exe output and extract /showIncludes info.
27 | /// If a dependency is extracted, returns a nonempty string.
28 | /// Exposed for testing.
29 | static std::string FilterShowIncludes(const std::string& line,
30 | const std::string& deps_prefix);
31 |
32 | /// Return true if a mentioned include file is a system path.
33 | /// Filtering these out reduces dependency information considerably.
34 | static bool IsSystemInclude(std::string path);
35 |
36 | /// Parse a line of cl.exe output and return true if it looks like
37 | /// it's printing an input filename. This is a heuristic but it appears
38 | /// to be the best we can do.
39 | /// Exposed for testing.
40 | static bool FilterInputFilename(std::string line);
41 |
42 | /// Parse the full output of cl, filling filtered_output with the text that
43 | /// should be printed (if any). Returns true on success, or false with err
44 | /// filled. output must not be the same object as filtered_object.
45 | bool Parse(const std::string& output, const std::string& deps_prefix,
46 | std::string* filtered_output, std::string* err);
47 |
48 | std::set includes_;
49 | };
50 |
51 | #endif // NINJA_CLPARSER_H_
52 |
--------------------------------------------------------------------------------
/src/command_collector.h:
--------------------------------------------------------------------------------
1 | // Copyright 2024 Google Inc. All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef NINJA_COMMAND_COLLECTOR_H_
16 | #define NINJA_COMMAND_COLLECTOR_H_
17 |
18 | #include
19 | #include
20 | #include
21 |
22 | #include "graph.h"
23 |
24 | /// Collects the transitive set of edges that lead into a given set
25 | /// of starting nodes. Used to implement the `compdb-targets` tool.
26 | ///
27 | /// When collecting inputs, the outputs of phony edges are always ignored
28 | /// from the result, but are followed by the dependency walk.
29 | ///
30 | /// Usage is:
31 | /// - Create instance.
32 | /// - Call CollectFrom() for each root node to collect edges from.
33 | /// - Call TakeResult() to retrieve the list of edges.
34 | ///
35 | struct CommandCollector {
36 | void CollectFrom(const Node* node) {
37 | assert(node);
38 |
39 | if (!visited_nodes_.insert(node).second)
40 | return;
41 |
42 | Edge* edge = node->in_edge();
43 | if (!edge || !visited_edges_.insert(edge).second)
44 | return;
45 |
46 | for (Node* input_node : edge->inputs_)
47 | CollectFrom(input_node);
48 |
49 | if (!edge->is_phony())
50 | in_edges.push_back(edge);
51 | }
52 |
53 | private:
54 | std::unordered_set visited_nodes_;
55 | std::unordered_set visited_edges_;
56 |
57 | /// we use a vector to preserve order from requisites to their dependents.
58 | /// This may help LSP server performance in languages that support modules,
59 | /// but it also ensures that the output of `-t compdb-targets foo` is
60 | /// consistent, which is useful in regression tests.
61 | public:
62 | std::vector in_edges;
63 | };
64 |
65 | #endif // NINJA_COMMAND_COLLECTOR_H_
66 |
--------------------------------------------------------------------------------
/src/debug_flags.cc:
--------------------------------------------------------------------------------
1 | // Copyright 2012 Google Inc. All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include
16 | #include