root/buildHelper.d

Revision 190:80660782bffe, 8.6 kB (checked in by korDen@korDen-pc, 2 months ago)

Fixed deprecated function call

Line 
1 // Written in The D Programming Language
2 /// Script to build DDMD
3 import std.file;
4 import std.getopt;
5 import std.path;
6 import std.process;
7 import std.stdio;
8 import std.string: replace, format;
9 import std.zip;
10
11 enum dmdVersionDefault = "2.040";
12 enum dmdArchiveBaseURL = "http://ftp.digitalmars.com/";
13 enum dmd = "dmd";
14
15 version(Windows)
16 {
17     enum scriptName = "build.bat";
18     enum osSubDir   = "windows";
19     enum configFile = "sc.ini";
20     enum execExt    = ".exe";
21     enum dmdLib = "dmd.lib";
22 }
23 else
24 {
25     version (OSX)
26         enum osSubDir   = "osx";
27
28     else version (linux)
29         enum osSubDir   = "linux";
30
31     enum scriptName = "./build.sh";
32     enum configFile = "dmd.conf";
33     enum execExt    = "";
34     enum dmdLib = "libdmd.a";
35 }
36
37 string dmdVersion;
38 string dmdPackage;
39 string dmdArchive;
40 string dmBase="";
41 bool shouldDownload;
42
43 void doCopy(string from, string to)
44 {
45     from = normFilePath(from);
46     to   = normFilePath(to);
47    
48     writefln(`copy "%s" "%s"`, from, to);
49     copy(from, to);
50 }
51
52 void doChDir(string dir)
53 {
54     dir = normDirPath(dir);
55    
56     writefln(`chdir "%s"`, dir);
57     chdir(dir);
58 }
59
60 int doSystem(string cmd)
61 {
62     writeln(cmd);
63     stdout.flush();
64     return system(cmd);
65 }
66
67 void copyRecurse(string from, string to)
68 {
69     from = normDirPath(from)[0..$-1];
70     to   = normDirPath(to)[0..$-1];
71     version(Windows)
72         doSystem(`xcopy "%s" "%s" /E /I /Y /Q`.format(from, to));
73     else
74         doSystem(`cp '%s' '%s' -r`.format(from, to));
75 }
76
77 void copyAndPatch(string from, string to, void delegate(ref string) patcher)
78 {
79     auto data = cast(string)read(from);
80     patcher(data);
81     std.file.write(to, data);
82 }
83
84 /// makePath("C:\foo\bar\dir") will create "C:\foo\bar\dir" if it doesn't already exist.
85 /// makePath("C:\foo\bar\dir\") will create "C:\foo\bar\dir" if it doesn't already exist.
86 void makePath(string dir)
87 {
88     dir = normDirPath(dir)[0..$-1];
89     if(!exists(dir))
90         mkdirRecurse(dir);
91 }
92
93 /// makePathTo("C:\foo\bar\file.txt") will create "C:\foo\bar\" if it doesn't already exist.
94 /// makePathTo("C:\foo\bar\dir\") will create "C:\foo\bar\" if it doesn't already exist.
95 void makePathTo(string file)
96 {
97     file = normFilePath(file);
98     auto dir = dirname(file);
99     makePath(dir);
100 }
101
102 /// Ensure trailing slash and OS-correct path separators
103 string normDirPath(string str)
104 {
105     str = normPathSep(str);
106     if(str.length > 0 && str[$-1] != sep[0])
107         str ~= sep;
108    
109     return str;
110 }
111
112 /// Ensure no trailing slash and OS-correct path separators
113 string normFilePath(string str)
114 {
115     str = normPathSep(str);
116     if(str.length > 0 && str[$-1] == sep[0])
117         str = str[0..$-1];
118    
119     return str;
120 }
121
122 /// Ensure OS-correct path separators
123 string normPathSep(string str)
124 {
125     version(Windows)
126         str = str.replace("/", "\\");
127     else
128         str = str.replace("\\", "/");
129    
130     return str;
131 }
132
133 unittest
134 {
135     version(Windows)
136     {
137         assert(normDirPath ("C:\\a/b\\c/d"  ) == "C:\\a\\b\\c\\d\\");
138         assert(normDirPath ("C:\\a/b\\c/d\\") == "C:\\a\\b\\c\\d\\");
139         assert(normDirPath ("C:\\a/b\\c/d/" ) == "C:\\a\\b\\c\\d\\");
140         assert(normFilePath("C:\\a/b\\c/d"  ) == "C:\\a\\b\\c\\d"  );
141         assert(normFilePath("C:\\a/b\\c/d\\") == "C:\\a\\b\\c\\d"  );
142     }
143     else
144     {
145         assert(normDirPath ("\\a/b\\c/d"  ) == "/a/b/c/d/");
146         assert(normDirPath ("\\a/b\\c/d\\") == "/a/b/c/d/");
147         assert(normDirPath ("\\a/b\\c/d/" ) == "/a/b/c/d/");
148         assert(normFilePath("\\a/b\\c/d"  ) == "/a/b/c/d" );
149         assert(normFilePath("\\a/b\\c/d\\") == "/a/b/c/d" );
150     }
151 }
152
153 bool initialSetup()
154 {
155     writeln("Running initial setup...");
156    
157     makePath("bin");
158    
159     // Download dmd zip
160     if(!exists(dmdArchive) && shouldDownload)
161         doSystem("wget "~dmdArchiveBaseURL~dmdArchive);
162
163     // Extract dmd zip
164     writeln("Extracting dmd archive...");
165     if(exists("dmd2"))
166         rmdirRecurse("dmd2");
167     auto zip = new ZipArchive(std.file.read(dmdArchive));
168     foreach(member; zip.directory)
169     {
170         makePathTo(member.name);
171         std.file.write(member.name, zip.expand(member));
172     }
173    
174     // Make mars2.c with 'main' hidden
175     doChDir("dmd2/src/dmd");
176     copyAndPatch("mars.c", "mars2.c", (ref string data) {
177         data = data.replace("int main(int argc, char *argv[])", "int HIDE_main(int argc, char *argv[])");
178     });
179    
180     copyAndPatch("util.c", "util.c", (ref string data) {
181         data = data.replace("void util_assert(char *file,int line)", "void HIDE_util_assert(char *file,int line)");
182     });
183
184     // Apply patch
185     doChDir("../../..");
186     doChDir("dmd2");
187     doSystem("patch -p1 --binary < " ~ normFilePath("../dmdpatch.patch"));
188    
189     // Setup makefile for dmd.lib
190     doChDir("..");
191     doChDir("dmd2/src/dmd");
192     version(Windows)
193         enum makefile = "win32.mak";
194     else
195     {
196         version (linux)
197             enum makefile = "linux_lib.mak";
198
199         else version (OSX)
200             enum makefile = "osx_lib.mak";
201
202         doCopy("../../../"~makefile, makefile);
203     }
204
205     version(Windows)
206     copyAndPatch(makefile, makefile, (ref string data) {
207         if(dmBase == "")
208         {
209             data = data.replace("\nCC=$(SCROOT)\\bin\\dmc", "\nCC=dmc");
210             data = data.replace("\nLIB=$(SCROOT)\\bin\\lib", "\nLIB=lib");
211         }
212         else
213             data = data.replace("\nD=", "\nD="~dmBase);
214     });
215
216    
217     // Build dmd.lib
218     version(Windows)
219         doSystem("make deblib -f"~makefile);
220     else
221         doSystem("make -f"~makefile);
222     doCopy(dmdLib, "../../../" ~ dmdLib);
223    
224     // Copy and patch config file
225     doChDir("../../..");
226     copyAndPatch(
227         normFilePath("dmd2/"~osSubDir~"/bin/"~configFile),
228         normFilePath("bin/"~configFile),
229         (ref string data) {
230             data = data.replace(normDirPath("../.."), normDirPath("../dmd2"));
231             data = data.replace(normDirPath("../lib")[0 .. $ - 1], normDirPath("../dmd2/"~osSubDir~"/lib")[0 .. $ - 1]);
232         }
233     );
234
235     // Copy linker
236     version (Windows)
237         doCopy("dmd2/"~osSubDir~"/bin/link"~execExt, "bin/link"~execExt);
238
239     return true;
240 }
241
242 int main(string[] args)
243 {
244     endOfOptions = "";
245     bool help;
246     bool shouldSetup;
247     bool debugOnly;
248     bool releaseOnly;
249     dmdVersion = dmdVersionDefault;
250     getopt(
251         args,
252         std.getopt.config.caseSensitive,
253         "setup",      &shouldSetup,
254         "debug|d",    &debugOnly,
255         "release|r",  &releaseOnly,
256         "ver",        &dmdVersion,
257         "download",   &shouldDownload,
258         "dmbase",     &dmBase,
259         "help|h|H|?", &help
260     );
261    
262     dmdPackage = "dmd."~dmdVersion;
263     dmdArchive = dmdPackage~".zip";
264
265     auto helpMsg =
266 `This script will compile DDMD
267
268 Note that this script must be run from the main DDMD directory.
269
270 Also, make sure you have GNU patch installed and current versions
271 of DMC and DMD (D2) on the PATH. (DMC is only needed on Windows.)
272
273 Usage:
274     `~scriptName~` [options...]
275     
276     --help,-h,-H,-?  Display this help message
277     --debug,-d       Only build debug version
278     --release,-r     Only build release version
279     --ver={ver}      Base DDMD off specific DMD version (default: `~dmdVersionDefault~`)
280     --setup          Run initial setup
281     --download       If running initial setup and the dmd zip doesn't exist,
282                      use wget to download it
283     --dmbase={path}  Path to directory containing 'dm' for building dmd.lib
284                      (Optional if --setup is used, otherwise ignored)
285 `;
286
287     // Assume the user meant they wanted both.
288     if(debugOnly && releaseOnly)
289     {
290         debugOnly = releaseOnly = false;
291     }
292    
293     if(
294         help ||
295         ( shouldSetup && !exists(dmdArchive) && !shouldDownload    ) ||
296         ( shouldSetup && exists(dmdArchive) && !isFile(dmdArchive) )
297     )
298     {
299         write(helpMsg);
300         return 1;
301     }
302    
303     if( !shouldSetup && (!exists(dmdLib) || !isFile(dmdLib)) )
304     {
305         auto needSetupMsg =
306 `'`~dmdLib~`' has not been built so you need to run the initial setup:
307
308 If you have GNU wget installed, just run:
309   `~scriptName~` --setup --download
310
311 If you don't have wget, download a copy of `~dmdArchive~` to this
312 directory. It can be obtained from:
313   `~dmdArchiveBaseURL~dmdArchive~`
314 Then run:
315   `~scriptName~` --setup
316
317 For a full list of options, run:
318   `~scriptName~` --help
319 `;
320
321         write(needSetupMsg);
322         return 1;
323     }
324
325     if(shouldSetup)
326     {
327         if(!initialSetup())
328             return 1;
329     }
330    
331     int ret=0;
332     version(Windows)
333     {
334         system("cls");
335         if(ret == 0) ret = doSystem(r"dmc.exe bridge\bridge.cpp -c");
336         if(!releaseOnly) if(ret == 0) ret = doSystem(dmd ~ r" -debug -g @commands.txt");
337         if(!debugOnly)   if(ret == 0) ret = doSystem(dmd ~ r" -release -O -inline @commands.txt");
338     }
339     else
340     {
341         version (linux)
342             auto commands = "@commands.linux.txt";
343
344         else version (OSX)
345             auto commands = "@commands.osx.txt";
346
347         if(ret == 0) ret = doSystem("g++ -m32 -c bridge/bridge.cpp -obridge.o");
348         if(!releaseOnly) if(ret == 0) ret = doSystem(dmd ~ " -debug -gc " ~ commands);
349         if(!debugOnly)   if(ret == 0) ret = doSystem(dmd ~ " -release -O -inline " ~ commands);
350     }
351    
352     return ret;
353 }
Note: See TracBrowser for help on using the browser.