root/trunk/buildme.d

Revision 300, 13.3 kB (checked in by aldacron, 3 months ago)

[DerelictFT]
* incorporated Cyborg16's updates for FreeType? 2.3.5 (Ticket #19)
[DerelictGL]
* added mclysenk's changes to load OpenGL extensions on Mac
[All]
* updated copyright header in all source modules (long overdue, that)

Line 
1 /*
2  * Copyright (c) 2004-2008 Derelict Developers
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the names 'Derelict' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 //==============================================================================
33 // Imports
34 //==============================================================================
35 module buildme;
36
37 version(Tango)
38 {
39 //    static assert(0, "Tango support for the build script is currently incomplete.");
40     private
41     {
42         import tango.text.Ascii;
43         import tango.text.Util;
44         import tango.io.File;
45         import tango.sys.Process;
46         import tango.core.Version;
47         import tango.stdc.stringz;
48         import tango.stdc.stdio;
49         import tango.io.FilePath;
50         import tango.io.Stdout;
51         import tango.sys.Environment;
52     }
53 }
54 else
55 {
56     private
57     {
58         import std.string;
59         import std.path;
60         import std.file;
61         import std.c.process;
62     }
63 }
64
65 //==============================================================================
66 // Constants
67 //==============================================================================
68 version(Windows)
69 {
70     private static const char[] delCmd  = "cmd /c del ";
71     private static const char[] pathSep     = "\\";
72     private static const char[] libPre      = "";
73     private static const char[] libExt      = ".lib";
74 }
75 else version(linux)
76 {
77     version = NixConst;
78 }
79 else version(Unix)
80 {
81     version = NixConst;
82 }
83
84 version(NixConst)
85 {
86     private static const char[] delCmd      = "rm -f ";
87     private static const char[] pathSep     = "/";
88     private static const char[] libPre      = "lib";
89     private static const char[] libExt      = ".a";
90 }
91
92 // this must be set in a static class constructor in the builder file
93 private Builder theBuilder = null;
94
95 //==============================================================================
96 // Options
97 //==============================================================================
98 // build configurations
99 enum Mode
100 {
101     Debug,
102     Release
103 }
104 private Mode mode = Mode.Release;
105
106 // option file types
107 enum OptsType
108 {
109     Debug,
110     Release,
111     Common
112 }
113
114 // when true, do not delete the temporary Build Response File for Bud
115 private bool doNotDeleteBRF = false;
116
117 //==============================================================================
118 // Main
119 //==============================================================================
120 void main(char[][] args)
121 {
122     // check if the first arg is the cleanlib argument
123     if(args.length == 2 && (cmpStr(toLowerStr(args[1]), "cleanlib") == 0))
124     {
125         cleanLib();
126         return;
127     }
128
129     // list of package names passed on the command line
130     char[][] packageList;
131
132     // parse the command line
133     foreach(c; args)
134     {
135         char[] lower = toLowerStr(c);
136         switch(lower)
137         {
138             case "bud":
139                 theBuilder = new BudBuilder();
140                 break;
141             case "debug":
142                 mode = Mode.Debug;
143                 break;
144             case "release":
145                 mode = Mode.Release;
146                 break;
147             case "nodelbrf":
148                 doNotDeleteBRF = true;
149                 break;
150             default:
151                 if(findStr(lower, "derelict") == 0)
152                 {
153                     packageList ~= c;
154                 }
155                 break;
156         }
157     }
158
159     theBuilder.build(packageList);
160 }
161
162 //==============================================================================
163 // CleanLib -- this is a special command that doesn't warrant a builder class
164 //==============================================================================
165 void cleanLib()
166 {
167     printf("[BuildMe] Deleting all %s files from the lib subdirectory...\n", toCString(libExt));
168     execute(delCmd ~ "lib" ~ pathSep ~ "*" ~ libExt);
169     printf("[BuildMe] Finished!\n\n");
170 }
171
172 //==============================================================================
173 // Builder Class
174 //==============================================================================
175 class Builder
176 {
177     abstract void buildPackage(char[] packageName);
178
179 private:
180     void build(char[][] packageList)
181     {
182         // if no packages were passed in, scan for buildable packages
183         if(packageList.length == 0 || packageList is null)
184         {
185             scanForPackages();
186         }
187         else
188         {
189             // iterate the package list and build each package
190             foreach(s; packageList)
191             {
192                 buildPackage(s);
193             }
194         }
195     }
196
197     void scanForPackages()
198     {
199         printf("\n[BuildMe] Scanning for buildable packages...\n\n");
200
201         // cycle through every Derelict directory to find buildable packages
202         version(Tango)
203         {
204             bool filter(FilePath p, bool isDir)
205             {
206                 char[] name = p.name;
207                 if(isDir && name[0] != '.')
208                     return true;
209                 return false;
210             }
211             scope dir = new FilePath(".");
212             foreach(p; dir.toList(&filter))
213             {
214                 processPackage(p.name);
215             }
216         }
217         else
218         {
219             auto list = listdir(".");
220             foreach(c; list)
221             {
222                 // if this filename is a directory, process it for building
223                 if(isdir(c) && c[0] != '.')
224                     processPackage(c);
225             }
226         }
227
228         printf("[BuildMe] Finished!\n\n");
229     }
230
231     void processPackage(char[] packageName)
232     {
233         // test if the package is buildable
234         if(findStr(packageName, "Derelict") != 0)
235         {
236             printf("[BuildMe] Nothing to do for directory \'%s\'\n", toCString(packageName));
237         }
238         else
239         {
240             buildPackage(packageName);
241         }
242     }
243 }
244
245 //==============================================================================
246 // BudBuilder -- for building with the Bud tool
247 //==============================================================================
248 class BudBuilder : Builder
249 {
250     static this()
251     {
252         theBuilder = new BudBuilder();
253     }
254
255     //==========================================================================
256     // Methods
257     //==========================================================================
258     override void buildPackage(char[] packageName)
259     {
260         // construct a path to the package's forbud file
261         char[] path = packageName ~ pathSep ~ _forBudName;
262
263         // create the temporary brf
264         printf("[BuildMe] Preparing to build package %s in %s mode...\n", toCString(packageName), toCString(modeToString()));
265         if(!createBRF(packageName, path))
266             return false;
267
268         // call out to build with the name of the temp brf as an arg
269         printf("[BuildMe] Building %s...\n", toCString(packageName));
270         if(execute(_name ~ " @" ~ _tempBRFName) != 0)
271         {
272             throw new Exception("Failed to build package " ~ packageName);
273         }
274
275         if(!doNotDeleteBRF)
276         {
277             // delete the temporary brf
278             printf("[BuildMe] Deleting temporary Build Response File...\n\n");
279             execute(delCmd ~ _tempBRFName);
280         }
281     }
282
283 private:
284     this()
285     {
286         _name               = "bud";
287         _tempBRFName        = "temp.brf";
288         _forBudName         = "forbud.txt";
289         _brfBuf             = "";
290
291         _brfBuf = loadOpts(_name, OptsType.Common) ~ "\n";
292         _brfBuf ~= loadOpts(_name, cast(OptsType)mode);
293     }
294
295     bool createBRF(char[] packageName, char[] path)
296     {
297         printf("[BuildMe] Reading build tool arguments...\n");
298
299         char[] txt;         // holds the contents of the forbud file
300
301         // read the forbud.txt in this package
302         txt = readFile(path);
303
304         // make sure the file was found
305         if(txt is null)
306         {
307             printf("[BuildMe] Could not find %s\n", toCString(path));
308             return false;
309         }
310
311         // this will store all of the text to be output to the temp brf
312         char[] brf = "";
313
314         // append the common brf buffer
315         brf ~= _brfBuf;
316
317         // the package directory myst be on the import path
318         brf ~= "\n-I" ~ packageName;
319
320         // if the current package is not DerelictUtil, then DerelictUtil must
321         // be on the import path and excluded from compilation
322         if(cmpStr(packageName, "DerelictUtil") != 0)
323         {
324             brf ~= "\n-IDerelictUtil\n-XDerelictUtil" ~ pathSep ~ "derelict" ~ pathSep ~ "util";
325         }
326
327         // append a switch to set the output path of the library and append the config file
328         brf ~= "\n-Tlib" ~ pathSep ~ libPre ~ packageName ~ libExt ~ "\n" ~ txt;
329
330         // write the temporary brf to disk
331         printf("[BuildMe] Creating temporary Build Response File...\n");
332
333         writeFile(_tempBRFName, brf);
334
335         return true;
336     }
337
338     //==========================================================================
339     // Members
340     //==========================================================================
341     char[] _name;
342     char[] _tempBRFName;
343     char[] _forBudName;
344     char[] _brfBuf;
345 }
346
347 //==============================================================================
348 // Utility functions
349 //==============================================================================
350 char[] modeToString()
351 {
352     return (mode == Mode.Debug) ? "Debug" : "Release";
353 }
354
355 char[] loadOpts(char[] prefix, OptsType type)
356 {
357     char[] fileName = "buildopts" ~ pathSep ~ prefix ~ optsSuffix(type) ~ ".txt";
358     char[] ret = readFile(fileName);
359     if(ret is null)
360     {
361         throw new Exception(fileName ~ " is missing!");
362     }
363     return ret;
364 }
365
366 char[] optsSuffix(OptsType type)
367 {
368     switch(type)
369     {
370         case OptsType.Common:
371             return "_common";
372         case OptsType.Release:
373             return "_release";
374         case OptsType.Debug:
375             return "_debug";
376         default:
377             throw new Exception("Unknown OptsType");
378     }
379 }
380
381 //==============================================================================
382 // Phobos/Tango Wrappers
383 //==============================================================================
384 char[] toLowerStr(char[] str)
385 {
386     version(Tango)
387     {
388         return toLower(str.dup);
389     }
390     else
391     {
392         return tolower(str);
393     }
394 }
395
396 int cmpStr(char[] a, char[] b)
397 {
398     version(Tango)
399     {
400         return compare(a,b);
401     }
402     else
403     {
404         return cmp(a,b);
405     }
406 }
407
408 int findStr(char[] str, char[] match)
409 {
410     version(Tango)
411     {
412         int i = locatePattern(str, match);
413         return (i == str.length) ? -1 : i;
414     }
415     else
416     {
417         return find(str, match);
418     }
419 }
420
421 char[][] splitString(char[] str, char[] delim)
422 {
423     return split(str, delim);
424 }
425
426 char *toCString(char[] str)
427 {
428     version(Tango)
429     {
430         return toStringz(str);
431     }
432     else
433     {
434         return toStringz(str);
435     }
436 }
437
438 int execute(char[] cmd)
439 {
440     version(Tango)
441     {
442         auto p = new Process(cmd, Environment.get);
443         p.execute();
444 //        Stdout.stream.copy(p.stdout);
445         auto r = p.wait();
446         return r.status;
447     }
448     else
449     {
450         return system(toStringz(cmd));
451     }
452 }
453
454 char[] readFile(char[] name)
455 {
456     version(Tango)
457     {
458         scope f = new File(name);
459         return cast(char[])f.read();
460     }
461     else
462     {
463         if(exists(name))
464             return cast(char[])read(name);
465         else
466             return null;
467     }
468 }
469
470 void writeFile(char[] name, char[] contents)
471 {
472     version(Tango)
473     {
474         scope f = new File(name);
475         f.write(cast(void[])contents);
476     }
477     else
478     {
479         write(name, cast(void[])contents);
480     }
481 }
Note: See TracBrowser for help on using the browser.