1 |
/* |
2 |
* csant.c - Build tool for C# program compilation. |
3 |
* |
4 |
* Copyright (C) 2001, 2002, 2003 Southern Storm Software, Pty Ltd. |
5 |
* |
6 |
* This program is free software; you can redistribute it and/or modify |
7 |
* it under the terms of the GNU General Public License as published by |
8 |
* the Free Software Foundation; either version 2 of the License, or |
9 |
* (at your option) any later version. |
10 |
* |
11 |
* This program is distributed in the hope that it will be useful, |
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
* GNU General Public License for more details. |
15 |
* |
16 |
* You should have received a copy of the GNU General Public License |
17 |
* along with this program; if not, write to the Free Software |
18 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 |
*/ |
20 |
|
21 |
/* |
22 |
|
23 |
This program is similar in behaviour to "NAnt" (nant.sourceforge.net), |
24 |
except that it is written in C instead of C#. This makes it a little |
25 |
less flexible in some ways. |
26 |
|
27 |
A core tenet of the Portable.NET design philosophy is that it must |
28 |
be self-bootstrapping. That is, the build must not rely upon any |
29 |
"magic binaries" that must be built with other tools prior to |
30 |
building Portable.NET. The only "magic" that we permit is the |
31 |
C compiler. |
32 |
|
33 |
"NAnt" is not self-bootstrapping. It must be built against the C# |
34 |
system library, but that library itself is built using something |
35 |
like "NAnt". This creates a "magic binary" dependency. |
36 |
|
37 |
Hence, we have provided this C version to bootstrap the compilation |
38 |
of the C# system library. Application programmers can then build |
39 |
and use "NAnt" to achieve as much flexibility as they desire. |
40 |
|
41 |
*/ |
42 |
|
43 |
#include "csant_defs.h" |
44 |
|
45 |
#ifdef __cplusplus |
46 |
extern "C" { |
47 |
#endif |
48 |
|
49 |
/* |
50 |
* Table of command-line options. |
51 |
*/ |
52 |
static ILCmdLineOption const options[] = { |
53 |
{"-f", 'f', 1, 0, 0}, |
54 |
{"--file", 'f', 1, |
55 |
"--file name or -f name", |
56 |
"Specify the name of the build file to use."}, |
57 |
{"-b", 'b', 1, 0, 0}, |
58 |
{"--base-src-dir", 'b', 1, |
59 |
"--base-src-dir name or -b name", |
60 |
"Specify the base source directory for the build tree."}, |
61 |
{"-B", 'B', 1, 0, 0}, |
62 |
{"--base-build-dir", 'B', 1, |
63 |
"--base-build-dir name or -B name", |
64 |
"Specify the base build directory for the build tree."}, |
65 |
{"-D", 'D', 1, 0, 0}, |
66 |
{"--define", 'D', 1, |
67 |
"-Dname=value or --define name=value", |
68 |
"Define the property `name' and set it to `value'."}, |
69 |
{"-p", 'p', 1, 0, 0}, |
70 |
{"--profile", 'p', 1, |
71 |
"--profile name or -p name", |
72 |
"Specify the definition profile to use."}, |
73 |
{"-n", 'n', 0, 0, 0}, |
74 |
{"--just-print", 'n', 0, |
75 |
"--just-print or -n", |
76 |
"Print the names of the commands, but do not execute them."}, |
77 |
{"-d", 'd', 0, 0, 0}, |
78 |
{"--dummy-doc", 'd', 0, |
79 |
"--dummy-doc or -d", |
80 |
"Output dummy documentation files."}, |
81 |
{"-k", 'k', 0, 0, 0}, |
82 |
{"--keep-going", 'k', 0, |
83 |
"--keep-going or -k", |
84 |
"Keep processing even after an error."}, |
85 |
{"-s", 's', 0, 0, 0}, |
86 |
{"--silent", 's', 0, |
87 |
"--silent or -s", |
88 |
"Do not print the names of commands as they are executed."}, |
89 |
{"-c", 'c', 0, 0, 0}, |
90 |
{"--csc-redirect", 'c', 0, |
91 |
"--csc-redirect or -c", |
92 |
"Treat <csc> tags as <compile> tags (for NAnt compatibility)."}, |
93 |
{"-m", 'm', 0, 0, 0}, |
94 |
{"--mono-corlib", 'm', 0, |
95 |
"--mono-corlib or -m", |
96 |
"Use Mono's corlib instead of mscorlib during C# compiles."}, |
97 |
{"-i", 'i', 0, 0, 0}, |
98 |
{"--install", 'i', 0, |
99 |
"--install or -i", |
100 |
"Install assemblies with `ilgac' instead of compiling."}, |
101 |
{"-u", 'u', 0, 0, 0}, |
102 |
{"--uninstall", 'u', 0, |
103 |
"--uninstall or -u", |
104 |
"Uninstall assemblies with `ilgac' instead of compiling."}, |
105 |
{"--quiet", 's', 0, 0, 0}, |
106 |
{"-C", 'C', 1, 0, 0}, |
107 |
{"--compiler", 'C', 1, |
108 |
"--compiler name or -C name", |
109 |
"Specify which compiler to use [`cscc' (default), `csc', or `msc']."}, |
110 |
{"-a", 'a', 1, 0, 0}, |
111 |
{"--assembly-cache", 'a', 1, |
112 |
"--assembly-cache dir or -a dir", |
113 |
"Specify the location of the assembly cache directory."}, |
114 |
{"-v", 'v', 0, 0, 0}, |
115 |
{"--version", 'v', 0, |
116 |
"--version or -v", |
117 |
"Print the version of the program."}, |
118 |
{"--help", 'h', 0, |
119 |
"--help", |
120 |
"Print this help message."}, |
121 |
{0, 0, 0, 0, 0} |
122 |
}; |
123 |
|
124 |
static char *progname; |
125 |
|
126 |
static void usage(const char *progname); |
127 |
static void version(void); |
128 |
static char *defaultBuildFile(const char *baseDir); |
129 |
static int xmlRead(void *data, void *buffer, int len); |
130 |
|
131 |
int main(int argc, char *argv[]) |
132 |
{ |
133 |
int state, opt; |
134 |
char *buildFilename = NULL; |
135 |
char *profileFilename = NULL; |
136 |
char *param; |
137 |
char *temp; |
138 |
FILE *infile; |
139 |
int errors; |
140 |
ILXMLReader *reader; |
141 |
|
142 |
/* Parse the command-line arguments */ |
143 |
progname = argv[0]; |
144 |
state = 0; |
145 |
while((opt = ILCmdLineNextOption(&argc, &argv, &state, |
146 |
options, ¶m)) != 0) |
147 |
{ |
148 |
switch(opt) |
149 |
{ |
150 |
case 'a': |
151 |
{ |
152 |
CSAntCacheDir = param; |
153 |
} |
154 |
break; |
155 |
|
156 |
case 'b': |
157 |
{ |
158 |
CSAntBaseSrcDir = param; |
159 |
} |
160 |
break; |
161 |
|
162 |
case 'B': |
163 |
{ |
164 |
CSAntBaseBuildDir = param; |
165 |
} |
166 |
break; |
167 |
|
168 |
case 'f': |
169 |
{ |
170 |
buildFilename = param; |
171 |
} |
172 |
break; |
173 |
|
174 |
case 'D': |
175 |
{ |
176 |
temp = strchr(param, '='); |
177 |
if(temp) |
178 |
{ |
179 |
CSAntDefineProperty(param, (int)(temp - param), |
180 |
temp + 1, 1); |
181 |
} |
182 |
else |
183 |
{ |
184 |
CSAntDefineProperty(param, strlen(param), "", 1); |
185 |
} |
186 |
} |
187 |
break; |
188 |
|
189 |
case 'p': |
190 |
{ |
191 |
profileFilename = param; |
192 |
} |
193 |
break; |
194 |
|
195 |
case 'n': |
196 |
{ |
197 |
CSAntJustPrint = 1; |
198 |
} |
199 |
break; |
200 |
|
201 |
case 'd': |
202 |
{ |
203 |
CSAntDummyDoc = 1; |
204 |
} |
205 |
break; |
206 |
|
207 |
case 'k': |
208 |
{ |
209 |
CSAntKeepGoing = 1; |
210 |
} |
211 |
break; |
212 |
|
213 |
case 's': |
214 |
{ |
215 |
CSAntSilent = 1; |
216 |
} |
217 |
break; |
218 |
|
219 |
case 'c': |
220 |
{ |
221 |
CSAntRedirectCsc = 1; |
222 |
} |
223 |
break; |
224 |
|
225 |
case 'm': |
226 |
{ |
227 |
CSAntForceCorLib = 1; |
228 |
} |
229 |
break; |
230 |
|
231 |
case 'i': |
232 |
{ |
233 |
CSAntInstallMode = 1; |
234 |
} |
235 |
break; |
236 |
|
237 |
case 'u': |
238 |
{ |
239 |
CSAntUninstallMode = 1; |
240 |
} |
241 |
break; |
242 |
|
243 |
case 'C': |
244 |
{ |
245 |
CSAntCompiler = param; |
246 |
} |
247 |
break; |
248 |
|
249 |
case 'v': |
250 |
{ |
251 |
version(); |
252 |
return 0; |
253 |
} |
254 |
/* Not reached */ |
255 |
|
256 |
default: |
257 |
{ |
258 |
usage(progname); |
259 |
return 1; |
260 |
} |
261 |
/* Not reached */ |
262 |
} |
263 |
} |
264 |
|
265 |
/* Process the targets and make-style defines */ |
266 |
while(argc > 1) |
267 |
{ |
268 |
temp = strchr(argv[1], '='); |
269 |
if(temp) |
270 |
{ |
271 |
/* This is a property definition */ |
272 |
CSAntDefineProperty(argv[1], (int)(temp - argv[1]), temp + 1, 1); |
273 |
} |
274 |
else |
275 |
{ |
276 |
/* This is a target name */ |
277 |
CSAntAddBuildTarget(argv[1]); |
278 |
} |
279 |
++argv; |
280 |
--argc; |
281 |
} |
282 |
|
283 |
/* Get the default build file if none was specified */ |
284 |
if(!buildFilename) |
285 |
{ |
286 |
buildFilename = defaultBuildFile(CSAntBaseSrcDir); |
287 |
if(!buildFilename) |
288 |
{ |
289 |
fprintf(stderr, "%s: could not locate a default build file\n", |
290 |
progname); |
291 |
return 1; |
292 |
} |
293 |
} |
294 |
|
295 |
/* Get the default compiler from the environment if necessary */ |
296 |
if(!CSAntCompiler) |
297 |
{ |
298 |
CSAntCompiler = getenv("CSANT_COMPILER"); |
299 |
if(!CSAntCompiler) |
300 |
{ |
301 |
CSAntCompiler = "cscc"; |
302 |
} |
303 |
} |
304 |
|
305 |
/* Process the build file to get all of the build rules */ |
306 |
errors = 0; |
307 |
if((infile = fopen(buildFilename, "r")) == NULL) |
308 |
{ |
309 |
perror(argv[1]); |
310 |
errors = 1; |
311 |
} |
312 |
else |
313 |
{ |
314 |
if((reader = ILXMLCreate(xmlRead, infile, 0)) == 0) |
315 |
{ |
316 |
CSAntOutOfMemory(); |
317 |
} |
318 |
if(!CSAntParseFile(reader, buildFilename)) |
319 |
{ |
320 |
errors = 1; |
321 |
} |
322 |
ILXMLDestroy(reader); |
323 |
fclose(infile); |
324 |
} |
325 |
|
326 |
/* Process the profile file to get additional build rules */ |
327 |
if(errors == 0 && profileFilename != 0) |
328 |
{ |
329 |
if((infile = fopen(profileFilename, "r")) == NULL) |
330 |
{ |
331 |
perror(argv[1]); |
332 |
errors = 1; |
333 |
} |
334 |
else |
335 |
{ |
336 |
if((reader = ILXMLCreate(xmlRead, infile, 0)) == 0) |
337 |
{ |
338 |
CSAntOutOfMemory(); |
339 |
} |
340 |
if(!CSAntParseProfileFile(reader, profileFilename)) |
341 |
{ |
342 |
errors = 1; |
343 |
} |
344 |
ILXMLDestroy(reader); |
345 |
fclose(infile); |
346 |
} |
347 |
} |
348 |
|
349 |
/* Bail out if there were errors parsing the build file */ |
350 |
if(errors) |
351 |
{ |
352 |
return 1; |
353 |
} |
354 |
|
355 |
/* Execute the build rules */ |
356 |
if(!CSAntBuild(buildFilename)) |
357 |
{ |
358 |
return 1; |
359 |
} |
360 |
|
361 |
/* Done */ |
362 |
return 0; |
363 |
} |
364 |
|
365 |
static void usage(const char *progname) |
366 |
{ |
367 |
fprintf(stdout, "CSANT " VERSION " - C# compilation build tool\n"); |
368 |
fprintf(stdout, "Copyright (c) 2001, 2002, 2003 Southern Storm Software, Pty Ltd.\n"); |
369 |
fprintf(stdout, "\n"); |
370 |
fprintf(stdout, "Usage: %s [options] [target ...]\n", progname); |
371 |
fprintf(stdout, "\n"); |
372 |
ILCmdLineHelp(options); |
373 |
} |
374 |
|
375 |
static void version(void) |
376 |
{ |
377 |
|
378 |
printf("CSANT " VERSION " - C# compilation build tool\n"); |
379 |
printf("Copyright (c) 2001, 2002, 2003 Southern Storm Software, Pty Ltd.\n"); |
380 |
printf("\n"); |
381 |
printf("CSANT comes with ABSOLUTELY NO WARRANTY. This is free software,\n"); |
382 |
printf("and you are welcome to redistribute it under the terms of the\n"); |
383 |
printf("GNU General Public License. See the file COPYING for further details.\n"); |
384 |
printf("\n"); |
385 |
printf("Use the `--help' option to get help on the command-line options.\n"); |
386 |
} |
387 |
|
388 |
/* |
389 |
* Locate the name of the default build file. |
390 |
*/ |
391 |
static char *defaultBuildFile(const char *baseDir) |
392 |
{ |
393 |
CSAntDir *dir; |
394 |
const char *name; |
395 |
char *combined; |
396 |
if(!baseDir) |
397 |
{ |
398 |
baseDir = "."; |
399 |
} |
400 |
dir = CSAntDirOpen(baseDir, "*.csant"); |
401 |
if(!dir) |
402 |
{ |
403 |
return 0; |
404 |
} |
405 |
name = CSAntDirNext(dir); |
406 |
if(name) |
407 |
{ |
408 |
combined = CSAntDirCombine(baseDir, name); |
409 |
CSAntDirClose(dir); |
410 |
return combined; |
411 |
} |
412 |
CSAntDirClose(dir); |
413 |
dir = CSAntDirOpen(baseDir, "*.build"); |
414 |
if(!dir) |
415 |
{ |
416 |
return 0; |
417 |
} |
418 |
name = CSAntDirNext(dir); |
419 |
if(name) |
420 |
{ |
421 |
combined = CSAntDirCombine(baseDir, name); |
422 |
} |
423 |
else |
424 |
{ |
425 |
combined = 0; |
426 |
} |
427 |
CSAntDirClose(dir); |
428 |
return combined; |
429 |
} |
430 |
|
431 |
/* |
432 |
* Read a block of bytes from a file-based XML input stream. |
433 |
*/ |
434 |
static int xmlRead(void *data, void *buffer, int len) |
435 |
{ |
436 |
if(!feof((FILE *)data)) |
437 |
{ |
438 |
return fread(buffer, 1, len, (FILE *)data); |
439 |
} |
440 |
else |
441 |
{ |
442 |
return 0; |
443 |
} |
444 |
} |
445 |
|
446 |
void CSAntOutOfMemory(void) |
447 |
{ |
448 |
fputs(progname, stderr); |
449 |
fputs(": virtual memory exhausted\n", stderr); |
450 |
exit(1); |
451 |
} |
452 |
|
453 |
char *CSAntGetProgramName(void) |
454 |
{ |
455 |
return progname; |
456 |
} |
457 |
|
458 |
#ifdef __cplusplus |
459 |
}; |
460 |
#endif |