1*9e94795aSAndroid Build Coastguard Worker# Ninja File Canonicalizer 2*9e94795aSAndroid Build Coastguard Worker 3*9e94795aSAndroid Build Coastguard WorkerSuppose we have a tool that generates a Ninja file from some other description (think Kati and makefiles), and during 4*9e94795aSAndroid Build Coastguard Workerthe testing we discovered a regression. Furthermore, suppose that the generated Ninja file is large (think millions of 5*9e94795aSAndroid Build Coastguard Workerlines). And, the new Ninja file has build statements and rules in a slightly different order. As the tool generates the 6*9e94795aSAndroid Build Coastguard Workerrule names, the real differences in the output of the `diff` command are drowned in noise. Enter Canoninja. 7*9e94795aSAndroid Build Coastguard Worker 8*9e94795aSAndroid Build Coastguard WorkerCanoninja renames each Ninja rule to the hash of its contents. After that, we can just sort the build statements, and a 9*9e94795aSAndroid Build Coastguard Workersimple `comm` command immediately reveal the essential difference between the files. 10*9e94795aSAndroid Build Coastguard Worker 11*9e94795aSAndroid Build Coastguard Worker## Example 12*9e94795aSAndroid Build Coastguard Worker 13*9e94795aSAndroid Build Coastguard WorkerConsider the following makefile 14*9e94795aSAndroid Build Coastguard Worker 15*9e94795aSAndroid Build Coastguard Worker```makefile 16*9e94795aSAndroid Build Coastguard Workersecond := 17*9e94795aSAndroid Build Coastguard Workerfirst: foo 18*9e94795aSAndroid Build Coastguard Workerfoo: 19*9e94795aSAndroid Build Coastguard Worker @echo foo 20*9e94795aSAndroid Build Coastguard Workersecond: bar 21*9e94795aSAndroid Build Coastguard Workerbar: 22*9e94795aSAndroid Build Coastguard Worker @echo bar 23*9e94795aSAndroid Build Coastguard Worker``` 24*9e94795aSAndroid Build Coastguard Worker 25*9e94795aSAndroid Build Coastguard WorkerDepending on Kati version converting it to Ninja file will yield either: 26*9e94795aSAndroid Build Coastguard Worker 27*9e94795aSAndroid Build Coastguard Worker``` 28*9e94795aSAndroid Build Coastguard Worker$ cat /tmp/1.ninja 29*9e94795aSAndroid Build Coastguard Worker# Generated by kati 06f2569b2d16628608c000a76e3d495a5a5528cb 30*9e94795aSAndroid Build Coastguard Worker 31*9e94795aSAndroid Build Coastguard Workerpool local_pool 32*9e94795aSAndroid Build Coastguard Worker depth = 72 33*9e94795aSAndroid Build Coastguard Worker 34*9e94795aSAndroid Build Coastguard Workerbuild _kati_always_build_: phony 35*9e94795aSAndroid Build Coastguard Worker 36*9e94795aSAndroid Build Coastguard Workerbuild first: phony foo 37*9e94795aSAndroid Build Coastguard Workerrule rule0 38*9e94795aSAndroid Build Coastguard Worker description = build $out 39*9e94795aSAndroid Build Coastguard Worker command = /bin/sh -c "echo foo" 40*9e94795aSAndroid Build Coastguard Workerbuild foo: rule0 41*9e94795aSAndroid Build Coastguard Workerbuild second: phony bar 42*9e94795aSAndroid Build Coastguard Workerrule rule1 43*9e94795aSAndroid Build Coastguard Worker description = build $out 44*9e94795aSAndroid Build Coastguard Worker command = /bin/sh -c "echo bar" 45*9e94795aSAndroid Build Coastguard Workerbuild bar: rule1 46*9e94795aSAndroid Build Coastguard Worker 47*9e94795aSAndroid Build Coastguard Workerdefault first 48*9e94795aSAndroid Build Coastguard Worker``` 49*9e94795aSAndroid Build Coastguard Worker 50*9e94795aSAndroid Build Coastguard Workeror 51*9e94795aSAndroid Build Coastguard Worker 52*9e94795aSAndroid Build Coastguard Worker``` 53*9e94795aSAndroid Build Coastguard Worker$ cat 2.ninja 54*9e94795aSAndroid Build Coastguard Worker# Generated by kati 371194da71b3e191fea6f2ccceb7b061bd0de310 55*9e94795aSAndroid Build Coastguard Worker 56*9e94795aSAndroid Build Coastguard Workerpool local_pool 57*9e94795aSAndroid Build Coastguard Worker depth = 72 58*9e94795aSAndroid Build Coastguard Worker 59*9e94795aSAndroid Build Coastguard Workerbuild _kati_always_build_: phony 60*9e94795aSAndroid Build Coastguard Worker 61*9e94795aSAndroid Build Coastguard Workerbuild second: phony bar 62*9e94795aSAndroid Build Coastguard Workerrule rule0 63*9e94795aSAndroid Build Coastguard Worker description = build $out 64*9e94795aSAndroid Build Coastguard Worker command = /bin/sh -c "echo bar" 65*9e94795aSAndroid Build Coastguard Workerbuild bar: rule0 66*9e94795aSAndroid Build Coastguard Workerbuild first: phony foo 67*9e94795aSAndroid Build Coastguard Workerrule rule1 68*9e94795aSAndroid Build Coastguard Worker description = build $out 69*9e94795aSAndroid Build Coastguard Worker command = /bin/sh -c "echo foo" 70*9e94795aSAndroid Build Coastguard Workerbuild foo: rule1 71*9e94795aSAndroid Build Coastguard Worker 72*9e94795aSAndroid Build Coastguard Workerdefault first 73*9e94795aSAndroid Build Coastguard Worker``` 74*9e94795aSAndroid Build Coastguard Worker 75*9e94795aSAndroid Build Coastguard WorkerThis is a quirk in Kati, see https://github.com/google/kati/issues/238 76*9e94795aSAndroid Build Coastguard Worker 77*9e94795aSAndroid Build Coastguard WorkerTrying to find out the difference between the targets even after sorting them isn't too helpful: 78*9e94795aSAndroid Build Coastguard Worker 79*9e94795aSAndroid Build Coastguard Worker``` 80*9e94795aSAndroid Build Coastguard Workerdiff <(grep '^build' /tmp/1.ninja|sort) <(grep '^build' /tmp/2.ninja | sort) 81*9e94795aSAndroid Build Coastguard Worker1c1 82*9e94795aSAndroid Build Coastguard Worker< build bar: rule1 83*9e94795aSAndroid Build Coastguard Worker--- 84*9e94795aSAndroid Build Coastguard Worker> build bar: rule0 85*9e94795aSAndroid Build Coastguard Worker3c3 86*9e94795aSAndroid Build Coastguard Worker< build foo: rule0 87*9e94795aSAndroid Build Coastguard Worker--- 88*9e94795aSAndroid Build Coastguard Worker> build foo: rule1 89*9e94795aSAndroid Build Coastguard Worker``` 90*9e94795aSAndroid Build Coastguard Worker 91*9e94795aSAndroid Build Coastguard WorkerHowever, running these files through `canoninja` yields 92*9e94795aSAndroid Build Coastguard Worker 93*9e94795aSAndroid Build Coastguard Worker``` 94*9e94795aSAndroid Build Coastguard Worker$ canoninja /tmp/1.ninja 95*9e94795aSAndroid Build Coastguard Worker# Generated by kati 06f2569b2d16628608c000a76e3d495a5a5528cb 96*9e94795aSAndroid Build Coastguard Worker 97*9e94795aSAndroid Build Coastguard Workerpool local_pool 98*9e94795aSAndroid Build Coastguard Worker depth = 72 99*9e94795aSAndroid Build Coastguard Worker 100*9e94795aSAndroid Build Coastguard Workerbuild _kati_always_build_: phony 101*9e94795aSAndroid Build Coastguard Worker 102*9e94795aSAndroid Build Coastguard Workerbuild first: phony foo 103*9e94795aSAndroid Build Coastguard Workerrule R2f9981d3c152fc255370dc67028244f7bed72a03 104*9e94795aSAndroid Build Coastguard Worker description = build $out 105*9e94795aSAndroid Build Coastguard Worker command = /bin/sh -c "echo foo" 106*9e94795aSAndroid Build Coastguard Workerbuild foo: R2f9981d3c152fc255370dc67028244f7bed72a03 107*9e94795aSAndroid Build Coastguard Workerbuild second: phony bar 108*9e94795aSAndroid Build Coastguard Workerrule R62640f3f9095cf2da5b9d9e2a82f746cc710c94c 109*9e94795aSAndroid Build Coastguard Worker description = build $out 110*9e94795aSAndroid Build Coastguard Worker command = /bin/sh -c "echo bar" 111*9e94795aSAndroid Build Coastguard Workerbuild bar: R62640f3f9095cf2da5b9d9e2a82f746cc710c94c 112*9e94795aSAndroid Build Coastguard Worker 113*9e94795aSAndroid Build Coastguard Workerdefault first 114*9e94795aSAndroid Build Coastguard Worker``` 115*9e94795aSAndroid Build Coastguard Worker 116*9e94795aSAndroid Build Coastguard Workerand 117*9e94795aSAndroid Build Coastguard Worker 118*9e94795aSAndroid Build Coastguard Worker``` 119*9e94795aSAndroid Build Coastguard Worker~/go/bin/canoninja /tmp/2.ninja 120*9e94795aSAndroid Build Coastguard Worker# Generated by kati 371194da71b3e191fea6f2ccceb7b061bd0de310 121*9e94795aSAndroid Build Coastguard Worker 122*9e94795aSAndroid Build Coastguard Workerpool local_pool 123*9e94795aSAndroid Build Coastguard Worker depth = 72 124*9e94795aSAndroid Build Coastguard Worker 125*9e94795aSAndroid Build Coastguard Workerbuild _kati_always_build_: phony 126*9e94795aSAndroid Build Coastguard Worker 127*9e94795aSAndroid Build Coastguard Workerbuild second: phony bar 128*9e94795aSAndroid Build Coastguard Workerrule R62640f3f9095cf2da5b9d9e2a82f746cc710c94c 129*9e94795aSAndroid Build Coastguard Worker description = build $out 130*9e94795aSAndroid Build Coastguard Worker command = /bin/sh -c "echo bar" 131*9e94795aSAndroid Build Coastguard Workerbuild bar: R62640f3f9095cf2da5b9d9e2a82f746cc710c94c 132*9e94795aSAndroid Build Coastguard Workerbuild first: phony foo 133*9e94795aSAndroid Build Coastguard Workerrule R2f9981d3c152fc255370dc67028244f7bed72a03 134*9e94795aSAndroid Build Coastguard Worker description = build $out 135*9e94795aSAndroid Build Coastguard Worker command = /bin/sh -c "echo foo" 136*9e94795aSAndroid Build Coastguard Workerbuild foo: R2f9981d3c152fc255370dc67028244f7bed72a03 137*9e94795aSAndroid Build Coastguard Worker 138*9e94795aSAndroid Build Coastguard Workerdefault first 139*9e94795aSAndroid Build Coastguard Worker``` 140*9e94795aSAndroid Build Coastguard Worker 141*9e94795aSAndroid Build Coastguard Workerand when we extract only build statements and sort them, we see that both Ninja files define the same graph: 142*9e94795aSAndroid Build Coastguard Worker 143*9e94795aSAndroid Build Coastguard Worker```shell 144*9e94795aSAndroid Build Coastguard Worker$ diff <(~/go/bin/canoninja /tmp/1.ninja | grep '^build' | sort) \ 145*9e94795aSAndroid Build Coastguard Worker <(~/go/bin/canoninja /tmp/2.ninja | grep '^build' | sort) 146*9e94795aSAndroid Build Coastguard Worker``` 147*9e94795aSAndroid Build Coastguard Worker 148*9e94795aSAndroid Build Coastguard Worker# Todo 149*9e94795aSAndroid Build Coastguard Worker 150*9e94795aSAndroid Build Coastguard Worker* Optionally output only the build statements, optionally sorted 151*9e94795aSAndroid Build Coastguard Worker* Handle continuation lines correctly 152