1 module tests.build; 2 3 import unit_threaded; 4 import reggae; 5 6 7 void testIsLeaf() { 8 Target("tgt").isLeaf.shouldBeTrue; 9 Target("other", "", [Target("foo"), Target("bar")]).isLeaf.shouldBeFalse; 10 Target("implicits", "", [], [Target("foo")]).isLeaf.shouldBeFalse; 11 } 12 13 14 void testInOut() { 15 //Tests that specifying $in and $out in the command string gets substituted correctly 16 { 17 const target = Target("foo", 18 "createfoo -o $out $in", 19 [Target("bar.txt"), Target("baz.txt")]); 20 target.expandCommand.shouldEqual("createfoo -o foo bar.txt baz.txt"); 21 } 22 { 23 const target = Target("tgt", 24 "gcc -o $out $in", 25 [ 26 Target("src1.o", "gcc -c -o $out $in", [Target("src1.c")]), 27 Target("src2.o", "gcc -c -o $out $in", [Target("src2.c")]) 28 ], 29 ); 30 target.expandCommand.shouldEqual("gcc -o tgt src1.o src2.o"); 31 } 32 33 { 34 const target = Target(["proto.h", "proto.c"], 35 "protocompile $out -i $in", 36 [Target("proto.idl")]); 37 target.expandCommand.shouldEqual("protocompile proto.h proto.c -i proto.idl"); 38 } 39 40 { 41 const target = Target("lib1.a", 42 "ar -o$out $in", 43 [Target(["foo1.o", "foo2.o"], "cmd", [Target("tmp")]), 44 Target("bar.o"), 45 Target("baz.o")]); 46 target.expandCommand.shouldEqual("ar -olib1.a foo1.o foo2.o bar.o baz.o"); 47 } 48 } 49 50 51 void testProject() { 52 const target = Target("foo", 53 "makefoo -i $in -o $out -p $project", 54 [Target("bar"), Target("baz")]); 55 target.expandCommand("/tmp").shouldEqual("makefoo -i /tmp/bar /tmp/baz -o foo -p /tmp"); 56 } 57 58 59 void testMultipleOutputs() { 60 const target = Target(["foo.hpp", "foo.cpp"], "protocomp $in", [Target("foo.proto")]); 61 target.outputs.shouldEqual(["foo.hpp", "foo.cpp"]); 62 target.expandCommand("myproj").shouldEqual("protocomp myproj/foo.proto"); 63 64 const bld = Build(target); 65 bld.targets.array[0].outputs.shouldEqual(["foo.hpp", "foo.cpp"]); 66 } 67 68 69 void testInTopLevelObjDir() { 70 71 const theApp = Target("theapp"); 72 const dirName = topLevelDirName(theApp); 73 const fooObj = Target("foo.o", "", [Target("foo.c")]); 74 fooObj.inTopLevelObjDirOf(dirName).shouldEqual( 75 Target("objs/theapp.objs/foo.o", "", [Target("foo.c")])); 76 77 const barObjInBuildDir = Target("$builddir/bar.o", "", [Target("bar.c")]); 78 barObjInBuildDir.inTopLevelObjDirOf(dirName).shouldEqual( 79 Target("bar.o", "", [Target("bar.c")])); 80 81 const leafTarget = Target("foo.c"); 82 leafTarget.inTopLevelObjDirOf(dirName).shouldEqual(leafTarget); 83 } 84 85 86 void testMultipleOutputsImplicits() { 87 const protoSrcs = Target([`$builddir/gen/protocol.c`, `$builddir/gen/protocol.h`], 88 `./compiler $in`, 89 [Target(`protocol.proto`)]); 90 const protoObj = Target(`$builddir/bin/protocol.o`, 91 `gcc -o $out -c $builddir/gen/protocol.c`, 92 [], [protoSrcs]); 93 const protoD = Target(`$builddir/gen/protocol.d`, 94 `echo "extern(C) " > $out; cat $builddir/gen/protocol.h >> $out`, 95 [], [protoSrcs]); 96 const app = Target(`app`, 97 `dmd -of$out $in`, 98 [Target(`src/main.d`), protoObj, protoD]); 99 const build = Build(app); 100 101 const newProtoSrcs = Target([`gen/protocol.c`, `gen/protocol.h`], 102 `./compiler $in`, 103 [Target(`protocol.proto`)]); 104 const newProtoD = Target(`gen/protocol.d`, 105 `echo "extern(C) " > $out; cat gen/protocol.h >> $out`, 106 [], [newProtoSrcs]); 107 108 build.targets.array.shouldEqual( 109 [Target("app", "dmd -of$out $in", 110 [Target("src/main.d"), 111 Target("bin/protocol.o", "gcc -o $out -c gen/protocol.c", 112 [], [newProtoSrcs]), 113 newProtoD])] 114 ); 115 } 116 117 118 void testRealTargetPath() { 119 const fooLib = Target("$project/foo.so", "dmd -of$out $in", [Target("src1.d"), Target("src2.d")]); 120 const barLib = Target("$builddir/bar.so", "dmd -of$out $in", [Target("src1.d"), Target("src2.d")]); 121 const symlink1 = Target("$project/weird/path/thingie1", "ln -sf $in $out", fooLib); 122 const symlink2 = Target("$project/weird/path/thingie2", "ln -sf $in $out", fooLib); 123 const symlinkBar = Target("$builddir/weird/path/thingie2", "ln -sf $in $out", fooLib); 124 125 immutable dirName = "/made/up/dir"; 126 127 realTargetPath(dirName, symlink1.outputs[0]).shouldEqual("$project/weird/path/thingie1"); 128 realTargetPath(dirName, symlink2.outputs[0]).shouldEqual("$project/weird/path/thingie2"); 129 realTargetPath(dirName, fooLib.outputs[0]).shouldEqual("$project/foo.so"); 130 131 132 realTargetPath(dirName, symlinkBar.outputs[0]).shouldEqual("weird/path/thingie2"); 133 realTargetPath(dirName, barLib.outputs[0]).shouldEqual("bar.so"); 134 135 } 136 137 138 void testOptional() { 139 enum foo = Target("foo", "dmd -of$out $in", Target("foo.d")); 140 enum bar = Target("bar", "dmd -of$out $in", Target("bar.d")); 141 142 optional(bar).target.shouldEqual(bar); 143 mixin build!(foo, optional(bar)); 144 auto build = buildFunc(); 145 build.targets.array[1].shouldEqual(bar); 146 } 147 148 149 void testDiamondDeps() { 150 const src1 = Target("src1.d"); 151 const src2 = Target("src2.d"); 152 const obj1 = Target("obj1.o", "dmd -of$out -c $in", src1); 153 const obj2 = Target("obj2.o", "dmd -of$out -c $in", src2); 154 const fooLib = Target("$project/foo.so", "dmd -of$out $in", [obj1, obj2]); 155 const symlink1 = Target("$project/weird/path/thingie1", "ln -sf $in $out", fooLib); 156 const symlink2 = Target("$project/weird/path/thingie2", "ln -sf $in $out", fooLib); 157 const build = Build(symlink1, symlink2); 158 159 const newObj1 = Target("objs/$project/foo.so.objs/obj1.o", "dmd -of$out -c $in", src1); 160 const newObj2 = Target("objs/$project/foo.so.objs/obj2.o", "dmd -of$out -c $in", src2); 161 const newFooLib = Target("$project/foo.so", "dmd -of$out $in", [newObj1, newObj2]); 162 const newSymlink1 = Target("$project/weird/path/thingie1", "ln -sf $in $out", newFooLib); 163 const newSymlink2 = Target("$project/weird/path/thingie2", "ln -sf $in $out", newFooLib); 164 165 build.range.array.shouldEqual([newObj1, newObj2, newFooLib, newSymlink1, newSymlink2]); 166 } 167 168 void testPhobosOptionalBug() { 169 enum obj1 = Target("obj1.o", "dmd -of$out -c $in", Target("src1.d")); 170 enum obj2 = Target("obj2.o", "dmd -of$out -c $in", Target("src2.d")); 171 enum foo = Target("foo", "dmd -of$out $in", [obj1, obj2]); 172 Target bar() { 173 return Target("bar", "dmd -of$out $in", [obj1, obj2]); 174 } 175 mixin build!(foo, optional!(bar)); 176 const build = buildFunc(); 177 178 const fooObj1 = Target("objs/foo.objs/obj1.o", "dmd -of$out -c $in", Target("src1.d")); 179 const fooObj2 = Target("objs/foo.objs/obj2.o", "dmd -of$out -c $in", Target("src2.d")); 180 const newFoo = Target("foo", "dmd -of$out $in", [fooObj1, fooObj2]); 181 182 const barObj1 = Target("objs/bar.objs/obj1.o", "dmd -of$out -c $in", Target("src1.d")); 183 const barObj2 = Target("objs/bar.objs/obj2.o", "dmd -of$out -c $in", Target("src2.d")); 184 const newBar = Target("bar", "dmd -of$out $in", [barObj1, barObj2]); 185 186 build.range.array.shouldEqual([fooObj1, fooObj2, newFoo, barObj1, barObj2, newBar]); 187 } 188 189 190 void testOutputsInProjectPath() { 191 const mkDir = Target("$project/foodir", "mkdir -p $out", [], []); 192 mkDir.outputsInProjectPath("/path/to/proj").shouldEqual(["/path/to/proj/foodir"]); 193 } 194 195 196 void testExpandOutputs() { 197 const foo = Target("$project/foodir", "mkdir -p $out", [], []); 198 foo.expandOutputs("/path/to/proj").array.shouldEqual(["/path/to/proj/foodir"]); 199 200 const bar = Target("$builddir/foodir", "mkdir -p $out", [], []); 201 bar.expandOutputs("/path/to/proj").array.shouldEqual(["foodir"]); 202 } 203 204 205 void testCommandBuilddir() { 206 const cmd = Command("dmd -of$builddir/ut_debug $in"); 207 cmd.shellCommand("/path/to/proj", Language.unknown, ["$builddir/ut_debug"], ["foo.d"]). 208 shouldEqual("dmd -ofut_debug foo.d"); 209 } 210 211 212 void testBuilddirInTopLevelTarget() { 213 const ao = objectFile(SourceFile("a.c")); 214 const liba = Target("$builddir/liba.a", "ar rcs liba.a a.o", [ao]); 215 mixin build!(liba); 216 const build = buildFunc(); 217 build.targets[0].outputs.shouldEqual(["liba.a"]); 218 }