1 module tests.ninja; 2 3 import unit_threaded; 4 import reggae.backend.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 [ 142 NinjaEntry("rule _ccompile", 143 ["command = gcc $flags $includes -MMD -MT $out -MF $DEPFILE -o $out -c $in", 144 "deps = gcc", 145 "depfile = $DEPFILE"]), 146 NinjaEntry("rule _cppcompile", 147 ["command = g++ $flags $includes -MMD -MT $out -MF $DEPFILE -o $out -c $in", 148 "deps = gcc", 149 "depfile = $DEPFILE"]), 150 NinjaEntry("rule _dcompile", 151 ["command = .reggae/dcompile --objFile=$out --depFile=$DEPFILE dmd $flags $includes $stringImports $in", 152 "deps = gcc", 153 "depfile = $DEPFILE"]), 154 NinjaEntry("rule _link", 155 ["command = dmd -of$out $flags $in"]), 156 ]); 157 } 158 159 160 void testImplicitOutput() { 161 const foo = Target(["foo.h", "foo.c"], "protocomp $in", [Target("foo.proto")]); 162 const bar = Target(["bar.h", "bar.c"], "protocomp $in", [Target("bar.proto")]); 163 const ninja = Ninja(Build(foo, bar)); 164 165 ninja.buildEntries.shouldEqual( 166 [NinjaEntry("build foo.h foo.c: protocomp foo.proto"), 167 NinjaEntry("build bar.h bar.c: protocomp bar.proto")]); 168 169 ninja.ruleEntries.shouldEqual( 170 [NinjaEntry("rule protocomp", 171 ["command = protocomp $in "])]); 172 } 173 174 175 void testImplicitInput() { 176 const protoSrcs = Target([`$builddir/gen/protocol.c`, `$builddir/gen/protocol.h`], 177 `./compiler $in`, 178 [Target(`protocol.proto`)]); 179 const protoObj = Target(`$builddir/bin/protocol.o`, 180 `gcc -o $out -c $builddir/gen/protocol.c`, 181 [], [protoSrcs]); 182 const protoD = Target(`$builddir/gen/protocol.d`, 183 `./translator $builddir/gen/protocol.h $out`, 184 [], [protoSrcs]); 185 const app = Target(`app`, `dmd -of$out $in`, 186 [Target("src/main.d"), protoObj, protoD]); 187 188 const ninja = Ninja(Build(app)); 189 190 ninja.buildEntries.shouldEqual( 191 [NinjaEntry("build gen/protocol.c gen/protocol.h: compiler protocol.proto"), 192 NinjaEntry("build bin/protocol.o: gcc gen/protocol.c | gen/protocol.c gen/protocol.h", 193 ["before = -o", 194 "between = -c"]), 195 NinjaEntry("build gen/protocol.c gen/protocol.h: compiler protocol.proto"), 196 NinjaEntry("build gen/protocol.d: translator gen/protocol.h | gen/protocol.c gen/protocol.h"), 197 NinjaEntry("build app: dmd src/main.d bin/protocol.o gen/protocol.d", 198 ["before = -of"]) 199 ]); 200 201 ninja.ruleEntries.shouldEqual( 202 [NinjaEntry("rule compiler", 203 ["command = ./compiler $in "]), 204 NinjaEntry("rule gcc", 205 ["command = gcc $before $out $between $in"]), 206 NinjaEntry("rule translator", 207 ["command = ./translator $in $out"]), 208 NinjaEntry("rule dmd", 209 ["command = dmd $before$out $in"]) 210 ]); 211 }