root/branches/bud/sss/build.d

Revision 276, 12.1 kB (checked in by Gregor, 2 years ago)

sss/build.d: Fixed a bug with subdirs and buildflags.

Line 
1 /**
2  * DSSS command "build"
3  *
4  * Authors:
5  *  Gregor Richards
6  *
7  * License:
8  *  Copyright (c) 2006  Gregor Richards
9  * 
10  *  Permission is hereby granted, free of charge, to any person obtaining a
11  *  copy of this software and associated documentation files (the "Software"),
12  *  to deal in the Software without restriction, including without limitation
13  *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  *  and/or sell copies of the Software, and to permit persons to whom the
15  *  Software is furnished to do so, subject to the following conditions:
16  * 
17  *  The above copyright notice and this permission notice shall be included in
18  *  all copies or substantial portions of the Software.
19  * 
20  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  *  DEALINGS IN THE SOFTWARE.
27  */
28
29 module sss.build;
30
31 import std.file;
32 import std.process;
33 import std.stdio;
34 import std.string;
35
36 import std.c.stdlib;
37
38 import hcf.path;
39 import hcf.process;
40
41 import sss.conf;
42
43 /** The entry function to the DSSS "build" command */
44 int build(char[][] buildElems, DSSSConf conf = null, char[] forceFlags = "") {
45     // get the configuration
46     if (conf is null)
47         conf = readConfig(buildElems);
48    
49     // buildElems are by either soure or target, so we need one by source only
50     char[][] buildSources;
51    
52     // get the sources
53     buildSources = sourcesByElems(buildElems, conf);
54    
55     // also get a complete list, since some steps need it
56     char[][] allSources = sourcesByElems(null, conf);
57    
58     /* building is fairly complicated, involves these steps:
59      * 1) Make .di files
60      *    (so that you link against your own libraries)
61      * 2) Make fake shared libraries
62      *    (they need to exist so that other libraries can link against them)
63      * 3) Make real shared libraries
64      * 4) Make binaries
65      */
66    
67     // make the basic build line
68     char[] bl = dsss_build ~ forceFlags;
69    
70     // for DMD, force output files to be generated in this directory
71     version (DigitalMars) {
72         bl ~= "-od. ";
73     }
74    
75     // 1) Make .di files for everything
76     foreach (build; allSources) {
77         char[][char[]] settings = conf.settings[build];
78        
79         // basic info
80         char[] type = settings["type"];
81         char[] target = settings["target"];
82        
83         if (type == "library") {
84             writefln("Creating imports for %s", target);
85            
86             // this is a library, so make .di files
87             char[][] srcFiles = targetToFiles(build, conf);
88            
89             // generate .di files
90             foreach (file; srcFiles) {
91                 if (!exists(file ~ "i") ||
92                     fileNewer(file, file ~ "i")) {
93                    
94                     /+
95                     // FIXME: this should not assume by version()
96                     int res;
97                     version (GNU) {
98                         res = system(dsss_build ~
99                                      "-obj -full -fintfc -fintfc-file=" ~
100                                      file ~ "i " ~ file);
101                     } else version (DigitalMars) {
102                         res = system(dsss_build ~
103                                      "-obj -full -H -Hf" ~
104                                      file ~ "i " ~ file);
105                     } else {
106                         static assert(0);
107                     }
108                     
109                     if (res) {
110                         // make sure the .i file is removed
111                         std.file.remove(file ~ "i");
112                         return res;
113                     }
114                     +/
115                    
116                     /* BIG FAT NOTE slash FIXME:
117                      * .di files do NOT include interfaces! So, we need to just
118                      * cast .d files as .di until that's fixed */
119                     std.file.copy(file, file ~ "i");
120                    
121                     // now edit the .di file to reference the appropriate library
122                    
123                     // usname = name_with_underscores
124                     char[] usname = replace(build, std.path.sep, "_");
125                    
126                     if (shLibSupport() &&
127                         ("shared" in settings)) {
128                           std.file.write(file ~ "i", std.file.read(file ~ "i") ~ `
129 version (build) {
130     version (DSSS_Static_` ~ usname ~ `) {
131         pragma(link, "S` ~ target ~ `");
132     } else {
133         pragma(link, "` ~ target ~ `");
134     }
135 }
136 `);
137                     } else {
138                         std.file.write(file ~ "i", std.file.read(file ~ "i") ~ `
139 version (build) {
140     pragma(link, "S` ~ target ~ `");
141 }
142 `);
143                     }
144                 }
145             }
146            
147             writefln("");
148            
149         } else if (type == "subdir") {
150             // recurse
151             char[] origcwd = getcwd();
152             chdir(build);
153            
154             // the one thing that's passed in is build flags
155             char[] orig_dsss_build = dsss_build.dup;
156             if ("buildflags" in settings) {
157                 dsss_build ~= settings["buildflags"] ~ " ";
158             }
159            
160             int buildret = sss.build.build(null);
161             chdir(origcwd);
162            
163             dsss_build = orig_dsss_build;
164         }
165     }
166    
167     // 2) Make fake shared libraries
168     if (shLibSupport()) {
169         foreach (build; allSources) {
170             char[][char[]] settings = conf.settings[build];
171            
172             // ignore this if we're not building a shared library
173             if (!("shared" in settings)) continue;
174        
175             // basic info
176             char[] type = settings["type"];
177             char[] target = settings["target"];
178        
179             if (type == "library") {
180                 char[] shlibname = getShLibName(settings);
181                 char[][] shortshlibnames = getShortShLibNames(settings);
182                 char[] shlibflag = getShLibFlag(settings);
183                
184                 if (exists(shlibname)) continue;
185                
186                 writefln("Building stub shared library for %s", target);
187                
188                 // make the stub
189                 version (GNU_or_Posix) {
190                     char[] stubbl = bl ~ "-fPIC -shlib " ~ stubDLoc ~ " -T" ~ shlibname ~
191                     " " ~ shlibflag;
192                     saySystemDie(stubbl);
193                     version (Posix) {
194                         foreach (ssln; shortshlibnames) {
195                             saySystemDie("ln -sf " ~ shlibname ~ " " ~ ssln);
196                         }
197                     }
198                 } else version (Windows) {
199                     assert(0);
200                 } else {
201                     static assert(0);
202                 }
203                
204                 writefln("");
205             }
206         }
207     }
208    
209     // 3) Make real libraries
210     foreach (build; buildSources) {
211         char[][char[]] settings = conf.settings[build];
212        
213         // basic info
214         char[] type = settings["type"];
215         char[] target = settings["target"];
216        
217         if (type == "library") {
218             char[] dotname = std.string.replace(build, std.path.sep, ".");
219            
220             // get the list of files
221             char[][] files = targetToFiles(build, conf);
222            
223             // unfortunately, at each step we need to move the .di files out of the way, then back
224             // I'd like a switch in build to avoid this, but there isn't one
225             foreach (file; files) {
226                 std.file.rename(file ~ "i", file ~ "i0");
227             }
228            
229             // and other necessary data
230             char[] shlibname = getShLibName(settings);
231             char[] shlibflag = getShLibFlag(settings);
232             char[] bflags;
233             if ("buildflags" in settings) {
234                 bflags = settings["buildflags"];
235             }
236            
237             // output what we're building
238             writefln("%s => %s", build, target);
239        
240             // do the prebuild
241             if ("prebuild" in settings) {
242                 dsssScriptedStep(conf, settings["prebuild"]);
243             }
244            
245             // get the file list
246             char[] fileList = std.string.join(targetToFiles(build, conf), " ");
247            
248             version (GNU_or_Posix) {
249                 // first do a static library
250                 if (exists("libS" ~ target ~ ".a")) std.file.remove("libS" ~ target ~ ".a");
251                 char[] stbl = bl ~ bflags ~ " -explicit -lib -full " ~ fileList ~ " -TlibS" ~ target ~ ".a";
252                 saySystemDie(stbl);
253                
254                 if (shLibSupport() &&
255                     ("shared" in settings)) {
256                     // then make the shared library
257                     if (exists(shlibname)) std.file.remove(shlibname);
258                     char[] shbl = bl ~ bflags ~ " -fPIC -explicit -shlib -full " ~ fileList ~ " -T" ~ shlibname ~
259                         " " ~ shlibflag;
260                    
261                     // finally, the shared compile
262                     saySystemDie(shbl);
263                 }
264                
265             } else version (Windows) {
266                 // for the moment, only do a static library
267                 if (exists("S" ~ target ~ ".lib")) std.file.remove("S" ~ target ~ ".lib");
268                 char[] stbl = bl ~ bflags ~ " -explicit -lib -full " ~ fileList ~ " -TS" ~ target ~ ".lib";
269                 saySystemDie(stbl);
270             } else {
271                 static assert(0);
272             }
273        
274             // do the postbuild
275             if ("postbuild" in settings) {
276                 dsssScriptedStep(conf, settings["postbuild"]);
277             }
278            
279             // unfortunately, at each step we need to move the .di files out of the way, then back
280             foreach (file; files) {
281                 std.file.rename(file ~ "i0", file ~ "i");
282             }
283            
284             // an extra line for clarity
285             writefln("");
286         }
287     }
288    
289     // 4) Binaries and specials
290     foreach (build; buildSources) {
291         char[][char[]] settings = conf.settings[build];
292        
293         // basic info
294         char[] type = settings["type"];
295         char[] target = settings["target"];
296        
297         if (type == "binary") {
298             // our binary build line
299             char[] bflags;
300             if ("buildflags" in settings) {
301                 bflags = settings["buildflags"];
302             }
303            
304             char[] bbl = bl ~ bflags ~ " ";
305            
306             // output what we're building
307             writefln("%s => %s", build, target);
308            
309             // do the prebuild
310             if ("prebuild" in settings) {
311                 dsssScriptedStep(conf, settings["prebuild"]);
312             }
313            
314             // build a build line
315             char[] ext = std.string.tolower(getExt(build));
316             if (ext == "d") {
317                 bbl ~= build ~ " -T" ~ target ~ " ";
318             } else if (ext == "brf") {
319                 bbl ~= "@" ~ getName(build) ~ " ";
320             } else {
321                 writefln("ERROR: I don't know how to build something with extension %s", ext);
322                 return 1;
323             }
324            
325             // then do it
326             saySystemDie(bbl);
327            
328             // do the postbuild
329             if ("postbuild" in settings) {
330                 dsssScriptedStep(conf, settings["postbuild"]);
331             }
332            
333             // an extra line for clarity
334             writefln("");
335            
336         } else if (type == "special") {
337             // special type, do pre/post
338             writefln("%s", target);
339             if ("prebuild" in settings) {
340                 dsssScriptedStep(conf, settings["prebuild"]);
341             }
342            
343             if ("postbuild" in settings) {
344                 dsssScriptedStep(conf, settings["postbuild"]);
345             }
346             writefln("");
347            
348         }
349     }
350    
351     return 0;
352 }
Note: See TracBrowser for help on using the browser.