1 module tests.ninja; 2 3 import unit_threaded; 4 import reggae.ninja; 5 import reggae.build; 6 7 8 void testEmpty() { 9 const ninja = Ninja(); 10 ninja.buildEntries.shouldEqual([]); 11 ninja.ruleEntries.shouldEqual([]); 12 } 13 14 void testCppLinker() { 15 const ninja = Ninja(Build(Target("mybin", 16 "/usr/bin/c++ $in -o $out", 17 [Target("foo.o"), Target("bar.o")], 18 ))); 19 ninja.buildEntries.shouldEqual([NinjaEntry("build mybin: cpp foo.o bar.o", 20 ["between = -o"]) 21 ]); 22 ninja.ruleEntries.shouldEqual([NinjaEntry("rule cpp", 23 ["command = /usr/bin/c++ $in $between $out"]) 24 ]); 25 } 26 27 void testCppLinkerProjectPath() { 28 const ninja = Ninja(Build(Target("mybin", 29 "/usr/bin/c++ $in -o $out", 30 [Target("foo.o"), Target("bar.o")], 31 )), 32 "/home/user/myproject"); 33 ninja.buildEntries.shouldEqual([NinjaEntry("build mybin: cpp /home/user/myproject/foo.o /home/user/myproject/bar.o", 34 ["between = -o"]) 35 ]); 36 ninja.ruleEntries.shouldEqual([NinjaEntry("rule cpp", 37 ["command = /usr/bin/c++ $in $between $out"]) 38 ]); 39 } 40 41 42 void testCppLinkerProjectPathAndBuild() { 43 const ninja = Ninja(Build(Target("mybin", 44 "/usr/bin/c++ $in -o $out", 45 [Target("foo.o"), Target("bar.o")], 46 )), 47 "/home/user/myproject"); 48 ninja.buildEntries.shouldEqual([NinjaEntry("build mybin: cpp /home/user/myproject/foo.o /home/user/myproject/bar.o", 49 ["between = -o"]) 50 ]); 51 ninja.ruleEntries.shouldEqual([NinjaEntry("rule cpp", 52 ["command = /usr/bin/c++ $in $between $out"]) 53 ]); 54 } 55 56 57 void testIccBuild() { 58 const ninja = Ninja(Build(Target("/path/to/foo.o", 59 "icc.12.0.022b.i686-linux -pe-file-prefix=/usr/intel/12.0.022b/cc/12.0.022b/include/ @/usr/lib/icc-cc.cfg -I/path/to/headers -gcc-version=345 -fno-strict-aliasing -nostdinc -include /path/to/myheader.h -DTOOL_CHAIN_GCC=gcc-user -D__STUFF__ -imacros /path/to/preinclude_macros.h -I/path/to -Wall -c -MD -MF /path/to/foo.d -o $out $in", 60 [Target("/path/to/foo.c")]))); 61 ninja.buildEntries.shouldEqual([NinjaEntry("build /path/to/foo.o: icc.12.0.022b.i686-linux /path/to/foo.c", 62 ["before = -pe-file-prefix=/usr/intel/12.0.022b/cc/12.0.022b/include/ @/usr/lib/icc-cc.cfg -I/path/to/headers -gcc-version=345 -fno-strict-aliasing -nostdinc -include /path/to/myheader.h -DTOOL_CHAIN_GCC=gcc-user -D__STUFF__ -imacros /path/to/preinclude_macros.h -I/path/to -Wall -c -MD -MF /path/to/foo.d -o"])]); 63 ninja.ruleEntries.shouldEqual([NinjaEntry("rule icc.12.0.022b.i686-linux", 64 ["command = icc.12.0.022b.i686-linux $before $out $in"])]); 65 } 66 67 68 void testBeforeAndAfter() { 69 const ninja = Ninja(Build(Target("foo.temp", 70 "icc @/path/to/icc-ld.cfg -o $out $in -Wl,-rpath-link -Wl,/usr/lib", 71 [Target("main.o"), Target("extra.o"), Target("sub_foo.o"), Target("sub_bar.o"), 72 Target("sub_baz.a")]))); 73 ninja.buildEntries.shouldEqual([NinjaEntry("build foo.temp: icc main.o extra.o sub_foo.o sub_bar.o sub_baz.a", 74 ["before = @/path/to/icc-ld.cfg -o", 75 "after = -Wl,-rpath-link -Wl,/usr/lib"])]); 76 ninja.ruleEntries.shouldEqual([NinjaEntry("rule icc", 77 ["command = icc $before $out $in $after"])]); 78 } 79 80 void testSimpleDBuild() { 81 const mainObj = Target(`main.o`, `dmd -I$project/src -c $in -of$out`, Target(`src/main.d`)); 82 const mathsObj = Target(`maths.o`, `dmd -c $in -of$out`, Target(`src/maths.d`)); 83 const app = Target(`myapp`, 84 `dmd -of$out $in`, 85 [mainObj, mathsObj] 86 ); 87 const build = Build(app); 88 const ninja = Ninja(build, "/path/to/project"); 89 90 ninja.buildEntries.shouldEqual( 91 [NinjaEntry("build objs/myapp.objs/main.o: dmd /path/to/project/src/main.d", 92 ["before = -I/path/to/project/src -c", 93 "between = -of"]), 94 NinjaEntry("build objs/myapp.objs/maths.o: dmd /path/to/project/src/maths.d", 95 ["before = -c", 96 "between = -of"]), 97 NinjaEntry("build myapp: dmd_2 objs/myapp.objs/main.o objs/myapp.objs/maths.o", 98 ["before = -of"]) 99 ]); 100 101 ninja.ruleEntries.shouldEqual( 102 [NinjaEntry("rule dmd", 103 ["command = dmd $before $in $between$out"]), 104 NinjaEntry("rule dmd_2", 105 ["command = dmd $before$out $in"]) 106 ]); 107 } 108 109 110 void testImplicitDependencies() { 111 const target = Target("foo.o", "gcc -o $out -c $in", [Target("foo.c")], [Target("foo.h")]); 112 const ninja = Ninja(Build(target)); 113 ninja.buildEntries.shouldEqual( 114 [NinjaEntry("build foo.o: gcc foo.c | foo.h", 115 ["before = -o", 116 "between = -c"]) 117 ]); 118 119 ninja.ruleEntries.shouldEqual( 120 [NinjaEntry("rule gcc", 121 ["command = gcc $before $out $between $in"])]); 122 } 123 124 void testImplicitDependenciesMoreThanOne() { 125 const target = Target("foo.o", "gcc -o $out -c $in", [Target("foo.c")], [Target("foo.h"), Target("foo.idl")]); 126 const ninja = Ninja(Build(target)); 127 ninja.buildEntries.shouldEqual( 128 [NinjaEntry("build foo.o: gcc foo.c | foo.h foo.idl", 129 ["before = -o", 130 "between = -c"]) 131 ]); 132 133 ninja.ruleEntries.shouldEqual( 134 [NinjaEntry("rule gcc", 135 ["command = gcc $before $out $between $in"])]); 136 } 137 138 139 void testDefaultRules() { 140 defaultRules().shouldEqual( 141 [NinjaEntry("rule _dcompile", 142 ["command = .reggae/dcompile --objFile=$out --depFile=$DEPFILE dmd $flags $includes $stringImports $in", 143 "deps = gcc", 144 "depfile = $DEPFILE"]), 145 NinjaEntry("rule _dlink", 146 ["command = dmd $flags -of$out $in"]), 147 NinjaEntry("rule _cppcompile", 148 ["command = g++ $flags $includes -MMD -MT $out -MF $DEPFILE -o $out -c $in", 149 "deps = gcc", 150 "depfile = $DEPFILE"]), 151 NinjaEntry("rule _ccompile", 152 ["command = gcc $flags $includes -MMD -MT $out -MF $DEPFILE -o $out -c $in", 153 "deps = gcc", 154 "depfile = $DEPFILE"]), 155 ]); 156 } 157 158 159 void testImplicitOutput() { 160 const foo = Target(["foo.h", "foo.c"], "protocomp $in", [Target("foo.proto")]); 161 const bar = Target(["bar.h", "bar.c"], "protocomp $in", [Target("bar.proto")]); 162 const ninja = Ninja(Build(foo, bar)); 163 164 ninja.buildEntries.shouldEqual( 165 [NinjaEntry("build foo.h foo.c: protocomp foo.proto"), 166 NinjaEntry("build bar.h bar.c: protocomp bar.proto")]); 167 168 ninja.ruleEntries.shouldEqual( 169 [NinjaEntry("rule protocomp", 170 ["command = protocomp $in "])]); 171 } 172 173 174 void testImplicitInput() { 175 const protoSrcs = Target([`$builddir/gen/protocol.c`, `$builddir/gen/protocol.h`], 176 `./compiler $in`, 177 [Target(`protocol.proto`)]); 178 const protoObj = Target(`$builddir/bin/protocol.o`, 179 `gcc -o $out -c $builddir/gen/protocol.c`, 180 [], [protoSrcs]); 181 const protoD = Target(`$builddir/gen/protocol.d`, 182 `./translator $builddir/gen/protocol.h $out`, 183 [], [protoSrcs]); 184 const app = Target(`app`, `dmd -of$out $in`, 185 [Target("src/main.d"), protoObj, protoD]); 186 187 const ninja = Ninja(Build(app)); 188 189 ninja.buildEntries.shouldEqual( 190 [NinjaEntry("build gen/protocol.c gen/protocol.h: compiler protocol.proto"), 191 NinjaEntry("build bin/protocol.o: gcc gen/protocol.c | gen/protocol.c gen/protocol.h", 192 ["before = -o", 193 "between = -c"]), 194 NinjaEntry("build gen/protocol.c gen/protocol.h: compiler protocol.proto"), 195 NinjaEntry("build gen/protocol.d: translator gen/protocol.h | gen/protocol.c gen/protocol.h"), 196 NinjaEntry("build app: dmd src/main.d bin/protocol.o gen/protocol.d", 197 ["before = -of"]) 198 ]); 199 200 ninja.ruleEntries.shouldEqual( 201 [NinjaEntry("rule compiler", 202 ["command = ./compiler $in "]), 203 NinjaEntry("rule gcc", 204 ["command = gcc $before $out $between $in"]), 205 NinjaEntry("rule translator", 206 ["command = ./translator $in $out"]), 207 NinjaEntry("rule dmd", 208 ["command = dmd $before$out $in"]) 209 ]); 210 }