diff --git a/.circleci/config.yml b/.circleci/config.yml index 0b06da20a2..9eba1881b6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -36,6 +36,7 @@ jobs: command: | cd build-cmake ctest --output-junit results.xml --verbose -j4 + cd ../hello_world_graph && ././hello_world_graph_test.sh - store_test_results: path: build-cmake diff --git a/hello_world_graph/hello.cc b/hello_world_graph/hello.cc new file mode 100644 index 0000000000..a44fd6475d --- /dev/null +++ b/hello_world_graph/hello.cc @@ -0,0 +1,7 @@ +// a simple test program to print "Hello World" +#include + +int main() { + std::cout << "Hello, World!" << std::endl; + return 0; +} diff --git a/hello_world_graph/hello_world_graph_test.sh b/hello_world_graph/hello_world_graph_test.sh new file mode 100755 index 0000000000..e27940db2c --- /dev/null +++ b/hello_world_graph/hello_world_graph_test.sh @@ -0,0 +1 @@ +../build-cmake/ninja hello && test "$(./hello)" = "Hello, World!" \ No newline at end of file diff --git a/shadowdash_docs/hello_world_graph_docs.md b/shadowdash_docs/hello_world_graph_docs.md new file mode 100644 index 0000000000..47cdd918cc --- /dev/null +++ b/shadowdash_docs/hello_world_graph_docs.md @@ -0,0 +1,74 @@ +# Hello World Graph Documentation + +This document provides an overview of the updates to the **Hello World Graph** task in the Shadowdash project, including its structure, new content, and instructions on how to run it. + +--- + +## **Overview** + +The `Hello World Graph` demonstrates a basic usage of Ninja's build system by introducing a simple graph structure that compiles and links a "Hello, World!" program. The primary updates in this task include: + +1. **Build Graph Definition**: + - A minimal build graph is defined using two custom rules: `compile` and `link`. + - Each rule is implemented as part of the Ninja state with inputs and outputs linked together. + +2. **Rules and Edges**: + - **Compile Rule**: Uses `g++` to compile `hello.cc` into `hello.o`. + - **Link Rule**: Links `hello.o` to produce the executable `hello`. + +3. **Integration**: + - The graph integrates seamlessly into the Ninja-based build system, leveraging Ninja's structure and performance. + +--- + +## **Key Components** + +### 1. **Rules** + +- **Compile Rule**: Defines how the source file (`hello.cc`) is compiled: + ```plaintext + g++ -c hello.cc -o hello.o + +- **Link Rule**: Defines how the object file (hello.o) is linked to produce the executable: + ```plaintext + g++ hello.o -o hello + +### 2. **Edges** + +The edges connect the rules, defining the dependencies: +- `hello.cc` → [Compile Rule] → `hello.o` +- `hello.o` → [Link Rule] → `hello` + +--- + +## **How to Run** + +1. **Prerequisites**: + - Ensure you have `g++` installed on your system. + - Ninja is required to run the build graph. + +2. **Steps to Build and Run**: + - Navigate to the project root directory: + ```bash + cd shadowdash + ``` + - Run the `hello` target using the Ninja build system: + ```bash + ./build-cmake/ninja hello + ``` + - Upon successful execution, you will see the compiled `hello` executable. Run it to verify the output: + ```bash + ./hello + ``` + - Expected Output: + ```plaintext + Hello, World! + ``` + +--- + +## **File Structure** + +- `hello_world_graph/hello.cc`: The "Hello, World!" source file. +- `build-cmake/ninja`: The Ninja executable for building the project. +- Custom rules and graph logic are embedded in the build system to demonstrate the flow. diff --git a/src/ninja.cc b/src/ninja.cc index 2902359f15..eb517878bc 100644 --- a/src/ninja.cc +++ b/src/ninja.cc @@ -1616,9 +1616,75 @@ NORETURN void real_main(int argc, char** argv) { exit(1); } +// routine to compile the example hello.cc by manually +// constructing the graph +void compile_hello(int argc, char** argv) { + // ninja initialization + const char* ninja_command = argv[0]; + BuildConfig config; + Options options = {}; + + int exit_code = ReadFlags(&argc, &argv, &options, &config); + if (exit_code >= 0) + exit(exit_code); + + Status* status = Status::factory(config); + + NinjaMain ninja(ninja_command, config); + + string* err; + + // start building hello world graph + + // create a compile rule + Rule* rule_compile = new Rule("compile"); + EvalString value1; + value1.AddText("g++ -c "); + value1.AddSpecial("in"); + value1.AddText(" -o "); + value1.AddSpecial("out"); + rule_compile->AddBinding("command", value1); + + // create a link rule + Rule* rule_link = new Rule("link"); + EvalString value2; + value2.AddText("g++ "); + value2.AddSpecial("in"); + value2.AddText(" -o "); + value2.AddSpecial("out"); + rule_link->AddBinding("command", value2); + + // add build from hello.cc to hello.o + Edge* edge_compile = ninja.state_.AddEdge(rule_compile); + + ninja.state_.AddOut(edge_compile, "hello.o", 0, err); + ninja.state_.AddIn(edge_compile, "hello.cc", 0); + + // add build from hello.o to hello + Edge* edge_link = ninja.state_.AddEdge(rule_link); + + ninja.state_.AddOut(edge_link, "hello", 0, err); + ninja.state_.AddIn(edge_link, "hello.o", 0); + + // feed to ninja and run the build + int result = ninja.RunBuild(argc, argv, status); + exit(result); +} + } // anonymous namespace int main(int argc, char** argv) { + // add a branch to run our hello world program + // compilation routine. We can cleanly seperate + // this in another file and generate a dedicated + // executable to compile hello.cc, but we believe + // this does not worth the effort since this task + // is more like an experiment + if(argc == 2 && !strcmp(argv[1], "hello")) + { + compile_hello(argc, argv); + return 0; + } #if defined(_MSC_VER) // Set a handler to catch crashes not caught by the __try..__except // block (e.g. an exception in a stack-unwind-block).