Experiments with gn (generate ninja)
Some of this contact is directly lifted from original sources, but ideally its a rewrite of notes. See the following URLS
- mailing list
- git
- consolidated help
- above link assumes you have git cloned gn in this repo
gn will generate the initial ninja files.
Assuming the current directory has the following files:
- .gn
- BUILD.gn
This command sequence:
$ gn gen -C out
Will make an out dir. In this dir will be the following files:
- args.gn
- build.ninja
- build.ninja.d
- build.ninja.stamp
- toolchain.ninja
- obj/ dir
For example three (mine3) obj/ dir will contain the following files:
- main.ninja
- the exe
- mymath.ninja
- the static library (*.a)
- mystring.ninja
- the dynamic/shared libray (*.so)
Once you have run the gn gen
command you do not need
to rerun gn
explicitly even if you have modified the BUILD.gn
file.
The ninja files generated by ninja will automatically rerun ninja. Here is an example:
Generate the ninja files.
$ gn gen -C out
Done. Made 3 targets from 4 files in 7ms
Build the code using ninja
$ ninja -v -C out
ninja: Entering directory `out'
[1/6] g++ -MMD -MF obj/src/main.main.o.d -c ../src/main.cc -o obj/src/main.main.o
[2/6] g++ -MMD -MF obj/src/libmymath.MyMath.o.d -c ../src/MyMath.cc -o obj/src/libmymath.MyMath.o
[3/6] g++ -MMD -MF obj/src/libmystring.MyString.o.d -DMYSTRING_IMPLEMENTATION -c ../src/MyString.cc -o obj/src/libmystring.MyString.o
[4/6] ar rcs obj/libmymath.a obj/src/libmymath.MyMath.o
[5/6] g++ -shared -o ./libmystring.so -install_name @executable_path/./libmystring.so @libmystring.so.rsp
[6/6] g++ -o main @main.rsp
Touch the original BUILD.gn
file, rerun ninja
and see how it reruns gn.
$ touch BUILD.gn
$ ninja -v -C out
ninja: Entering directory `out'
[0/1] ../../../gn/out/gn --root=./.. -q --C --regeneration gen .
ninja: no work to do.
$
# usage: build
$ gn gen -C out $ ninja -v -C out $ ./out/main
# usage: clean
Clean build from ninja.
$ ninja -v -C out -t clean
Clean ninja files generated by gn.
$ gn clean out
### Important Files
* .gn
```
# The location of the build configuration file.
buildconfig = "//build/BUILDCONFIG.gn"
```
- This file identifies the top level of the gn/ninja build system. You can override with `--root-/somedir` command line argument.
- The contents of this file specifies the `build` dir containing the configs file.
- Once `gn gen` is run:
- build/BUILD.gn
- contains configs used by build/toolchain/BUILD.gn
- build/BUILDCONFIG.gn
- Variables in this file are global to all build files.
- Variables for default toolchain
- Variables for compiler flags and settings
- build/toolchain/BUILD.gn
- contains tool definitions
- cc, cxx, alink, solink, etc.
-
- see `gn help dotfile`
* BUILD.gn
- Contains the list of target directives.
- executable
- shared_library
- static_library
- source_set
- etc.
- Also contains the list of config directives
- Sets up global variables and default settings
- Location defined by `.gn` file
#### `.gn` content
This file contains a list of variables. See `gn help dotfile` for a complete list. Here is a subset of variables:
* `buildconfig`
- required variable.
- Contains path to a file containing the default `args.gn` content. This content is visible when you run:
```
$ cd mine3
$ gn args -C out
# or
# gn args out
```
It will open the `out/args.gn` file where you can edit the default args.
- Can also list the default args via:
```
$ gn args out --list --short
current_cpu = ""
current_os = ""
host_cpu = "arm64"
host_os = "mac"
target_cpu = ""
target_os = ""
```
- Note in this case, `out/args.gn` is empty and thus these args are via other files. Namely, `build/BUILDCONFIG.gn`
- see `gn help args`
* `root`
- optional variable
- Label of the root build target.
- `gn` will start by loading the build file containing this target name. Defaults to "//:" which causes gn to load `//BUILD.gn`.
- The command-line switch `--root-target` will override this target. See `gn help --root-target`.
### Important Commands
* `gn help`
- `gn help runtime_deps`
- `gn help deps`
- `gn help data`
* `gn clean out`
- This cleans out the results of the ninja build. ie. *.o, *.a, *.so, etc.
- It does not clean out/*.gn files.
* `gn ls <build_dir> <target_wildcard>`
- Lists all the targets
- `gn ls out/ "//*"`
* `//:main`
* `//:mymath`
* `//:mystring`
* `gn desc <build_dir> <target_name>`
- Describes target for example provides
* sources
* Type of target. eg. executable, shared library or static library.
* direct dependencies
- `gn desc out/ "//:main"`
- `gn desc out //:main runtime_deps`
- `gn desc out //:main deps`
- `gn desc out //:main deps --tree`
* `gn desc <build_dir> <target_name> deps --tree`
- `gn desc out //:main deps --tree`
- lists depends tree
- `gn desc out/ "//:main"` deps --tree
* `gn args out`
- opens an editor to override the default
* `gn args --list out`
- shows all the args, default values and their documentation
* `gn analyze <out_dir> <input_path> <output_path>`
- analyze which targets are affected by a list of files
- If the input/output paths are `-`, then it
uses stdin/stdout.
- While helpfull, this is a bit tricky to use.
- Here is a sample in.json
```
{
"files":[
"//src/xmain.cc",
"//src/xMyString.cc",
"//src/xMyMath.cc"
],
"test_targets":[
"//:mystring"
]
}
```
- In this case, I want to find if the specified files are required to build the `mystring` library. Since these are typos of the various
source files, the analyze will say there is no dependency.
```
$ gn analyze out in.json -
{"compile_targets":[],"status":"No dependency","test_targets":[]}
```
- If the sample json file is corrected to have
the proper filenames, then the output is:
```
$ gn analyze out in.json -
{"compile_targets":[],"status":"Found dependency","test_targets":["//:mystring"]}
```
* `gn outputs <out_dir> <list of target or file names>`
-
### Important Target Declarations
These are common target declarations used in `BUILD.gn`
NOTE: Targets chain dependecies on other targets using the `deps` directive.
* executable
- Declare an executable target
- Tools and commands used to create this target are determined by the source files in its sources.
- C/C++ are allowed, but C and Rust are not.
* shared_library
- Declare a shared library target
- makes a `.so` file.
- A shared library will be specified on the linker line for targets listing the shared library in it its "deps".
- On osx use "loadable_module" instead.
* static_library
- Declare a static library target
- makes a `.a` or a `.lib` file.
- If you want to skip the `.a`, but want intermediate results consider a `source set` instead.
* group
- Declare a named group of targets
- This target type creates meta-targets that just collect a set of dependencies into one named target.
- Groups can additionally specify configs that apply to their dependents.
- Example
```
group("all") {
deps = [
"//project:runner",
"//project:unit_tests",
]
}
```
* loadable_module
- Declare a loadable module target
- Creates an object file that is (and can only be) loaded and unloaded at runtime.
- If you don't want this (if you don't need to dynamically load the library at runtime), then you should use a "shared_library" target type instead. (What?)
- The style guide has more info on this relative to plaforms linux, windows and osx. See [here](https://gn.googlesource.com/gn/+/main/docs/style_guide.md#loadable-modules-versus-shared-libraries)
* target
- Declare a target with specified programmatic type
- The target() function is a way to invoke a built-in target or template with a type determined at runtime. This is useful for cases where the type of a target type might not be known statically.
- Only templates and built-in target functions are supported for the target type string parameter. Arbitrary functions, configs and toolchains are not supported.
- signature:
```
target(target_type string, target_name string) { ... }
```
- Equvalent Example
```
target("source_set", "doom_melon") {...}
```
=
```
source_set("doom_melon") {...}
```
### Important Target Variables
* compiler configuration settings
* include_dirs
- When a subdir contains a library which is specified as a dependency, the subdir does not appear to be included. In this case, specify this option to locate the headers. See example `mine4`.
```
include_dirs = [ "//src/mymath" ]
```
* cflags
- Flags for the compiler
```
cflags = [ "-Wall" ]
```
* defines
- Preprocessor defines to steer `#ifdef`s
```
defines = [ "FOO=BAR" ]
```
* config
- Can group all configs for reuse in multiple targets
```
config("myconfig") {
include_dirs = [ "//src/mymath" ]
cflags = [ "-Wall" ]
defines = [ "FOO=BAR" ]
}
```
### Important config directives
Used in the BUILD.gn files.
* example
config("myconfig") { include_dirs = [ "include/common" ] defines = [ "ENABLE_DOOM_MELON" ] }
executable("mything") { configs = [ ":myconfig" ] }
### gn clean and ninja clean
1. gn gen makes the build dir and the ninja build files.
2. then use ninja to build the projet
When you run `ninja -t clean`, it cleans the files that ninja knows about. When you run `gn clean` it deletes everything. Note, if you touch the gn config files, the ninja files generated by gn will auto-re-run gn to recreate the ninja files.
### Targets, Dependencies and Labels
Using the `src/mine3/BUILD.gn` file as an example, which is reproduced here for quick reference.
executable("main") { sources = [ "src/main.cc" ]
deps = [ ":mymath", # shorthand notation "//:mystring" # explicit long hand notation ] }
static_library("mymath") { sources = [ "src/MyMath.cc", "src/MyMath.h" ] }
shared_library("mystring") { sources = [ "src/MyString.cc", "src/MyString.h" ]
defines = [ "MYSTRING_IMPLEMENTATION"] }
The words, "main", "mymath", etc in the target directives are termed `labels`. The ":" is a shorthand method. The full name is specified using a `"\\"` syntax to signify the top level directory with interleaving `"\"` to denote sub-directories.
If the source was in a sub-directory then the "\" would comes into play.
Regarding dependencies. It appears that specifying a dependency on a target in
a subdir does not add that subdir to the list of includes. This is demonstrasted in
examples `mine4` and onward. Without the `include_dirs` directive, `gn gen` will work, but
the compile via `ninja -C out` will fail because it can not locate the header files.
#### From the Brett Wilson presentation
##### Full Label
//chrome/browser:version
Looks for "version" in `chrome/browser/BUILD.gn`
##### Implicit name
//base
Shorthand for `//base:base`
##### In Current file
:baz
Shorthand for `baz` in current file.
//:baz
Specifies a label (baz) in top level. Useful for a BUILD.gn in a subdir.
//foo:bar
Specifies a label (bar) in a subdir named foo.
Example src/mine7 demos usage of configs and labels.
#### Summary
* label is `directory:name` where directory is a source path containing a `build.gn` file with a label specified by name.
* shorthand `directory" will refer to a label name corresponding to the same name as the directory.
- `//foo/goo`
* Looks for label `goo` in directory/file `foo/goo/build.gn`
## apple clang
This code can be switched to use native clang or the gcc clang clone. Change the comment in `build/BUILDCONFIG.gn`.
* [apple clang ref manual](https://opensource.apple.com/source/clang/clang-23/clang/tools/clang/docs/UsersManual.html)
* [clang ref manual](https://clang.llvm.org/docs/UsersManual.html)
## GN Reference
$ vi ../../gn/docs/reference.md
## Idea for CSV code
Used practice of programming book as guide for the CSV code
* [book homepage](http://www.cs.princeton.edu/~bwk/tpop.webpage/)
* [code reference](https://www.cs.princeton.edu/~bwk/tpop.webpage/csvgetlinec++.c)