root/branches/bud/dsss_build/build.d

Revision 229, 126.6 kB (checked in by Gregor, 2 years ago)

RELEASE: 0.12 (try 3)

dsss_build/build.d: Fixed another bizarre library linking bug on DMD/Windows.

Line 
1 /* *******************************************************
2    Build is a tool to assist building applications and libraries written
3    using the D programming language.
4
5  Copyright:
6    (c) 2005 Derek Parnell
7    (c) 2006 Gregor Richards
8  Authors:
9    Derek Parnell, Melbourne
10    Gregor Richards
11  Initial Creation: January 2005
12  Version: 3.04+DSSS
13  Date: October 2006
14  License:
15         This software is provided 'as-is', without any express or implied
16         warranty. In no event will the authors be held liable for damages
17         of any kind arising from the use of this software.
18         Permission is hereby granted to anyone to use this software for any
19         purpose, including commercial applications, and to alter it and/or
20         redistribute it freely, subject to the following restrictions:$(NL)
21         1. The origin of this software must not be misrepresented; you must
22            not claim that you wrote the original software. If you use this
23            software in a product, an acknowledgment within documentation of
24            said product would be appreciated but is not required.$(NL)
25         2. Altered source versions must be plainly marked as such, and must
26            not be misrepresented as being the original software.$(NL)
27         3. This notice may not be removed or altered from any distribution
28            of the source.$(NL)
29         4. Derivative works are permitted, but they must carry this notice
30            in full and credit the original source.
31 ******************************************************* */
32
33 module build;
34 private import build_bn;    // This module's build number
35
36 version(unix)   version = Unix;
37 version(Unix)   version = Posix;
38 version(linux)  version = Posix;
39 version(darwin) version = Posix;
40 version(DigitalMars) version(Windows) version = UseResponseFile;
41
42 version(build)
43 {
44     version(Windows) {
45         // OptLink Definition File
46         pragma (build_def, "VERSION 3.04");
47     }
48 }
49
50
51 private{
52     alias char[] string;
53     // --------- imports ----------------
54     static import source;          // Source File class
55
56     static import util.str;        // non-standard string routines.
57     static import util.fdt;        // File Date-Time class
58     static import util.pathex;     // Extended Path routines.
59     static import util.fileex;     // Extended File routines.
60     static import util.macro;      // Macro processing routines.
61     static import util.booltype;   // definition of True and False
62     alias util.booltype.True True;
63     alias util.booltype.False False;
64     alias util.booltype.Bool Bool;
65
66     static import std.c.stdio;
67     static import std.file;
68     static import std.outbuffer;
69     static import std.path;
70     static import std.stdio;
71     static import std.stream;
72     static import std.string;
73
74     version(Windows)
75     {
76         static import std.c.windows.windows;
77     }
78
79     else version(linux)
80     {
81         static import std.c.linux.linux;
82     }
83
84     else version(darwin)
85     {
86         static import std.c.darwin.darwin;
87     }
88
89     // --------- C externals ----------------
90     extern (C)
91     {
92         int     system  (char *);
93     }
94
95     class BuildException : Error
96     {
97         this(string pMsg)
98         {
99             super (vAppName ~ ":" ~ pMsg);
100         }
101     }
102
103     // --------- enums ----------------
104     enum LibOpt {Implicit, Build, Shared, DontBuild}
105
106     // --------- internal strings ----------------
107     version(Windows) {
108         string vExeExtension=`exe`;
109         string vLibExtension=`lib`;
110         string vObjExtension=`obj`;
111         string vShrLibExtension=`dll`;
112         string vLinkerStdOut = ">nul";
113     }
114
115     version(Posix) {
116         string vExeExtension=``;
117         string vLibExtension=`a`;
118         string vObjExtension=`o`;
119         string vShrLibExtension=`so`;
120         string vLinkerStdOut = ">/dev/null";
121     }
122     string vSrcExtension=`d`;
123     string vSrcDInterfaceExt = `di`;
124     string vMacroExtension=`mac`;
125     string vDdocExtension=`ddoc`;
126
127     // ---------- Module scoped globals -----------
128     version(DigitalMars) {
129         version(Windows) {
130             string vCompilerExe=`dmd.exe`;
131             string vCompileOnly = `-c`;
132             string vLinkerExe=`link.exe`;
133             bool   vPostSwitches = true;
134             bool   vAppendLinkSwitches = true;
135             string vArgDelim = ",";
136             string vArgFileDelim = "+";
137             string vConfigFile=`sc.ini`;
138             string vCompilerPath=``;
139             string vLinkerPath=``;
140             string vLinkerDefs=`/noi/map`;
141             string vConfigPath=``;
142             string vLibPaths = ``;
143             string vConfigSep = ";";
144             string vLibrarian = `lib.exe`;
145             string vLibrarianOpts = `-c -p256`;
146             string vPostLibrarian = ``;
147             bool   vShLibraries = false;
148             string vShLibrarian = "";
149             string vShLibrarianOpts = "";
150             string vShLibrarianOutFileSwitch = "";
151             string vHomePathId = "HOME";
152             string vEtcPath    = "";
153             string vSymInfoSwitch = "/co";
154             string vOutFileSwitch = "-of";
155             string vLinkLibSwitch = "";
156         }
157
158         version(Posix) {
159             string vCompilerExe=`dmd`;
160             string vCompileOnly= `-c`;
161             string vLinkerExe=`gcc`;
162             bool   vPostSwitches = false;
163             bool   vAppendLinkSwitches = false;
164             string vArgDelim = " ";
165             string vArgFileDelim = " ";
166             string vConfigFile=`dmd.conf`;
167             string vCompilerPath=``;
168             string vLinkerPath=``;
169             string vLinkerDefs=``;
170             string vConfigPath=`/etc/`;
171             string vLibPaths = ``;
172             string vConfigSep = ":";
173             string vLibrarian = `ar`;
174             string vLibrarianOpts = `-r`;
175             string vPostLibrarian = `ranlib`;
176             bool   vShLibraries = false;
177             string vShLibrarian = "";
178             string vShLibrarianOpts = "";
179             string vShLibrarianOutFileSwitch = "";
180             string vHomePathId = "HOME";
181             string vEtcPath    = "/etc/";
182             string vSymInfoSwitch = "-g";
183             string vOutFileSwitch = "-o ";
184             string vLinkLibSwitch = "-l";
185         }
186
187         string     vVersionSwitch = "-version";
188         string     vDebugSwitch = "-debug";
189         string[]   vCompilerDefs;
190         string     vImportPath = "-I";
191         bool       vUseModBaseName = false;
192        
193         // circular dependency things
194         bool       vCircularDepsOK = true;
195         bool       vCircularLinkAll = false;
196         string     vCircularOnlyFlag = "";
197     }
198
199     version(GNU) {
200         version(Windows) {
201             string vCompilerExe=`gdc.exe`;
202             string vCompileOnly= `-c`;
203             string vLinkerExe=`gdc.exe`;
204             bool   vPostSwitches = false;
205             bool   vAppendLinkSwitches = false;
206             string vArgDelim = " ";
207             string vArgFileDelim = " ";
208             string vConfigFile=null;
209             string vCompilerPath=``;
210             string vLinkerPath=``;
211             string vLinkerDefs=``;
212             string vConfigPath=null;
213             string vLibPaths = ``;
214             string vConfigSep = ";";
215             string vLibrarian = `ar.exe`;
216             string vLibrarianOpts = `-c`;
217             string vPostLibrarian = `ranlib.exe`;
218             bool   vShLibraries = false;
219             string vShLibrarian = "";
220             string vShLibrarianOpts = "";
221             string vShLibrarianOutFileSwitch = "";
222             string vLinkLibSwitch = "-l";
223             string vHomePathId = "HOME";
224             string vEtcPath    = "";
225         }
226
227         version(Posix) {
228             string vCompilerExe=`gdc`;
229             string vCompileOnly= `-c`;
230             string vLinkerExe=`gdc`;
231             bool   vPostSwitches = false;
232             bool   vAppendLinkSwitches = false;
233             string vArgDelim = " ";
234             string vArgFileDelim = " ";
235             string vConfigFile=null;
236             string vCompilerPath=``;
237             string vLinkerPath=``;
238             string vLinkerDefs=``;
239             string vConfigPath=null;
240             string vLibPaths = ``;
241             string vConfigSep = ":";
242             string vLibrarian = `ar`;
243             string vLibrarianOpts = `-r`;
244             string vPostLibrarian = `ranlib`;
245             bool   vShLibraries = true;
246             string vShLibrarian = `gcc`;
247             string vShLibrarianOpts = `-shared`;
248             string vShLibrarianOutFileSwitch = `-o `;
249             string vLinkLibSwitch = "-l";
250             string vHomePathId = "HOME";
251             string vEtcPath    = "/etc/";
252         }
253        
254         string     vOutFileSwitch = "-o ";
255         string     vVersionSwitch = "-fversion";
256         string     vDebugSwitch = "-fdebug";
257         string[]   vCompilerDefs;
258         string     vImportPath = "-I ";
259         string     vSymInfoSwitch = "-g";
260         /* GDC places object files in the directory from which it is called */
261         bool       vUseModBaseName = true;
262        
263         // circular dependency things
264         bool       vCircularDepsOK = false;
265         bool       vCircularLinkAll = true;
266         string     vCircularOnlyFlag = "-fonly=";
267     }
268
269     string       vCFGPath = ``;
270     string       vOverrideConfigPath = "";
271     string       vBuildImportPath = "-I";
272     string       vImportPathDelim = ";";
273     string       vOutputPath = "-od";
274     string       vRunSwitch = "-exec";
275     string       vLibrarianPath = "";
276     string*      vDelayedValue = null;
277     string       vTemporaryPath = "";
278     string       vLibPathSwitch = "-L";
279     string       vMapSwitch = "-M";
280     string       vGenDebugInfo = "-g";
281     string       vResponseExt = "brf";
282     string       vDefResponseFile = "build.brf";
283     string       vDefMacroDefFile = "build.mdf";
284     string       vUtilsConfigFile = "build.cfg";
285     string       vPathId = "PATH";   // Used to locate the environment symbol
286
287     string       vModOutPrefix = "MODULES = \n";
288     string       vModOutSuffix = "";
289     string       vModOutBody   = "    $(MODULE {mod})\n";
290     string       vModOutDelim  = "";
291     string       vModOutFile   = "_modules.ddoc";
292
293     string[]     vFinalProc;
294
295     Bool         vTestRun;
296     Bool         vExplicit;
297     Bool         vScanImports;
298     Bool         vNoLink;
299     Bool         vForceCompile;
300     Bool         vSilent;
301     Bool         vSymbols;
302     Bool         vCleanup;
303     version(BuildVerbose) Bool         vVerbose;
304     Bool         vMacroInput;
305     Bool         vCollectUses;
306     Bool         vNames;
307     Bool         vAllObjects;
308     Bool         vNoDef;
309     Bool         vAutoImports;
310     Bool         vExecuteProgram;
311     Bool         vUseResponseFile;
312     Bool         vConsoleApp;
313     Bool         vUseFinal;
314     Bool         vEmptyArgs;
315    
316     Bool         vCircularDeps;
317
318     string       vUsesOutput;
319     string       vSymbolOutName;
320     string       vRunParms;
321     string       vTargetExe;
322     string[]     vImportRoots;
323     string[]     vModulesToIgnore;
324     string[]     vModulesToNotice;
325     string[]     vBuildDef;
326     string[]     vDefaultLibs;
327     LibOpt       vLibraryAction = LibOpt.Implicit;
328     string       vAppPath;
329     string       vAppName;
330     string       vAppVersion = "3.04";
331     string       vTargetName;           // Output name from first file name.
332     string       vPragmaTargetName;     // Output name from pragma.
333     string       vCommandTargetName;    // Output name from switches.
334     string[]     vCmdLineSourceFiles;   // List of source files from command line
335     string[]     vLinkFiles;            // List of non-source files from command line
336     string[]     vCombinedArgs;         // All the args are gathered here prior to processing.
337     string[]     vBuildArgs;            // Arguments passed to build
338     string[]     vCompilerArgs;         // Arguments passed to compiler
339     string[]     vSourceScanList;       // The list of places to find source files.
340     bool[string] vResourceFileTypes;
341     string[]     vUDResTypes;
342
343
344     version(Windows)
345     {
346         string       vWinVer = "";
347         ubyte        vWinVerNum;
348         bool         vAutoWinLibs = true;
349     }
350
351 }
352
353 // Module constructor.
354 //-------------------------------------------------------
355 static this()
356 //-------------------------------------------------------
357 {
358     // Force the 'build' version to be active.
359     source.ActivateVersion("build");
360
361     vSourceScanList ~= "." ~ std.path.sep;
362     vNoLink = False;
363     vTestRun = False;
364     vExplicit = False;
365     vScanImports = False;
366     vUseFinal = True;
367     vEmptyArgs = True;
368     vForceCompile = False;
369     vSilent = False;
370     vCleanup = False;
371     version(BuildVerbose) vVerbose = False;
372     vMacroInput = True;
373     vCollectUses = False;
374     vNames = False;
375     vAllObjects = False;
376     vNoDef = False;
377     vAutoImports = True;
378     vExecuteProgram = False;
379     vUseResponseFile = False;
380     vSymbols = False;
381     vConsoleApp = True;
382    
383     vCircularDeps = False;
384
385     version(Posix)
386     {
387         vCompilerDefs ~= vVersionSwitch ~ "=Posix"; // Until such time as this is standard in dmd.
388     }
389
390     version(Windows) {
391         vWinVerNum = cast(ubyte)(std.c.windows.windows.GetVersion() & 0xFF);
392         vWinVer = std.string.format("%d.0", vWinVerNum);
393      }
394
395     vUseResponseFile = False;
396     version(UseResponseFile) vUseResponseFile = True;
397
398     util.str.SetEnv("@P", std.path.getDirName(vConfigPath));
399     util.str.SetEnv("@D", std.path.getDirName(vCompilerPath));
400
401     source.Source.UseModBaseName(vUseModBaseName);
402
403 }
404
405 //-------------------------------------------------------
406 void DisplayUsage(bool pFull = true)
407 //-------------------------------------------------------
408 {
409
410     std.stdio.writefln(
411         "Path and Version : %s v%s(%d)\n  built on %s"
412             ,vAppPath, vAppVersion, build_bn.auto_build_number,
413             __TIMESTAMP__);
414     if (pFull == false)
415         return;
416     else {
417
418     std.stdio.writefln(
419         "Usage: %s sourcefile [options objectfiles libraries]"
420             , vAppName);
421     std.stdio.writefln("  sourcefile D source file");
422     std.stdio.writefln("  -v         Verbose (passed through to D)");
423     std.stdio.writefln("  -V         Verbose (NOT passed through)");
424     std.stdio.writefln("  -names     Displays the names of the files used in building the target.");
425     std.stdio.writefln("  -DCPATH<path> <path> is where the compiler has been installed.");
426     std.stdio.writefln("             Only needed if the compiler is not in the system's");
427     std.stdio.writefln("             PATH list. Used if you are testing an alternate");
428     std.stdio.writefln("             version of the compiler.");
429     std.stdio.writefln("  -CFPATH<path> <path> is where the D config file has been installed.");
430     std.stdio.writefln("  -BCFPATH<path> <path> is where the Build config file has been installed.");
431     std.stdio.writefln("  -full      Causes all source files, except ignored modules,");
432     std.stdio.writefln("              to be compiled.");
433     std.stdio.writefln("  -link      Forces the linker to be called instead of the librarian.");
434     std.stdio.writefln("              (Only needed if the source files do not contain");
435     std.stdio.writefln("               main/WinMain)");
436     std.stdio.writefln("  -nolink    Ensures that the linker is not called.");
437     std.stdio.writefln("              (Only needed if main/WinMain is found in the source");
438     std.stdio.writefln("               files and you do NOT want an executable created.)");
439     std.stdio.writefln("  -lib       Forces the object files to be placed in a library.");
440     std.stdio.writefln("              (Only needed if main/WinMain is found in the source");
441     std.stdio.writefln("               files AND you want it in a library instead of");
442     std.stdio.writefln("               an executable.)");
443     std.stdio.writefln("  -shlib     Forces the object files to be placed in a shared library.");
444     std.stdio.writefln("  -shlib-support");
445     std.stdio.writefln("             Output 'yes' and return a successful exit code if shared");
446     std.stdio.writefln("             libraries are supported, otherwise output 'no' and return");
447     std.stdio.writefln("             a failure exit code.");
448     std.stdio.writefln("  -nolib     Ensures that the object files are not used to form");
449     std.stdio.writefln("              a library.");
450     std.stdio.writefln("              (Only needed if main/WinMain is not found in the source");
451     std.stdio.writefln("               files and you do NOT want a library.");
452     std.stdio.writefln("  -obj       This is the same as having both -nolib and -nolink switches.");
453     std.stdio.writefln("  -allobj    Ensures that all object files are added to a");
454     std.stdio.writefln("              library.");
455     std.stdio.writefln("              (Normally only those in the same directory are added.)");
456     std.stdio.writefln("  -cleanup   Ensures that all object files created during the run");
457     std.stdio.writefln("              are removed at the end of the run, plus other work files.");
458     std.stdio.writefln("  -clean     Same as -cleanup");
459   version(Windows) {
460     std.stdio.writefln("  -gui[:x.y] Forces a GUI application to be created. The optional");
461     std.stdio.writefln("              :x.y can be used to build an application for a ");
462     std.stdio.writefln("              specific version of Windows. eg. -gui:4.0");
463     std.stdio.writefln("              (Only needed if WinMain is not found in the source files");
464     std.stdio.writefln("               or if you wish to override the default Windows version)");
465     std.stdio.writefln("  -dll       Forces a DLL library to be created.");
466     std.stdio.writefln("              (Only needed if DllMain is not found in the source files.)");
467    }
468
469     std.stdio.writefln("  -explicit  Only compile files explicitly named on the command line.");
470     std.stdio.writefln("             All other files, such as imported ones, are not compiled.");
471     std.stdio.writefln("  -LIBOPT<opt> Allows you to pass <opt> to the librarian.");
472     std.stdio.writefln("  -SHLIBOPT<opt> Allows you to pass <opt> to the shared-librarian.");
473     std.stdio.writefln("  -LIBPATH=<pathlist> Used to add a semi-colon delimited list");
474     std.stdio.writefln("                of search paths for library files.");
475     std.stdio.writefln("  -MDF<path> Overrides the default Macro Definition File");
476     std.stdio.writefln("  -test      Does everything as normal except it displays the commands");
477     std.stdio.writefln("              instead of running them.");
478     std.stdio.writefln("  -RDF<path> Overrides the default Rule Definition File");
479     std.stdio.writefln("  -R=<Yes|No> Indicates whether to use a response file or command line");
480     std.stdio.writefln("              arguments with the compiler tools.");
481     std.stdio.writefln("               -R=Yes will cause a response to be used.");
482     std.stdio.writefln("               -R=No will cause command line arguments to be used.");
483     std.stdio.writefln("               -R will reverse the current usage.");
484     std.stdio.writefln("  -PP<path>  Add a path to the Source Search List");
485     std.stdio.writefln("  -usefinal=<Yes|No> Indicates whether to use any FINAL processes");
486     std.stdio.writefln("              defined in the configuration file.");
487     std.stdio.writefln("               -usefinal=Yes will cause the FINAL to be used. This is the default");
488     std.stdio.writefln("               -usefinal=No will prevent the FINAL from being used.");
489
490   version(UseResponseFile)
491     std.stdio.writefln("               ** The default is to use a response file");
492   else
493     std.stdio.writefln("               ** The default is to use command line arguments");
494
495     std.stdio.writefln("  -exec<param> If the link is successful, this will cause the");
496     std.stdio.writefln("               executable just created to run. You can give it ");
497     std.stdio.writefln("               run time parameters. Anything after the '-exec' will");
498     std.stdio.writefln("               placed in the program's command line. You will need");
499     std.stdio.writefln("               to quote any embedded spaces.");
500     std.stdio.writefln("  -od<path>  Nominate the directory where temporary (work) files");
501     std.stdio.writefln("             are to be created. By default they are created in");
502     std.stdio.writefln("             the same directory as the target file.");
503     std.stdio.writefln("  -X<module> Modules/Packages to ignore (eg. -Xmylib)");
504     std.stdio.writefln("  -M<module> Modules/Packages to notice (eg. -Mphobos)");
505     std.stdio.writefln("  -T<targetname> The name of the target file to create. Normally");
506     std.stdio.writefln("              the target name istaken from the first or only name");
507     std.stdio.writefln("              of the command line.");
508     std.stdio.writefln("  -help     Displays the full 'usage' help text. ");
509     std.stdio.writefln("  -h        Same as -help, displays the full 'usage' help text.");
510     std.stdio.writefln("  -?        Same as -help, displays the full 'usage' help text.");
511     std.stdio.writefln("  -silent   Avoids unnecessary messages being displayed.");
512     std.stdio.writefln("  -noautoimport Turns off the automatic addition of source paths");
513     std.stdio.writefln("              to the list of Import Roots.");
514     std.stdio.writefln("  -info      Displays the version and path of the Build application.");
515     std.stdio.writefln("  -nodef    Prevents a Module Definition File from being created.");
516     std.stdio.writefln("  -UMB=<Yes/No> If 'Yes' this forces the utility to expect");
517     std.stdio.writefln("            the object file to be created or residing in the current");
518     std.stdio.writefln("            directory.");
519     std.stdio.writefln("  -circular Allows circular dependencies to work on some compilers (namely GDC)");
520     version(Windows)
521     {
522     std.stdio.writefln("  -AutoWinLibs=<Yes/No> If 'No' this prevents the tool from");
523     std.stdio.writefln("              passing the standard set of Windows libraries");
524     std.stdio.writefln("              to the linker for GUI applications. 'Yes' is");
525     std.stdio.writefln("              is the default.");
526     }
527     std.stdio.writefln("  [...]      All other options, objectfiles and libraries are");
528     std.stdio.writefln("              passed to the compiler");
529     std.stdio.writefln("*Note, you can specify all or any command line value in a ");
530     std.stdio.writefln("   response file. Each value appears in its own line in the");
531     std.stdio.writefln(<