1 /*
2  * DSFML - The Simple and Fast Multimedia Library for D
3  *
4  * Copyright (c) 2013 - 2017 Jeremy DeHaan (dehaan.jeremiah@gmail.com)
5  *
6  * This software is provided 'as-is', without any express or implied warranty.
7  * In no event will the authors be held liable for any damages arising from the
8  * use of this software.
9  *
10  * Permission is granted to anyone to use this software for any purpose,
11  * including commercial applications, and to alter it and redistribute it
12  * freely, subject to the following restrictions:
13  *
14  * 1. The origin of this software must not be misrepresented; you must not claim
15  * that you wrote the original software. If you use this software in a product,
16  * an acknowledgment in the product documentation would be appreciated but is
17  * not required.
18  *
19  * 2. Altered source versions must be plainly marked as such, and must not be
20  * misrepresented as being the original software.
21  *
22  * 3. This notice may not be removed or altered from any source distribution
23  */
24 
25 module build;
26 
27 import std.stdio;
28 import std.file;
29 import std.process;
30 import std.algorithm;
31 import std.array;
32 import std.getopt;
33 
34 static if (__VERSION__ < 2068L)
35 {
36 	static assert(0, "Please upgrade your compiler to v2.068 or later");
37 }
38 
39 version(DigitalMars)
40 {
41     string compiler = "dmd ";
42 }
43 else version(GNU)
44 {
45     string compiler = "gdc ";
46 }
47 else version(LDC)
48 {
49     string compiler = "ldc2 ";
50 }
51 else
52 {
53     static assert(false, "Unknown or unsupported compiler.");
54 }
55 
56 //build settings
57 string prefix;
58 string extension;
59 string libCompilerSwitches;
60 string docCompilerSwitches;
61 string interfaceCompilerSwitches;
62 string unittestCompilerSwitches;
63 bool buildStop;
64 
65 
66 //switch settings
67 bool buildingLibs;
68 bool buildingInterfaceFiles;
69 bool buildingDoc;
70 bool buildingWebsiteDocs;
71 bool showingHelp;
72 bool force32Build;
73 bool force64Build;
74 
75 bool buildingUnittests;
76 string unittestLibraryLocation;
77 
78 bool buildingAll;
79 
80 bool hasUnrecognizedSwitch;
81 string unrecognizedSwitch;
82 
83 string makefileType;
84 string makefileProgram;
85 string objExt;
86 string singleFileSwitches;
87 string archSwitch;
88 
89 
90 //Possibly use this to completely automate the process for dmd/ldc users on windows
91 //environment.get("VCINSTALLDIR");
92 //will need to find an alternative for gdc users on windows in regards to mingw
93 
94 version(Windows)
95 {
96 }
97 else version(linux)
98 {
99 }
100 else version(OSX)
101 {
102 }
103 //FreeBSD Support coming soon!
104 else
105 {
106     static assert(false, "DSFML is only supported on OSX, Windows, and Linux.");
107 }
108 
109 
110 string[5] modules = ["system", "audio", "network", "window", "graphics"];
111 string selectedModule;
112 
113 //lists of d files and c++ object files
114 string[][string] fileList;
115 string[][string] objectList;
116 
117 
118 //checks for any inconsistencies with the passed switchs.
119 //Returns true if everything is ok and false if an error was found.
120 bool checkSwitchErrors()
121 {
122     //can't force both
123     if(force32Build && force64Build)
124     {
125         writeln("Can't use -m32 and -m64 together");
126         return false;
127     }
128 
129     //if other Switchs are used with -all
130     if(buildingAll)
131     {
132         if(buildingLibs || buildingDoc ||
133            buildingInterfaceFiles || buildingUnittests)
134         {
135             writeln("Can't use -all with any other build switches ",
136                     "(-lib, -doc, -import, -unittest)");
137 
138             return false;
139         }
140     }
141 
142     return true;
143 }
144 
145 //initialize all build settings
146 void initialize()
147 {
148     //populate file lists
149     fileList["system"] = ["clock", "config", "err", "inputstream", "lock",
150                           "mutex", "package", "sleep", "string", "thread",
151                           "vector2", "vector3"];
152 
153     fileList["audio"] = ["listener", "music", "package", "sound",
154                          "soundbuffer", "soundbufferrecorder",
155                          "inputsoundfile", "outputsoundfile",
156                          "soundrecorder", "soundsource", "soundstream"];
157 
158     fileList["network"] = ["ftp", "http", "ipaddress", "package",
159                            "packet", "socket", "socketselector",
160                            "tcplistener", "tcpsocket", "udpsocket"];
161 
162     fileList["window"] = ["context", "contextsettings", "event", "joystick",
163                           "keyboard", "mouse", "sensor", "touch", "package",
164                           "videomode", "window", "windowhandle"];
165 
166     fileList["graphics"] = ["blendmode", "circleshape", "color", "convexshape",
167                             "drawable", "font", "glsl", "glyph", "image",
168                             "package", "primitivetype", "rect",
169                             "rectangleshape", "renderstates", "rendertarget",
170                             "rendertexture", "renderwindow", "shader", "shape",
171                             "sprite", "text", "texture", "transform",
172                             "transformable", "vertex", "vertexarray", "view"];
173 
174     archSwitch = "";
175 
176 
177     version(DigitalMars)
178     {
179         initializeDMD();
180     }
181     else version(GNU)
182     {
183         initializeGDC();
184     }
185     else
186     {
187         initializeLDC();
188     }
189 
190     if(force32Build)
191     {
192         version(Windows)
193         {
194             version(DigitalMars)
195             {
196                 archSwitch = "-m32mscoff";
197             }
198         }
199         else
200         {
201             archSwitch = "-m32";
202         }
203     }
204 
205     if(force64Build)
206     {
207         archSwitch = "-m64";
208     }
209 
210     writeln();
211 }
212 
213 void initializeDMD()
214 {
215 
216     string linkToSFMLLibs = "";
217 
218     version (Windows)
219     {
220         writeln("Building for Windows with dmd");
221         prefix = "";
222         extension = ".lib";
223         objExt = ".obj";
224 
225         //Default to 64 bit on windows because why wouldn't we?
226         if(!force64Build || !force32Build)
227         {
228             archSwitch = " -m64";
229         }
230 
231         makefileProgram = "nmake";
232         makefileType = `"NMake Makefiles"`;
233 
234         linkToSFMLLibs = "-L/LIBPATH:lib -L/LIBPATH:SFML\\lib "~
235         "-L/LIBPATH:SFML\\extlibs\\libs-msvc-universal\\x64 ";
236 
237         linkToSFMLLibs ~=
238         "dsfmlc-graphics.lib dsfmlc-window.lib dsfmlc-audio.lib " ~
239         "dsfmlc-network.lib dsfmlc-system.lib ";
240 
241         linkToSFMLLibs~=
242         "sfml-graphics.lib sfml-window.lib sfml-audio.lib "~
243         "sfml-network.lib sfml-system.lib ";
244 
245         /*linkToSFMLLibs~=
246         "opengl32.lib gdi32.lib flac.lib freetype.lib jpeg.lib ogg.lib "~
247         "openal32.lib vorbis.lib vorbisenc.lib vorbisfile.lib ws2_32.lib "~
248         "winmm.lib user32.lib ";
249         */
250     }
251     else version(linux)
252     {
253         writeln("Building for Linux with dmd");
254         prefix = "lib";
255         extension = ".a";
256         objExt = ".o";
257 
258         makefileProgram = "make";
259         makefileType = `"Unix Makefiles"`;
260 
261 
262         linkToSFMLLibs = "-L-Llib -L-LSFML/lib ";
263 
264         linkToSFMLLibs ~=
265         "-L-ldsfmlc-graphics -L-ldsfmlc-window -L-ldsfmlc-audio " ~
266         "-L-ldsfmlc-network -L-ldsfmlc-system ";
267 
268         linkToSFMLLibs ~=
269         "-L-lsfml-graphics -L-lsfml-window -L-lsfml-audio "~
270         "-L-lsfml-network -L-lsfml-system ";
271 
272         linkToSFMLLibs ~= "-L-lstdc++ ";
273 
274         //linkToSFMLLibs ~=
275         //"-L-lstdc++ -L-lFLAC -L-logg -L-lvorbisfile -L-lvorbisenc -L-lvorbis "~
276         //"-L-lopenal -L-lX11 -L-ludev -L-lGL -L-lXrandr -L-ljpeg -L-lfreetype";
277     }
278     else
279     {
280         writeln("Building for OSX with dmd");
281         prefix = "lib";
282         extension = ".a";
283         objExt = ".o";
284 
285         makefileProgram = "make";
286         makefileType = `"Unix Makefiles"`;
287 
288 
289         linkToSFMLLibs = "-L-Llib -L-LSFML/lib ";
290 
291         linkToSFMLLibs ~=
292         "-L-ldsfmlc-graphics -L-ldsfmlc-window -L-ldsfmlc-audio " ~
293         "-L-ldsfmlc-network -L-ldsfmlc-system ";
294 
295         linkToSFMLLibs ~=
296         "-L-lsfml-graphics -L-lsfml-window -L-lsfml-audio "~
297         "-L-lsfml-network -L-lsfml-system ";
298 
299         linkToSFMLLibs ~= "-L-lstdc++ -L-rpath -L. ";
300 
301         //linkToSFMLLibs ~=
302         //"-L-lstdc++ -L-lFLAC -L-logg -L-lvorbisfile -L-lvorbisenc -L-lvorbis "~
303         //"-L-lopenal -L-lX11 -L-ludev -L-lGL -L-lXrandr -L-ljpeg -L-lfreetype";
304     }
305 
306     singleFileSwitches = archSwitch ~ " -c -O -release -inline -Isrc";
307     libCompilerSwitches = archSwitch ~ " -lib  -Isrc";
308     docCompilerSwitches = " -c -o- -op -D -Dd../../doc -I../../src";
309     //interfaceCompilerSwitches = " -c -o- -op -H -Hd"~quoteString(interfaceDirectory);
310 
311     unittestCompilerSwitches =
312     "-main -unittest -version=DSFML_Unittest_System " ~
313     "-version=DSFML_Unittest_Window -version=DSFML_Unittest_Graphics " ~
314     "-version=DSFML_Unittest_Audio -version=DSFML_Unittest_Network "~
315     linkToSFMLLibs;
316     //unittestCompilerSwitches ="-main -unittest -version=DSFML_Unittest_Network "~linkToSFMLLibs;
317     //libCompilerSwitches = "-lib -O -release -inline -I"~quoteString(impDirectory);
318     //interfaceCompilerSwitches = " -c -o- -op -H -Hd"~quoteString(interfaceDirectory);
319 }
320 
321 void initializeGDC()
322 {
323     //need to set up for windows and macOS later
324 
325     string linkToSFMLLibs = "";
326 
327     version(linux)
328     {
329         writeln("Building for Linux with gdc");
330         prefix = "lib";
331         extension = ".a";
332         objExt = ".o";
333 
334         makefileProgram = "make";
335         makefileType = `"Unix Makefiles"`;
336 
337         linkToSFMLLibs = "-Llib -LSFML/lib ";
338 
339         linkToSFMLLibs ~=
340         "-ldsfmlc-graphics -ldsfmlc-window -ldsfmlc-audio " ~
341         "-ldsfmlc-network -ldsfmlc-system ";
342 
343         linkToSFMLLibs ~=
344         "-lsfml-graphics -lsfml-window -lsfml-audio "~
345         "-lsfml-network -lsfml-system ";
346 
347         linkToSFMLLibs ~= "-lstdc++ ";
348 
349         //linkToSFMLLibs ~=
350         //"-lstdc++ -lFLAC -logg -lvorbisfile -lvorbisenc -lvorbis "~
351         //"-lopenal -lX11 -ludev -lGL -lXrandr -ljpeg -lfreetype";
352     }
353 
354 
355     singleFileSwitches = archSwitch ~ " -c -O3 -frelease -Isrc";
356     libCompilerSwitches = archSwitch ~ " -Isrc";
357     docCompilerSwitches = " -c -fdoc -I../../src";
358 
359     unittestCompilerSwitches =
360     "-funittest -fversion=DSFML_Unittest_System " ~
361     "-fversion=DSFML_Unittest_Window -fversion=DSFML_Unittest_Graphics " ~
362     "-fversion=DSFML_Unittest_Audio -fversion=DSFML_Unittest_Network "~
363     linkToSFMLLibs;
364 
365 }
366 
367 void initializeLDC()
368 {
369     string linkToSFMLLibs = "";
370 
371     //fix this before testing on windows
372     version(Windows)
373     {
374         writeln("Building for Windows with ldc");
375         prefix = "";
376         extension = ".lib";
377         objExt = ".obj";
378 
379         //Default to 64 bit on windows because why wouldn't we?
380         if(!force64Build || !force32Build)
381         {
382             archSwitch = " -m64";
383         }
384 
385         makefileProgram = "nmake";
386         makefileType = `"NMake Makefiles"`;
387 
388          linkToSFMLLibs = "-L=/LIBPATH:lib -L=/LIBPATH:SFML\\lib "~
389         "-L=/LIBPATH:SFML\\extlibs\\libs-msvc-universal\\x64 ";
390 
391         linkToSFMLLibs ~=
392         "dsfmlc-graphics.lib dsfmlc-window.lib dsfmlc-audio.lib " ~
393         "dsfmlc-network.lib dsfmlc-system.lib ";
394 
395         linkToSFMLLibs~=
396         "sfml-graphics.lib sfml-window.lib sfml-audio.lib "~
397         "sfml-network.lib sfml-system.lib ";
398 
399         /*linkToSFMLLibs~=
400         "opengl32.lib gdi32.lib flac.lib freetype.lib jpeg.lib ogg.lib "~
401         "openal32.lib vorbis.lib vorbisenc.lib vorbisfile.lib ws2_32.lib "~
402         "winmm.lib user32.lib ";
403         */
404     }
405     else version(linux)
406     {
407         writeln("Building for Linux with ldc");
408         prefix = "lib";
409         extension = ".a";
410         objExt = ".o";
411 
412         makefileProgram = "make";
413         makefileType = `"Unix Makefiles"`;
414 
415 
416         linkToSFMLLibs = "-L=-Llib -L=-LSFML/lib ";
417 
418         linkToSFMLLibs ~=
419         "-L=-ldsfmlc-graphics -L=-ldsfmlc-window -L=-ldsfmlc-audio " ~
420         "-L=-ldsfmlc-network -L=-ldsfmlc-system ";
421 
422         linkToSFMLLibs ~=
423         "-L=-lsfml-graphics -L=-lsfml-window -L=-lsfml-audio "~
424         "-L=-lsfml-network -L=-lsfml-system ";
425 
426         linkToSFMLLibs ~= "-L=-lstdc++ ";
427 
428         //linkToSFMLLibs ~=
429         //"-L=-lstdc++ -L=-lFLAC -L=-logg -L=-lvorbisfile -L=-lvorbisenc "~
430         //"-L=-lvorbis -L=-lopenal -L=-lX11 -L=-ludev -L=-lGL -L=-lXrandr "~
431         //"-L=-ljpeg -L=-lfreetype";
432     }
433     else
434     {
435         writeln("Building for OSX with ldc");
436         prefix = "lib";
437         extension = ".a";
438         objExt = ".o";
439 
440         makefileProgram = "make";
441         makefileType = `"Unix Makefiles"`;
442 
443         linkToSFMLLibs = "-L=-Llib -L=-LSFML/lib ";
444 
445         linkToSFMLLibs ~=
446         "-L=-ldsfmlc-graphics -L=-ldsfmlc-window -L=-ldsfmlc-audio " ~
447         "-L=-ldsfmlc-network -L=-ldsfmlc-system ";
448 
449         linkToSFMLLibs ~=
450         "-L=-lsfml-graphics -L=-lsfml-window -L=-lsfml-audio "~
451         "-L=-lsfml-network -L=-lsfml-system ";
452 
453         linkToSFMLLibs ~= "-L=-lstdc++ -L=-rpath -L=. ";
454     }
455 
456     singleFileSwitches = archSwitch ~ " -c -O -release -oq -I=src";
457     libCompilerSwitches = archSwitch ~ " -lib -I=src";
458     docCompilerSwitches = " -c -o- -op -D -Dd=../../doc -I=../../src";
459 
460     unittestCompilerSwitches =
461     "-main -unittest -d-version=DSFML_Unittest_System " ~
462     "-d-version=DSFML_Unittest_Window -d-version=DSFML_Unittest_Graphics " ~
463     "-d-version=DSFML_Unittest_Audio -d-version=DSFML_Unittest_Network "~
464     linkToSFMLLibs;
465 }
466 
467 //build the static libraries. Returns true on successful build, false on unsuccessful build
468 bool buildLibs()
469 {
470     import std.ascii; //toUpper
471 
472     if(!exists("lib/"))
473     {
474         mkdir("lib/");
475     }
476 
477 
478 
479     if(!exists("CMakeCache.txt"))
480     {
481         auto pid = spawnShell("cmake -G"~makefileType~" .");
482         if(wait(pid) != 0)
483         {
484             //oh shit, what up?
485             return false;
486         }
487     }
488 
489     //always try to rebuild c++ files. They will be skipped if nothing to do.
490     auto pid = spawnProcess([makefileProgram]);
491     if(wait(pid) != 0)
492     {
493         //oh shit, what up?
494         return false;
495     }
496 
497     writeln();
498 
499     //go trhough each module directory, build d source files if need be,
500     //populate a list of all object files (both d and cpp),
501     //and build a static lib.
502     foreach(theModule;modules)
503     {
504         if(selectedModule != "" && theModule != selectedModule)
505         {
506             continue;
507         }
508 
509         //+1 for lib file
510         size_t numberOfFiles = fileList[theModule].length + 1;
511         int currentFile = 1;
512         string files = "";
513         foreach (string name; fileList[theModule])
514         {
515             string objectFile = "src/dsfml/" ~theModule~"/"~name~objExt;
516             string dFile = "src/dsfml/" ~theModule~"/"~name~".d";
517 
518             version(DigitalMars)
519             {
520                 string buildCommand = compiler~dFile~singleFileSwitches~
521                                   " -of" ~objectFile;
522             }
523             else version(GNU)
524             {
525                 string buildCommand = compiler~dFile~singleFileSwitches~
526                                   " -o" ~objectFile;
527             }
528             else version(LDC)
529             {
530                 string buildCommand = compiler~dFile~singleFileSwitches~
531                                   " -of=" ~objectFile;
532             }
533 
534 
535             if(needToBuild(objectFile, dFile))
536             {
537                 progressOutput(currentFile, numberOfFiles, dFile);
538 
539                 auto status = executeShell(buildCommand);
540                 if(status.status !=0)
541                 {
542                     writeln(status.output);
543                     return false;
544                 }
545             }
546 
547             files~= objectFile ~ " ";
548             currentFile++;
549         }
550 
551 
552         string buildCommand = compiler ~ files;
553 
554         version(DigitalMars)
555         {
556             //adding the library to dmd doesn't work on OSX
557             version(OSX)
558             {
559                 buildCommand = "cd "~"src/dsfml/"~theModule~"/ && "~
560                 "ar -x ../../../lib/"~prefix~"dsfmlc-"~theModule~extension ~ " && "~
561                 " ar rcs ../../../lib/libdsfml-"~theModule~extension~" *"~objExt~"&& "~
562                 "cd ../../../";
563             }
564             else
565             {
566                 //build the static libs directly
567                 buildCommand ~= " -lib -L-Llib/ -L-l"~"dsfmlc-"~theModule~extension ~
568                 " -oflib/"~prefix~"dsfml-"~theModule~extension~archSwitch;
569             }
570         }
571         else version(GNU)
572         {
573             writeln("building the library");
574 
575             //we want to use ar here, so we'll completely reset the build command
576 
577             buildCommand = "cd "~"src/dsfml/"~theModule~"/ && "~
578             "ar -x ../../../lib/"~prefix~"dsfmlc-"~theModule~extension ~ " && "~
579             " ar rcs ../../../lib/libdsfml-"~theModule~extension~" *"~objExt~"&& "~
580             "cd ../../../";
581 
582         }
583         else
584         {
585             version(OSX)
586             {
587                 buildCommand = "cd "~"src/dsfml/"~theModule~"/ && "~
588                 "ar -x ../../../lib/"~prefix~"dsfmlc-"~theModule~extension ~ " && "~
589                 " ar rcs ../../../lib/libdsfml-"~theModule~extension~" *"~objExt~"&& "~
590                 "cd ../../../";
591             }
592             else
593             {
594                 buildCommand ~= " -lib lib/"~prefix~"dsfmlc-"~theModule~extension ~
595                 " -of=lib/"~prefix~"dsfml-"~theModule~extension~archSwitch;
596             }
597             //buildCommand ~= " -of="~quoteString(libDirectory~prefix~"dsfml-"~theModule~extension);
598         }
599 
600 
601         //always rebuilds the lib in case the cpp files were re-built
602         auto status = executeShell(buildCommand);
603 
604         //writeln(buildCommand);
605 
606         if(status.status !=0)
607         {
608             writeln("Something happened!");
609             writeln(status.output);
610             return false;
611         }
612 
613         writeln("[100%] Built "~prefix~"dsfml-" ~ theModule~extension);
614     }
615 
616     return true;
617 }
618 
619 bool buildUnittests()
620 {
621 
622     version(Windows)
623     {
624         //technically, we also need .lib files because Windows is stupid, but
625         //the build script will only look for the .dll's.
626         string dynamicExtension = "-2.dll";
627     }
628     else version(linux)
629     {
630         string dynamicExtension = ".so";
631     }
632     else
633     {
634         string dynamicExtension = ".dylib";
635     }
636 
637     import std.ascii; //toUpper
638     //string[2] testModules = ["system", "network"];
639     //check to make sure ALL SFML libs were built
640     foreach(theModule; modules)
641     {
642         if(!exists("SFML/lib/"~prefix~"sfml-"~theModule~dynamicExtension))
643         {
644             writeln("SFML/lib/"~prefix~"sfml-"~theModule~dynamicExtension,
645                     " not found.");
646             writeln("Building unit tests requires SFML libs in ",
647                     "dsfml/SFML/lib/ directory.");
648             return false;
649         }
650     }
651 
652     if(!exists("CMakeCache.txt"))
653     {
654         auto pid = spawnShell("cmake -G"~makefileType~" .");
655         if(wait(pid) != 0)
656         {
657             //oh shit, what up?
658             return false;
659         }
660     }
661 
662     //always try to rebuild c++ files. They will be skipped if nothing to do.
663     auto pid = spawnProcess([makefileProgram]);
664     if(wait(pid) != 0)
665     {
666         //oh shit, what up?
667         return false;
668     }
669 
670     string files = "";
671 
672     foreach(theModule;modules)
673     {
674         foreach(string name; fileList[theModule])
675         {
676             files~= "src/dsfml/" ~theModule~"/"~name~".d ";
677         }
678     }
679 
680     string buildCommand = compiler;
681 
682         version(DigitalMars)
683         {
684             buildCommand ~= files~" "~unittestCompilerSwitches~archSwitch;
685             buildCommand ~= " -ofunittest/unittest";
686         }
687         else version(GNU)
688         {
689             std.file.write("main.d", "void main(){}");
690 
691             buildCommand ~= "main.d "~files~unittestCompilerSwitches~archSwitch~
692             " -ounittest/unittest -Wl,--verbose";
693         }
694         else
695         {
696             buildCommand ~= unittestCompilerSwitches~archSwitch~" -oq "~files;
697             buildCommand ~= "-of=unittest/unittest";
698             //buildCommand ~= " -of="~quoteString(libDirectory~prefix~"dsfml-"~theModule~extension);
699         }
700 
701         version(Windows)
702         {
703             buildCommand ~= ".exe";
704         }
705 
706         writeln(buildCommand);
707 
708 
709         //std.file.write("cmdFile")
710         //remove(deleteme);
711 
712 
713 
714         auto status = executeShell(buildCommand);
715 
716         version(GNU)
717         {
718             std.file.remove("main.d");
719         }
720 
721         if(status.status !=0)
722         {
723             writeln(status.output);
724             return false;
725         }
726 
727         return true;
728 }
729 
730 bool buildDocumentation()
731 {
732     if(!exists("doc/"))
733     {
734         mkdir("doc/");
735     }
736 
737     chdir("src/dsfml/");
738 
739     string docExtension;
740     string ddoc;
741     if(buildingWebsiteDocs)
742     {
743         docExtension = ".php";
744 
745         version(GNU)
746             ddoc = "../../doc/website_documentation.ddoc";
747         else
748             ddoc = " ../../doc/website_documentation.ddoc";
749     }
750     else
751     {
752         docExtension = ".html";
753         version(GNU)
754             ddoc = "../../doc/default_ddoc_theme.ddoc";
755         else
756             ddoc = " ../../doc/local_documentation.ddoc";
757     }
758 
759     foreach(theModule;modules)
760     {
761         if(selectedModule != "" && theModule != selectedModule)
762         {
763             continue;
764         }
765 
766         // skipping package.d
767         size_t numberOfFiles = fileList[theModule].length -1 ;
768         int currentFile = 1;
769         foreach (string name; fileList[theModule])
770         {
771             if (name == "package")
772                 continue;
773             string docFile = "../../doc/"~theModule~"/"~name~docExtension;
774             string outputFile = name~docExtension;
775             string dFile = theModule~"/"~name~".d";
776 
777 
778             string buildCommand;
779 
780             version(GNU)
781             {
782                 buildCommand = compiler~dFile~" -fdoc-inc="~ddoc~
783                 " -fdoc-dir=../../doc/dsfml/"~theModule~
784                 docCompilerSwitches~" -o obj.o";
785             }
786             else
787                 buildCommand = compiler~dFile~ddoc~docCompilerSwitches;
788 
789             if(needToBuild(docFile, dFile))
790             {
791                 progressOutput(currentFile, numberOfFiles, outputFile);
792 
793                 auto status = executeShell(buildCommand);
794                 if(status.status !=0)
795                 {
796                     writeln(status.output);
797                     return false;
798                 }
799 
800                 if(docExtension!=".html")
801                     rename("../../doc/"~theModule~"/"~name~".html",
802                            "../../doc/"~theModule~"/"~name~docExtension);
803             }
804 
805             currentFile++;
806         }
807     }
808 
809     version(GNU)
810         core.stdc.stdio.remove("obj.o");
811 
812     chdir("../..");
813 
814     return true;
815 }
816 
817 /**
818  * Display the progress as a percentage given the current file is next.
819  *
820  * Display example:
821  * [ 20%] Building dsfml/src/system/clock.d
822  */
823 void progressOutput(int current, size_t total, string file)
824 {
825     size_t percentage = (current*100)/total;
826 
827     writefln("[%3u%%] Building %s", percentage, file);
828 }
829 
830 /**
831  * Checks the timestamps on the object file and its associated source file.
832  *
833  * If the source file has been more recently updated than the object file was
834  * built, or if the object file doesn't yet exist, this will return true.
835  */
836 bool needToBuild(string objLocation, string srcLocation)
837 {
838     import std.file: exists, timeStamp = timeLastModified;
839 
840     return exists(objLocation)?timeStamp(objLocation) < timeStamp(srcLocation):
841                                true;
842 }
843 
844 string singleSplitter(string haystack, char needle, ref int startPos)
845 {
846     int i;
847     for(i = startPos; i < haystack.length; i++)
848     {
849         if(haystack[i] == needle)
850             break;
851     }
852 
853     if(i >= haystack.length)
854         return null;
855     auto ret = haystack[startPos .. i];
856     startPos = i+1;
857     return ret;
858 }
859 
860 string pathToMSVCToolChain()
861 {
862     string dmdPath;
863     auto paths = environment.get("PATH");
864     int start = 0;
865     auto path = singleSplitter(paths, ';', start);
866 
867     while(path !is null)
868     {
869 
870         if(canFind(path, "dmd2"))
871         {
872             dmdPath = path;
873         }
874         path = singleSplitter(paths, ';', start);
875     }
876 
877     File scFile = File(dmdPath~"\\sc.ini", "r");
878     char[] buf;
879 
880     while(!canFind(buf, "VCINSTALLDIR="))
881     {
882         scFile.readln(buf);
883         //writeln(buf);
884     }
885 
886     //$-1 because the buffer ends with \n
887     return buf[13 ..$-1].idup;
888 
889 }
890 
891 int main(string[] args)
892 {
893 
894     GetoptResult optInfo;
895     try
896     {
897         optInfo = getopt(args,
898         "lib", "Build static libraries.", &buildingLibs,
899         "m32", "Force 32 bit building.", &force32Build,
900         "m64", "Force 64 bit building.", &force64Build,
901         "unittest", "Build DSFML unit test executable.", &buildingUnittests,
902         "doc", "Build DSFML documentation.", &buildingDoc,
903         "webdoc", "Build the DSFML website documentation.", &buildingWebsiteDocs
904         );
905     }
906     catch(GetOptException e)
907     {
908         writeln(e.msg);
909         return -1;
910     }
911 
912     if(optInfo.helpWanted)
913     {
914         defaultGetoptPrinter("Switch Information\n"
915         ~"Default (no switches passed) will be to build static libraries with the compiler that built this.",
916         optInfo.options);
917         return 0;
918     }
919 
920     //default to building libs
921     if(!buildingLibs && !buildingDoc && !buildingInterfaceFiles &&
922        !buildingWebsiteDocs && !buildingUnittests && !buildingAll)
923     {
924         buildingLibs = true;
925     }
926 
927     /*
928         writeln("lib ", buildingLibs);
929         writeln("doc ", buildingDoc);
930         writeln("import ",buildingInterfaceFiles);
931         writeln("unittest ", buildingUnittests);
932         writeln("all ", buildingAll);
933         writeln("sharedDir ", unittestLibraryLocation);
934         writeln("m32 ", force32Build);
935         writeln("m64 ", force64Build);
936         writeln("dmd ", forceDMD);
937         writeln("gdc ", forceGDC);
938         writeln("ldc ", foorceLDC);
939     */
940 
941     if(!checkSwitchErrors())
942     {
943         return -1;
944     }
945 
946     writeln();
947     initialize();
948     if(buildingLibs)
949     {
950         if(!buildLibs())
951             return -1;
952     }
953     if(buildingUnittests)
954     {
955         if(!buildUnittests())
956             return -1;
957     }
958     if(buildingDoc || buildingWebsiteDocs)
959     {
960         if(!buildDocumentation())
961             return -1;
962     }
963 
964     return 0;
965 }