Expand description
§ninja-writer
Library for writing ninja build files with a focus on ergonomics and simplicity.
Since Rust requires a trait to be in scope to use,
it is recommended to import *
from the crate, so that all the traits
are in scope.
use ninja_writer::*;
§Why another?
I found existing libraries poorly documented, and I want to explore and learn the syntax for ninja myself.
§Example
The Ninja
struct is the main entry point for writing a ninja file.
It is used to make top-level declarations, such as variables and rules.
It implements Display
so that it can be converted to a string, written to a file, etc.
Here’s a complete example of writing a ninja file that builds a simple C program.
See Ninja
for all the methods available.
use ninja_writer::*;
// Create writer
let ninja = Ninja::new();
// Create a variable
ninja.variable("cflags", "-Wall -Wextra -Werror");
// Create the cc rule
let cc = ninja.rule("cc", "gcc -MD -MF $depfile $cflags -c $in -o $out")
.description("Compiling $out")
.depfile("$out.d")
.deps_gcc();
// Create the ld rule
let ld = ninja.rule("ld", "gcc -o $out $in")
.description("Linking $out");
// Create build edges using the rules
cc.build(["foo.o"]).with(["foo.c"]);
cc.build(["bar.o"]).with(["bar.c"])
.variable("cflags", "-Wall -DDEBUG");
ld.build(["app"]).with(["foo.o", "bar.o"]);
ninja.defaults(["app"]);
let ninja_file: String = ninja.to_string();
assert_eq!(ninja_file, r###"
cflags = -Wall -Wextra -Werror
rule cc
command = gcc -MD -MF $depfile $cflags -c $in -o $out
description = Compiling $out
depfile = $out.d
deps = gcc
rule ld
command = gcc -o $out $in
description = Linking $out
build foo.o: cc foo.c
build bar.o: cc bar.c
cflags = -Wall -DDEBUG
build app: ld foo.o bar.o
default app
"###);
§Encoding
Because .to_string()
is used to get the output, All inputs/outputs are expected to be UTF-8
encoded. Utilities like ToArg
will panic for std
types if the input is not valid UTF-8.
§Args and lists
All functions take implementation of ToArg
as parameters.
This trait is implemented for common Rust types like Path
and
String
.
For functions that take a list of arguments (such as build
),
the types of the elements in the slice must be the same due to Rust’s type system restrictions.
// This won't compile
let args = [1, "bar"];
The args
macro is provided to workaround this limitation.
§std
feature
You can disable the std
feature to make the library no_std
compatible. I don’t know why you
want to do that, but it’s here just in case.
§Thread safety
By default, the API is not thread-safe. However, you can enable the thread-safe
feature,
which uses Arc
and RwLock
to ensure thread safety.
Here’s an example of using 2 threads to configure 200 rules.
(It’s highly theoretical. Rule
has a more realistic example
where multiple threads configure build edges on the same rule)
use ninja_writer::*;
use std::sync::Arc;
let ninja = Arc::new(Ninja::new());
let ninja1 = Arc::clone(&ninja);
let ninja2 = Arc::clone(&ninja);
let t1 = std::thread::spawn(move || {
for i in 0..100 {
ninja1.rule("example", "...");
}
});
let t2 = std::thread::spawn(move || {
for i in 0..100 {
ninja2.rule("example", "...");
}
});
t1.join().unwrap();
t2.join().unwrap();
assert_eq!(ninja.stmts.inner().len(), 200);
The example won’t compile unless you enable the thread-safe
feature.
§Escaping
There is an escape
function that can be used to escape strings
according to the behavior of ninja.
use ninja_writer::escape;
assert_eq!(escape("foo"), "foo");
assert_eq!(escape("$foo"), "$$foo");
assert_eq!(escape("foo bar"), "foo bar");
assert_eq!(escape("foo: bar"), "foo: bar");
Since it’s only necessary to escape spaces in list of paths, you can use escape_path
to do that:
use ninja_writer::escape_path;
assert_eq!(escape_path("foo bar"), "foo$ bar");
Similarly, escape_build
can be used to escape both spaces and :
s, for
specifying outputs.
use ninja_writer::escape_build;
assert_eq!(escape_build("foo: bar"), "foo$:$ bar");
§Duplicated variables
Duplicates are not checked, since ninja allows it.
use ninja_writer::Ninja;
let mut ninja = Ninja::new();
ninja.variable("foo", "bar");
ninja.variable("foo", "bar again");
assert_eq!(ninja.to_string(), r###"
foo = bar
foo = bar again
"###);
§Order of statements
The order of statements is preserved. Ninja’s variables are expanded immediately except for in rules, so the order of statements does matter.
Macros§
- Convert a mixed list of arguments types to a list of strings
Structs§
- A build edge, as defined by the
build
keyword - Reference to a build statement
- The main entry point for writing a ninja file.
- A pool, as defined by the
pool
keyword - Reference to a pool statement
- A rule, as defined by the
rule
keyword - Reference to a rule statement that can be used to create build edges using this rule
- A variable declaration (
name = value
)
Traits§
- Trait for implementing build-specific variables
- Trait for implementing variables for
rule
andbuild
- Convert something to an argument
- Convienience trait to implement types that supports variables
Functions§
- Escape a string for ninja, without escaping spaces or colons
- Escape a string for ninja. Spaces and colons are escaped as well
- Escape a string for ninja, including spaces in the string, but not colons