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 }