platform_build/tools/canoninja/README.md

152 lines
3.5 KiB
Markdown
Raw Normal View History

# Ninja File Canonicalizer
Suppose we have a tool that generates a Ninja file from some other description (think Kati and makefiles), and during
the testing we discovered a regression. Furthermore, suppose that the generated Ninja file is large (think millions of
lines). And, the new Ninja file has build statements and rules in a slightly different order. As the tool generates the
rule names, the real differences in the output of the `diff` command are drowned in noise. Enter Canoninja.
Canoninja renames each Ninja rule to the hash of its contents. After that, we can just sort the build statements, and a
simple `comm` command immediately reveal the essential difference between the files.
## Example
Consider the following makefile
```makefile
second :=
first: foo
foo:
@echo foo
second: bar
bar:
@echo bar
```
Depending on Kati version converting it to Ninja file will yield either:
```
$ cat /tmp/1.ninja
# Generated by kati 06f2569b2d16628608c000a76e3d495a5a5528cb
pool local_pool
depth = 72
build _kati_always_build_: phony
build first: phony foo
rule rule0
description = build $out
command = /bin/sh -c "echo foo"
build foo: rule0
build second: phony bar
rule rule1
description = build $out
command = /bin/sh -c "echo bar"
build bar: rule1
default first
```
or
```
$ cat 2.ninja
# Generated by kati 371194da71b3e191fea6f2ccceb7b061bd0de310
pool local_pool
depth = 72
build _kati_always_build_: phony
build second: phony bar
rule rule0
description = build $out
command = /bin/sh -c "echo bar"
build bar: rule0
build first: phony foo
rule rule1
description = build $out
command = /bin/sh -c "echo foo"
build foo: rule1
default first
```
This is a quirk in Kati, see https://github.com/google/kati/issues/238
Trying to find out the difference between the targets even after sorting them isn't too helpful:
```
diff <(grep '^build' /tmp/1.ninja|sort) <(grep '^build' /tmp/2.ninja | sort)
1c1
< build bar: rule1
---
> build bar: rule0
3c3
< build foo: rule0
---
> build foo: rule1
```
However, running these files through `canoninja` yields
```
$ canoninja /tmp/1.ninja
# Generated by kati 06f2569b2d16628608c000a76e3d495a5a5528cb
pool local_pool
depth = 72
build _kati_always_build_: phony
build first: phony foo
rule R2f9981d3c152fc255370dc67028244f7bed72a03
description = build $out
command = /bin/sh -c "echo foo"
build foo: R2f9981d3c152fc255370dc67028244f7bed72a03
build second: phony bar
rule R62640f3f9095cf2da5b9d9e2a82f746cc710c94c
description = build $out
command = /bin/sh -c "echo bar"
build bar: R62640f3f9095cf2da5b9d9e2a82f746cc710c94c
default first
```
and
```
~/go/bin/canoninja /tmp/2.ninja
# Generated by kati 371194da71b3e191fea6f2ccceb7b061bd0de310
pool local_pool
depth = 72
build _kati_always_build_: phony
build second: phony bar
rule R62640f3f9095cf2da5b9d9e2a82f746cc710c94c
description = build $out
command = /bin/sh -c "echo bar"
build bar: R62640f3f9095cf2da5b9d9e2a82f746cc710c94c
build first: phony foo
rule R2f9981d3c152fc255370dc67028244f7bed72a03
description = build $out
command = /bin/sh -c "echo foo"
build foo: R2f9981d3c152fc255370dc67028244f7bed72a03
default first
```
and when we extract only build statements and sort them, we see that both Ninja files define the same graph:
```shell
$ diff <(~/go/bin/canoninja /tmp/1.ninja | grep '^build' | sort) \
<(~/go/bin/canoninja /tmp/2.ninja | grep '^build' | sort)
```
# Todo
* Optionally output only the build statements, optionally sorted
* Handle continuation lines correctly