173 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			173 lines
		
	
	
	
		
			6 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# ngen
 | 
						|
Build file generator (engine) for the [Ninja build
 | 
						|
system](https://ninja-build.org/).
 | 
						|
 | 
						|
Licensed under the GPLv3.
 | 
						|
 | 
						|
## Methodology and Overview
 | 
						|
 | 
						|
The problem with existing meta build systems---or makefile generators---like
 | 
						|
[Meson](https://mesonbuild.com/) and [CMake](https://cmake.org/) is that they
 | 
						|
are needlessly complex for small-to-medium-sized C/C++ projects. These projects
 | 
						|
are just large enough that hand-writing a makefile would be painful, but trying
 | 
						|
to configure a large meta build system would be just as painful. It is
 | 
						|
unacceptable that building a simple project with 10 .c files and a library
 | 
						|
requires knowledge of a unique, obscure configuration language which is
 | 
						|
constantly changing.
 | 
						|
 | 
						|
*ngen* aims to make generating build files for these small C/C++ projects as
 | 
						|
simple as possible by using a basic key-value configuration file using patterns
 | 
						|
that any experienced programmer should be familiar with. In doing so, ngen fills
 | 
						|
the gap between writing your own makefile and wrangling with CMakeLists.txt. 
 | 
						|
 | 
						|
ngen generates files for the small and modern [Ninja](https://ninja-build.org/)
 | 
						|
build system. "Where other build systems are high-level languages Ninja aims to
 | 
						|
be an assembler," according to Ninja's website. It can be thought of as a
 | 
						|
simpler, faster replacement for the classic `make`. It is used by default by
 | 
						|
Meson; CMake can also be configured to use ninja as a backend. Ninja is used by
 | 
						|
used by Google to build Chromium, v8, etc., and it is also used to build LLVM.
 | 
						|
(All this to say, Ninja is commonly used and it is likely installed on your
 | 
						|
system already.)
 | 
						|
 | 
						|
## Building
 | 
						|
 | 
						|
Build: `cargo build --release`
 | 
						|
 | 
						|
Install: `sudo sh install.sh`
 | 
						|
 | 
						|
Uninstall: `sudo sh uninstall.sh`
 | 
						|
 | 
						|
## Usage
 | 
						|
What follows is a tutorial of how to set up ngen for an existing executable
 | 
						|
project. If you are looking for a reference, look <SOMEWHERE>.
 | 
						|
 | 
						|
The first thing you will need is an `ngen.toml` file. This is what will specify
 | 
						|
all of the build parameters, such as compilation flags, source files to track,
 | 
						|
etc. Start by creating this file and opening it in your editor.
 | 
						|
 | 
						|
The simplest valid `ngen.toml` just lists the source files you want to track.
 | 
						|
Lets say you have a executable project that looks like this:
 | 
						|
 | 
						|
```txt
 | 
						|
example
 | 
						|
├── ngen.toml
 | 
						|
└── src
 | 
						|
    ├── foobar.c
 | 
						|
    ├── functions.c
 | 
						|
    ├── include
 | 
						|
    │   ├── foobar.h
 | 
						|
    │   ├── functions.h
 | 
						|
    │   ├── main.h
 | 
						|
    │   └── util.h
 | 
						|
    ├── main.c
 | 
						|
    └── util.c
 | 
						|
```
 | 
						|
 | 
						|
In your `ngen.toml`, write the following:
 | 
						|
 | 
						|
```toml
 | 
						|
sources = [
 | 
						|
  "src/main.c",
 | 
						|
  "src/util.c",
 | 
						|
  "src/functions.c",
 | 
						|
  "src/foobar.c",
 | 
						|
]
 | 
						|
```
 | 
						|
 | 
						|
**The `sources` key is a *list* of *strings*, each specifying a single source
 | 
						|
file name.**
 | 
						|
 | 
						|
Now run `ngen`. This will generate a `build.ninja` file in the current working
 | 
						|
directory. You won't ever have to touch this file; that's what ngen is for. You
 | 
						|
also won't ever have to run `ngen` yourself again (unless your `build.ninja`
 | 
						|
gets deleted); Ninja will take care of regenerating the build file if
 | 
						|
`ngen.toml` changes.
 | 
						|
 | 
						|
With your `build.ninja` generated, run `ninja` on the command line. That's it!
 | 
						|
Your project is now built, you will find the executable at `build/main/a.out`.
 | 
						|
Remember, you can also freely add and remove files from the above list without
 | 
						|
running `ngen` again: Ninja will regenerate the `build.ninja` for you.
 | 
						|
 | 
						|
Now, while this is functional, it isn't very useful. It is very likely that you
 | 
						|
will want to specify a compiler (gcc/clang), pass some flags, link some
 | 
						|
libraries into your final executable, and definitely name your program something
 | 
						|
other than "a.out." ngen makes these things dead simple, too.
 | 
						|
 | 
						|
**The `outfile` key is a *string* that specifies the name of the file produced
 | 
						|
by the `linker` (see below).**
 | 
						|
 | 
						|
Lets set this to "example."
 | 
						|
 | 
						|
```toml
 | 
						|
outfile = "example"
 | 
						|
```
 | 
						|
 | 
						|
**The `compiler` key is a *string* that specifies the program that will be used
 | 
						|
to turn .c files into .o files.**
 | 
						|
 | 
						|
By default, if not specified, `compiler` is set to "cc," which on Linux systems
 | 
						|
should be a C compiler. It should be noted that the compiler you choose must
 | 
						|
support the `-MD` and `-MF` flags to generate dependency files (both gcc and
 | 
						|
clang support this). Lets say we want to use "gcc." Add the following line to
 | 
						|
your `ngen.toml`:
 | 
						|
 | 
						|
```toml
 | 
						|
compiler = "gcc"
 | 
						|
```
 | 
						|
 | 
						|
**The `compiler_flags` key is a *list* of *strings* that contains the arguments
 | 
						|
to be passed to the `compiler` during the compilation of each `source` file.**
 | 
						|
 | 
						|
It is not necessary to add the `-c` or `-o outfile` flags, ngen will take care
 | 
						|
of this for you. For example, add the following to your `ngen.toml`:
 | 
						|
 | 
						|
```toml
 | 
						|
compiler_flags = ["-Wall", "-Wextra -O2"]
 | 
						|
```
 | 
						|
 | 
						|
**The `linker` key is a *string* that specifies the program that will be used to
 | 
						|
combine the .o files into the final `outfile`.**
 | 
						|
 | 
						|
If the `linker` key is not found, it will be set to the value of `compiler`. For
 | 
						|
this example, we don't have to change anything here.
 | 
						|
 | 
						|
**The `linker_flags` key is a *list* of *strings* that contains the arguments to
 | 
						|
be passed to the `linker` during the linking of the `outfile`.**
 | 
						|
 | 
						|
Library flags (`-lm`, `-lyourlib`) should NOT be included here. This is for
 | 
						|
linker options, not libraries. The syntax is the same as `compiler_flags`. There
 | 
						|
is nothing we have to set here.
 | 
						|
 | 
						|
**The `linker_libs` key is a *list* of *strings* that contains the link library
 | 
						|
arguments to be linked to the `outfile`.**
 | 
						|
 | 
						|
THIS is where library flags (`-lm`, `-lyourlib`) go. Lets say our example
 | 
						|
project needs the math library:
 | 
						|
 | 
						|
```toml
 | 
						|
linker_libs = ["-lm"]
 | 
						|
```
 | 
						|
 | 
						|
Now, our `ngen.toml` looks like this:
 | 
						|
 | 
						|
```toml
 | 
						|
outfile = "example"
 | 
						|
compiler = "gcc"
 | 
						|
compiler_flags = ["-Wall", "-Wextra -O2"]
 | 
						|
linker_libs = ["-lm"]
 | 
						|
sources = [
 | 
						|
  "src/main.c",
 | 
						|
  "src/util.c",
 | 
						|
  "src/functions.c",
 | 
						|
  "src/foobar.c",
 | 
						|
]
 | 
						|
```
 | 
						|
 | 
						|
This is a much more realistic looking project. Once again, any changes to any of
 | 
						|
these values will be automatically picked up by Ninja and accounted for in the
 | 
						|
build. Running `ninja -v` immediately after saving `ngen.toml` should show that
 | 
						|
the options you set were recognized, and your files were rebuilt accordingly.
 | 
						|
 | 
						|
TODO: explain
 | 
						|
- seperate targets
 | 
						|
- config table
 |