Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
f220dc5
Merge pull request #2479 from mcprat/workflow-ctest-verbose
jhasse Aug 28, 2024
7d671d2
status_printer.h: Add 'override' statements to avoid warnings.
digit-google Aug 28, 2024
77d979b
explanations.h: Remove Explanations:enabled_ field.
digit-google Aug 28, 2024
0f05540
metrics.cc: Remove unused GetFrequency() function.
digit-google Aug 28, 2024
50ae55a
build.cc: Add 'override' directives to virtual method overrides.
digit-google Aug 28, 2024
4b7d399
Merge pull request #2486 from digit-google/remove-warnings
jhasse Aug 30, 2024
7e03348
Add InputsCollector class.
digit-google Aug 29, 2024
5b94d34
Fix `inputs` tool implementation.
digit-google Aug 29, 2024
2843493
Add new options to `inputs` tool.
digit-google Aug 29, 2024
60f901e
Rewrite ElideMiddle.ElideAnsiEscapeCodes test.
digit-google Sep 2, 2024
2d7ee52
Move ElideMiddle() to its own source file.
digit-google May 17, 2024
ee9a296
Faster and more correct ElideMiddle with ANSI sequences
digit-google May 16, 2024
5dd9b78
ElideMiddle: Get rid of std::regex usage and heap allocations.
digit-google May 16, 2024
1ba5570
StatusPrinter: only strip ANSI sequences when needed.
digit-google May 19, 2024
b2ae865
Merge pull request #2487 from digit-google/faster-elide-middle
jhasse Sep 2, 2024
2c13023
Ensure depfile's parent directory is created before running an action.
digit-google Sep 4, 2024
60838c1
typos
spaette Sep 9, 2024
fe83433
Merge pull request #2492 from digit-google/create-depfile-directory
nico Sep 10, 2024
41ecb09
Merge pull request #2485 from digit-google/fix-inputs-tool
jhasse Sep 19, 2024
6a31acc
Merge pull request #2494 from vaerksted/master
jhasse Sep 19, 2024
0e28864
Add CircleCI integration
mayank-ramnani Sep 21, 2024
5896632
Add manifest and test files for converter
mayank-ramnani Oct 13, 2024
4f11aab
Make testing build.ninja and build.ninja.cc consistent
mayank-ramnani Oct 13, 2024
ada7e84
Start implementing converter in Python
mayank-ramnani Oct 13, 2024
2a5272f
Move Python converter to archive - will use cpp to do the conversion …
mayank-ramnani Oct 16, 2024
931ce8e
Start changing ninja code itself to behave as a converter instead of …
mayank-ramnani Oct 17, 2024
221597e
Add converter usage instructions in readme
mayank-ramnani Oct 31, 2024
5511dee
Handle rules for converter
mayank-ramnani Oct 22, 2024
fcfb875
Handle let statements for converter
mayank-ramnani Oct 24, 2024
e2d8a25
Handle edges (build statements) for converter
mayank-ramnani Oct 30, 2024
fadd24c
Handle default statements for converter
mayank-ramnani Oct 30, 2024
7df7ece
Fix bug with converting let statements (to prevent extra statements f…
mayank-ramnani Oct 31, 2024
90d7bc0
Formatting improvements for output file - tab characters
mayank-ramnani Nov 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Use the latest 2.1 version of CircleCI pipeline process engine.
# See: https://circleci.com/docs/configuration-reference
version: 2.1

# Define a job to be invoked later in a workflow.
# See: https://circleci.com/docs/jobs-steps/#jobs-overview & https://circleci.com/docs/configuration-reference/#jobs
jobs:
ninja:
docker:
- image: cimg/base:current
steps:
- checkout
- run:
name: Install ctest, clang-tidy and compiler
command: |
sudo apt-get update
sudo apt-get install -y cmake g++ clang-tidy
- run:
name: Copy clang-tidy config
command: |
cp .clang-tidy /tmp/.clang-tidy
- run:
name: Run clang-tidy, build ninja and run ctest
command: |
mkdir build
cd build
cmake ..
cmake --build .
make
ctest


# Orchestrate jobs using workflows
# See: https://circleci.com/docs/workflows/ & https://circleci.com/docs/configuration-reference/#workflows
workflows:
build-and-test: # This is the name of the workflow, feel free to change it to better match your workflow.
# Inside the workflow, you define the jobs you want to run.
jobs:
- ninja
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ set(NINJA_PYTHON "python" CACHE STRING "Python interpreter to use for the browse

check_platform_supports_browse_mode(platform_supports_ninja_browse)

# run clang-tidy before source code is built
set(CMAKE_CXX_CLANG_TIDY "clang-tidy;--config-file=/tmp/.clang-tidy")

# Core source files all build into ninja library.
add_library(libninja OBJECT
src/build_log.cc
Expand All @@ -135,6 +138,7 @@ add_library(libninja OBJECT
src/deps_log.cc
src/disk_interface.cc
src/edit_distance.cc
src/elide_middle.cc
src/eval_env.cc
src/graph.cc
src/graphviz.cc
Expand Down Expand Up @@ -265,6 +269,7 @@ if(BUILD_TESTING)
src/disk_interface_test.cc
src/dyndep_parser_test.cc
src/edit_distance_test.cc
src/elide_middle_test.cc
src/explanations_test.cc
src/graph_test.cc
src/json_test.cc
Expand Down Expand Up @@ -295,6 +300,7 @@ if(BUILD_TESTING)
canon_perftest
clparser_perftest
depfile_parser_perftest
elide_middle_perftest
hash_collision_bench
manifest_parser_perftest
)
Expand Down
109 changes: 14 additions & 95 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,100 +1,19 @@
# Ninja

Ninja is a small build system with a focus on speed.
https://ninja-build.org/

See [the manual](https://ninja-build.org/manual.html) or
`doc/manual.asciidoc` included in the distribution for background
and more details.

Binaries for Linux, Mac and Windows are available on
[GitHub](https://github.com/ninja-build/ninja/releases).
Run `./ninja -h` for Ninja help.

Installation is not necessary because the only required file is the
resulting ninja binary. However, to enable features like Bash
completion and Emacs and Vim editing modes, some files in misc/ must be
copied to appropriate locations.

If you're interested in making changes to Ninja, read
[CONTRIBUTING.md](CONTRIBUTING.md) first.

## Building Ninja itself

You can either build Ninja via the custom generator script written in Python or
via CMake. For more details see
[the wiki](https://github.com/ninja-build/ninja/wiki).

### Python

```
./configure.py --bootstrap
# Shadowdash Converter
## Build
```sh
./build.sh
```
This will create the converter in the `debug-build` directory with debug symbols.

This will generate the `ninja` binary and a `build.ninja` file you can now use
to build Ninja with itself.

If you have a GoogleTest source directory, you can build the tests
by passing its path with `--gtest-source-dir=PATH` option, or the
`GTEST_SOURCE_DIR` environment variable, e.g.:

```
./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.
```

Use the CMake build below if you want to use a preinstalled binary
version of the library.

### CMake

```
cmake -Bbuild-cmake
cmake --build build-cmake
## Run
```sh
./debug-build/ninja
```
Run the above in a directory where a `build.ninja` file is present

The `ninja` binary will now be inside the `build-cmake` directory (you can
choose any other name you like).

To run the unit tests:

## Testing
```sh
cd converter/testing/
../../debug-build/ninja
```
./build-cmake/ninja_test
```

## Generating documentation

### Ninja Manual

You must have `asciidoc` and `xsltproc` in your PATH, then do:

```
./configure.py
ninja manual doc/manual.pdf
```

Which will generate `doc/manual.html`.

To generate the PDF version of the manual, you must have `dblatext` in your PATH then do:

```
./configure.py # only if you didn't do it previously.
ninja doc/manual.pdf
```

Which will generate `doc/manual.pdf`.

### Doxygen documentation

If you have `doxygen` installed, you can build documentation extracted from C++
declarations and comments to help you navigate the code. Note that Ninja is a standalone
executable, not a library, so there is no public API, all details exposed here are
internal.

```
./configure.py # if needed
ninja doxygen
```

Then open `doc/doxygen/html/index.html` in a browser to look at it.
This will run the converter on the hello world example `build.ninja` file and produce `output.cc` as a result.
2 changes: 2 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cmake -DCMAKE_BUILD_TYPE=Debug -B debug-build
cmake --build debug-build --parallel --config Debug --target ninja
3 changes: 3 additions & 0 deletions configure.py
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,7 @@ def has_re2c() -> bool:
'dyndep',
'dyndep_parser',
'edit_distance',
'elide_middle',
'eval_env',
'graph',
'graphviz',
Expand Down Expand Up @@ -638,6 +639,7 @@ def has_re2c() -> bool:
'disk_interface_test',
'dyndep_parser_test',
'edit_distance_test',
'elide_middle_test',
'explanations_test',
'graph_test',
'json_test',
Expand Down Expand Up @@ -683,6 +685,7 @@ def has_re2c() -> bool:

for name in ['build_log_perftest',
'canon_perftest',
'elide_middle_perftest',
'depfile_parser_perftest',
'hash_collision_bench',
'manifest_parser_perftest',
Expand Down
98 changes: 98 additions & 0 deletions converter/archive/convert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import argparse

def parse_ninja_file(ninja_file_content):
rules = {}
builds = []
current_rule = None
default_target = None

lines = ninja_file_content.splitlines()

for line in lines:
line = line.strip()
if line.startswith("rule"):
current_rule = line.split()[1]
rules[current_rule] = {"command": None, "flags": "-O3"}
elif line.startswith("command ="):
if current_rule:
rules[current_rule]["command"] = line.split("=", 1)[1].strip()
elif line.startswith("flags ="):
if current_rule:
rules[current_rule]["flags"] = line.split("=", 1)[1].strip()
elif line.startswith("build"):
parts = line.split()
output, rule, inputs = parts[1], parts[2], parts[3:]
builds.append((output, rule, inputs))
elif line.startswith("default"):
default_target = line.split()[1]

return rules, builds, default_target

def generate_manifest_cc(rules, builds, default_target):
cc_code = '#include "../manifest.h"\n\nusing namespace shadowdash;\n\nvoid manifest() {\n'
cc_code += f' let(flags, "{rules["compile"]["flags"]}");\n\n'

for rule, details in rules.items():
cc_code += f' auto {rule} = rule{{ {{\n'
command = details["command"].replace("$flags", '"flags"_v').replace("$in", "in").replace("$out", "out")
cc_code += f' bind(command, {command}), //\n'
cc_code += f' }} }};\n\n'

for build in builds:
output, rule, inputs = build
inputs_str = ", ".join([f'str{{ "{inp}" }}' for inp in inputs])
if rule == "compile" and "flags" in rules["compile"] and rules["compile"]["flags"] != "-O3":
cc_code += f' build(list{{ str{{ "{output}" }} }}, //\n'
cc_code += f' {{}}, //\n'
cc_code += f' {rule}, //\n'
cc_code += f' list{{ {inputs_str} }}, //\n'
cc_code += f' {{}}, //\n'
cc_code += f' {{}}, //\n'
cc_code += f' {{ bind(flags, "{rules["compile"]["flags"]}") }} //\n'
cc_code += f' );\n\n'
else:
cc_code += f' build(list{{ str{{ "{output}" }} }}, //\n'
cc_code += f' {{}}, //\n'
cc_code += f' {rule}, //\n'
cc_code += f' list{{ {inputs_str} }}, //\n'
cc_code += f' {{}}, //\n'
cc_code += f' {{}}, //\n'
cc_code += f' {{}} //\n'
cc_code += f' );\n\n'

cc_code += f' build(list{{ str{{ "{default_target}" }} }}, //\n'
cc_code += f' {{}}, //\n'
cc_code += f' link, //\n'
cc_code += f' list{{ str{{ "{default_target}.o" }} }}, //\n'
cc_code += f' {{}}, //\n'
cc_code += f' {{}}, //\n'
cc_code += f' {{}} //\n'
cc_code += f' );\n'

cc_code += '}\n'
return cc_code

def main():
# argument parser for input and output file names
parser = argparse.ArgumentParser(description="Convert a build.ninja file to a build.ninja.cc file.")
parser.add_argument('input_file', help="Path to the input build.ninja file")
parser.add_argument('output_file', help="Path to the output build.ninja.cc file")

args = parser.parse_args()

# read input file
with open(args.input_file, 'r') as f:
ninja_file_content = f.read()

# parse the ninja file
rules, builds, default_target = parse_ninja_file(ninja_file_content)

# generate the manifest.cc content
manifest_cc_content = generate_manifest_cc(rules, builds, default_target)

# write the output to the file
with open(args.output_file, 'w') as f:
f.write(manifest_cc_content)

if __name__ == "__main__":
main()
21 changes: 21 additions & 0 deletions converter/src/hooks.cpp
Comment thread
mayank-ramnani marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

void HandleRule(Rule* rule)
{
// output string
std::string output = "auto " + rule.name_ + " = rule{{bind(command, \"g++\", \"flags\"_v, \"-c\", ";

// Iterate over the parsed_ vector in the "command" binding
for (const auto& entry : rule.bindings_["command"].parsed_) {
if (entry.second == RAW) {
output += "\"" + entry.first + "\", "; // Add quotes for raw strings
} else if (entry.second == SPECIAL) {
output += entry.first + ", "; // No quotes for special variables
}
}

// Finish the string
output += ")}};";

// Print the result
std::cout << output << std::endl;
}
55 changes: 55 additions & 0 deletions converter/src/main.cpp
Comment thread
mayank-ramnani marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include <iostream>
#include <string>
#include <map>
#include <vector>

// Assuming you have these constants
enum EvalStringType { RAW, SPECIAL };

// Example structures based on your description
struct EvalString {
std::string first;
EvalStringType second;
};

struct Binding {
std::vector<EvalString> parsed_;
};

struct Rule {
std::string name_;
std::map<std::string, Binding> bindings_;
};

int main() {
// Simulate your object
Rule rule;
rule.name_ = "compile";
rule.bindings_["command"].parsed_ = {
{"g++ -c ", RAW},
{"in", SPECIAL},
{" -o ", RAW},
{"out", SPECIAL},
{" ", RAW}
};

// Begin the output string
std::string output = "auto " + rule.name_ + " = rule{{bind(command, \"g++\", \"flags\"_v, \"-c\", ";

// Iterate over the parsed_ vector in the "command" binding
for (const auto& entry : rule.bindings_["command"].parsed_) {
if (entry.second == RAW) {
output += "\"" + entry.first + "\", "; // Add quotes for raw strings
} else if (entry.second == SPECIAL) {
output += entry.first + ", "; // No quotes for special variables
}
}

// Finish the string
output += ")}};";

// Print the result
std::cout << output << std::endl;

return 0;
}
Loading