1 module build; 2 3 import std.stdio; 4 import std.file; 5 import std.process; 6 import std.algorithm; 7 import std.array; 8 9 10 version(DigitalMars) 11 { 12 bool isDMD = true; 13 bool isGDC = false; 14 bool isLDC = false; 15 string compiler = "dmd "; 16 } 17 else version(GNU) 18 { 19 bool isDMD = false; 20 bool isGDC = true; 21 bool isLDC = false; 22 string compiler = "gdc "; 23 } 24 else version(LDC) 25 { 26 bool isDMD = false; 27 bool isGDC = false; 28 bool isLDC = true; 29 string compiler = "ldc2 "; 30 } 31 else 32 { 33 static assert(false, "Unknown or unsupported compiler."); 34 } 35 36 //location settings 37 string currentDirectory; 38 string impDirectory; 39 string libDirectory; 40 string interfaceDirectory; 41 string docDirectory; 42 string unittestDirectory; 43 44 //build settings 45 string prefix; 46 string extension; 47 string libCompilerSwitches; 48 string docCompilerSwitches; 49 string interfaceCompilerSwitches; 50 string unittestCompilerSwitches; 51 bool buildStop; 52 53 54 //switch settings 55 bool buildingLibs; 56 bool buildingInterfaceFiles; 57 bool buildingDoc; 58 bool showingHelp; 59 bool force32Build; 60 bool force64Build; 61 62 bool buildingUnittests; 63 string unittestLibraryLocation; 64 65 bool buildingAll; 66 67 bool hasUnrecognizedSwitch; 68 string unrecognizedSwitch; 69 70 71 version(Windows) 72 { 73 bool isWindows = true; 74 bool isLinux = false; 75 bool isMac = false; 76 } 77 else version(linux) 78 { 79 bool isWindows = false; 80 bool isLinux = true; 81 bool isMac = false; 82 } 83 else version(OSX) 84 { 85 bool isWindows = false; 86 bool isLinux = false; 87 bool isMac = true; 88 } 89 else 90 { 91 static assert(false, "DSFML is only supported on OSX, Windows, and Linux."); 92 } 93 94 95 string[5] modules = ["system", "audio", "network", "window", "graphics"]; 96 97 //parses and finds all given switches 98 void parseSwitches(string[] switches) 99 { 100 //no switches passed 101 if(switches.length ==0) 102 { 103 buildingLibs = true; 104 return; 105 } 106 107 //find those switches! 108 foreach(clswitch;switches) 109 { 110 111 switch(clswitch) 112 { 113 case "-help": 114 { 115 showingHelp = true; 116 break; 117 } 118 case "-lib": 119 { 120 buildingLibs = true; 121 break; 122 } 123 case "-doc": 124 { 125 buildingDoc = true; 126 break; 127 } 128 case "-import": 129 { 130 buildingInterfaceFiles = true; 131 break; 132 } 133 case "-m32": 134 { 135 force32Build = true; 136 break; 137 } 138 case "-m64": 139 { 140 force64Build = true; 141 break; 142 } 143 case "-dmd": 144 { 145 isDMD = true; 146 isGDC = false; 147 isLDC = false; 148 compiler = "dmd "; 149 break; 150 } 151 case "-gdc": 152 { 153 isDMD = false; 154 isGDC = true; 155 isLDC = false; 156 compiler = "gdc "; 157 break; 158 } 159 case "-ldc": 160 { 161 isDMD = false; 162 isGDC = false; 163 isLDC = true; 164 compiler = "ldc2 "; 165 break; 166 } 167 case "-unittest": 168 { 169 buildingUnittests = true; 170 unittestLibraryLocation = ""; 171 break; 172 } 173 case "-all": 174 { 175 buildingAll = true; 176 unittestLibraryLocation = ""; 177 break; 178 } 179 180 default: 181 { 182 183 184 //check for unittest switch 185 auto result = clswitch.findSplit(":"); 186 187 //if some unknown switch 188 if(result[0] == clswitch) 189 { 190 hasUnrecognizedSwitch = true; 191 unrecognizedSwitch = clswitch; 192 return; 193 } 194 else 195 { 196 //found unittest or all Switch 197 if((result[0] == "-unittest")) 198 { 199 buildingUnittests = true; 200 unittestLibraryLocation = result[2]; 201 } 202 else if((result[0] == "-all")) 203 { 204 buildingAll = true; 205 unittestLibraryLocation = result[2]; 206 } 207 //found unknown switch that happened to have a : in it 208 else 209 { 210 hasUnrecognizedSwitch = true; 211 unrecognizedSwitch = clswitch; 212 return; 213 } 214 } 215 } 216 } 217 } 218 219 220 //make sure the default happens if not building anything else 221 if(!buildingLibs || !buildingDoc || !buildingInterfaceFiles || !buildingUnittests || !buildingAll) 222 { 223 buildingLibs = true; 224 } 225 226 } 227 228 //checks for any inconsistencies with the passed switchs. Returns true if everything is ok and false if an error was found. 229 bool checkSwitchErrors() 230 { 231 232 //if Switchs are used with -help 233 if(showingHelp) 234 { 235 if(buildingLibs || buildingDoc || buildingInterfaceFiles || buildingUnittests || buildingAll || hasUnrecognizedSwitch || force32Build || force64Build) 236 { 237 writeln("Using -help will ignore all other switchs."); 238 return false; 239 } 240 } 241 242 //can't force both 243 if(force32Build && force64Build) 244 { 245 writeln("Can't use -m32 and -m64 together"); 246 return false; 247 } 248 249 //if other Switchs are used with -all 250 if(buildingAll) 251 { 252 if(buildingLibs || buildingDoc || buildingInterfaceFiles || buildingUnittests) 253 { 254 writeln("Can't use -all with any other build switches (-lib, -doc, -import, -unittest)"); 255 return false; 256 } 257 258 if(unittestLibraryLocation == "") 259 { 260 writeln("Not putting in a location for shared libraries will work if they are in a standard location."); 261 } 262 263 } 264 265 if(buildingUnittests) 266 { 267 if(unittestLibraryLocation == "") 268 { 269 writeln("Note: Not putting in a location for shared libraries will work only if they are in a standard location."); 270 } 271 } 272 273 return true; 274 } 275 276 //initialize all build settings 277 void initialize() 278 { 279 280 if(isWindows) 281 { 282 currentDirectory = getcwd; 283 impDirectory = currentDirectory~"\\src"; 284 libDirectory = currentDirectory~"\\lib\\"; 285 interfaceDirectory = currentDirectory~"\\import\\"; 286 docDirectory = currentDirectory~"\\doc\\"; 287 unittestDirectory = currentDirectory~"\\unittest\\"; 288 289 if(!exists(currentDirectory~"\\lib\\")) 290 { 291 mkdir(currentDirectory~"\\lib\\"); 292 } 293 } 294 else 295 { 296 currentDirectory = getcwd; 297 impDirectory = `"`~currentDirectory~"/src"~`"`; 298 libDirectory = `"`~currentDirectory~"/lib/"~`"`; 299 interfaceDirectory = `"`~currentDirectory~"/import/"~`"`; 300 docDirectory = `"`~currentDirectory~"/doc/"~`"`; 301 unittestDirectory = `"`~currentDirectory~"/unittest/"~`"`; 302 303 if(!exists(currentDirectory~"/lib/")) 304 { 305 mkdir(currentDirectory~"/lib/"); 306 } 307 } 308 309 310 311 if(isDMD) 312 { 313 initializeDMD(); 314 } 315 else if(isGDC) 316 { 317 initializeGDC(); 318 } 319 else 320 { 321 initializeLDC(); 322 } 323 324 if(force32Build) 325 { 326 libCompilerSwitches = "-m32 "~libCompilerSwitches; 327 unittestCompilerSwitches = "-m32 "~unittestCompilerSwitches; 328 } 329 330 if(force64Build) 331 { 332 libCompilerSwitches = "-m64 "~libCompilerSwitches; 333 unittestCompilerSwitches = "-m64 "~unittestCompilerSwitches; 334 } 335 336 337 writeln(); 338 } 339 340 void initializeDMD() 341 { 342 if(isWindows) 343 { 344 writeln("Building for Windows with dmd"); 345 prefix = ""; 346 extension = ".lib"; 347 unittestCompilerSwitches = "-main -unittest -cov -I"~impDirectory~" dsfml-graphics.lib dsfml-window.lib dsfml-audio.lib dsfml-network.lib dsfml-system.lib dsfmlc-graphics.lib dsfmlc-window.lib dsfmlc-audio.lib dsfmlc-network.lib dsfmlc-system.lib "; 348 349 if(!force64Build) 350 { 351 unittestCompilerSwitches~="-L+"~libDirectory; 352 } 353 else 354 { 355 unittestCompilerSwitches~="-L/LIBPATH:"~libDirectory; 356 } 357 } 358 else if(isLinux) 359 { 360 writeln("Building for Linux with dmd"); 361 prefix = "lib"; 362 extension = ".a"; 363 unittestCompilerSwitches = "-main -unittest -cov -I"~impDirectory~" -L-ldsfml-graphics -L-ldsfml-window -L-ldsfml-audio -L-ldsfml-network -L-ldsfml-system -L-ldsfmlc-graphics -L-ldsfmlc-window -L-ldsfmlc-audio -L-ldsfmlc-network -L-ldsfmlc-system -L-L"~libDirectory; 364 } 365 else 366 { 367 writeln("Building for OSX with dmd"); 368 prefix = "lib"; 369 extension = ".a"; 370 unittestCompilerSwitches = "-main -unittest -cov -I"~impDirectory~" -L-ldsfml-graphics -L-ldsfml-window -L-ldsfml-audio -L-ldsfml-network -L-ldsfml-system -L-ldsfmlc-graphics -L-ldsfmlc-window -L-ldsfmlc-audio -L-ldsfmlc-network -L-ldsfmlc-system -L-L"~libDirectory; 371 } 372 373 unittestCompilerSwitches ="-version=DSFML_Unittest_System -version=DSFML_Unittest_Window -version=DSFML_Unittest_Graphics -version=DSFML_Unittest_Audio -version=DSFML_Unittest_Network "~unittestCompilerSwitches; 374 375 376 libCompilerSwitches = "-lib -O -release -inline -I"~impDirectory; 377 docCompilerSwitches = "-D -Dd"~docDirectory~" -c -o- -op"; 378 interfaceCompilerSwitches = "-H -Hd"~interfaceDirectory~" -c -o- -op"; 379 } 380 381 void initializeGDC() 382 { 383 if(isWindows) 384 { 385 writeln("Building for Windows with gdc"); 386 } 387 else if(isLinux) 388 { 389 writeln("Building for Linux with gdc"); 390 } 391 else 392 { 393 writeln("Building for OSX with gdc"); 394 } 395 prefix = "lib"; 396 extension = ".a"; 397 unittestCompilerSwitches = "-fversion=DSFML_Unittest_System -fversion=DSFML_Unittest_Window -fversion=DSFML_Unittest_Graphics -fversion=DSFML_Unittest_Audio -fversion=DSFML_Unittest_Network -funittest -I"~impDirectory~" -ldsfml-graphics -ldsfml-window -ldsfml-audio -ldsfml-network -ldsfml-system -ldsfmlc-graphics -ldsfmlc-window -ldsfmlc-audio -ldsfmlc-network -ldsfmlc-system -L"~libDirectory; 398 399 libCompilerSwitches = "-c -O3 -frelease -I"~impDirectory; 400 docCompilerSwitches = " -fdoc -c"; 401 interfaceCompilerSwitches = " -fintfc -c"; 402 403 } 404 405 void initializeLDC() 406 { 407 //The stuff for windows probbly needs to be fixed 408 if(isWindows) 409 { 410 writeln("Building for Windows with ldc"); 411 412 413 414 if(!force64Build) 415 { 416 prefix = "lib"; 417 extension = ".a"; 418 419 unittestCompilerSwitches = "-main -unittest -I="~impDirectory~" -L=-ldsfml-graphics -L=-ldsfml-window -L=-ldsfml-audio -L=-ldsfml-network -L=-ldsfml-system -L=-ldsfmlc-graphics -L=-ldsfmlc-window -L=-ldsfmlc-audio -L=-ldsfmlc-network -L=-ldsfmlc-system -L=-L"~libDirectory; 420 421 unittestCompilerSwitches~="-L=-L"~libDirectory; 422 } 423 else 424 { 425 prefix = ""; 426 extension = ".lib"; 427 428 unittestCompilerSwitches = "-main -unittest -I="~impDirectory~" dsfml-graphics.lib dsfml-window.lib dsfml-audio.lib dsfml-network.lib dsfml-system.lib dsfmlc-graphics.lib dsfmlc-window.lib dsfmlc-audio.lib dsfmlc-network.lib dsfmlc-system.lib "; 429 430 unittestCompilerSwitches~="-L=/LIBPATH:"~libDirectory; 431 432 } 433 } 434 else if(isLinux) 435 { 436 writeln("Building for Linux with ldc"); 437 prefix = "lib"; 438 extension = ".a"; 439 unittestCompilerSwitches = "-main -singleobj -unittest -I="~impDirectory~" -L=-ldsfml-graphics -L=-ldsfml-window -L=-ldsfml-audio -L=-ldsfml-network -L=-ldsfml-system -L=-ldsfmlc-graphics -L=-ldsfmlc-window -L=-ldsfmlc-audio -L=-ldsfmlc-network -L=-ldsfmlc-system -L=-L"~libDirectory; 440 } 441 else 442 { 443 writeln("Building for OSX with ldc"); 444 prefix = "lib"; 445 extension = ".a"; 446 unittestCompilerSwitches = "-main -unittest -I="~impDirectory~" -L=-ldsfml-graphics -L=-ldsfml-window -L=-ldsfml-audio -L=-ldsfml-network -L=-ldsfml-system -L=-ldsfmlc-graphics -L=-ldsfmlc-window -L=-ldsfmlc-audio -L=-ldsfmlc-network -L=-ldsfmlc-system -L=-L"~libDirectory; 447 } 448 449 unittestCompilerSwitches ="-d-version=DSFML_Unittest_System -d-version=DSFML_Unittest_Window -d-version=DSFML_Unittest_Graphics -d-version=DSFML_Unittest_Audio -d-version=DSFML_Unittest_Network "~unittestCompilerSwitches; 450 451 452 libCompilerSwitches = `-lib -O3 -release -enable-inlining -I=`~impDirectory; 453 docCompilerSwitches = "-D -Dd="~docDirectory~" -c -o- -op"; 454 interfaceCompilerSwitches = "-H -Hd="~interfaceDirectory~" -c -o- -op"; 455 } 456 457 //build the static libraries. Returns true on successful build, false on unsuccessful build 458 bool buildLibs() 459 { 460 writeln("Building static libraries!"); 461 foreach(theModule;modules) 462 { 463 string fileList = ""; 464 465 foreach (string name; dirEntries("src/dsfml/"~theModule, SpanMode.depth)) 466 { 467 if(isDFile(name)) 468 { 469 fileList~= name ~ " "; 470 } 471 472 } 473 474 string buildCommand = compiler~ fileList ~ libCompilerSwitches; 475 476 if(isDMD) 477 { 478 //build the static libs directly 479 buildCommand ~= " -of"~libDirectory~prefix~"dsfml-"~theModule~extension; 480 } 481 else if(isGDC) 482 { 483 //build the object stuff and then build the archive 484 buildCommand ~= " -o"~libDirectory~"dsfml-"~theModule~".o"~" && ar rcs lib/libdsfml-"~theModule~extension~" " ~"lib/dsfml-"~theModule~".o"; 485 } 486 else 487 { 488 buildCommand ~= " -of="~libDirectory~prefix~"dsfml-"~theModule~extension; 489 } 490 491 writeln("Building " ~ theModule~ " module."); 492 493 auto status = executeShell(buildCommand); 494 495 if(status.status !=0) 496 { 497 writeln(status.output); 498 return false; 499 } 500 501 //If we had to build object files, let's delete them. 502 if(exists("lib/dsfml-"~theModule~".o")) 503 { 504 remove("lib/dsfml-"~theModule~".o"); 505 } 506 if(exists("lib/libdsfml-"~theModule~".o")) 507 { 508 remove("lib/libdsfml-"~theModule~".o"); 509 } 510 511 } 512 return true; 513 } 514 515 //build the unit test. Returns true on successful build, false on unsuccessful build 516 bool buildUnittests() 517 { 518 writeln("Building unit tests!"); 519 string filelist = ""; 520 521 foreach(theModule;modules) 522 { 523 foreach (string name; dirEntries("src/dsfml/"~theModule, SpanMode.depth)) 524 { 525 526 if(isDFile(name)) 527 { 528 filelist~= name ~ " "; 529 } 530 } 531 } 532 533 if(isGDC) 534 { 535 std.file.write("main.d", "void main(){}"); 536 filelist = "main.d "~filelist; 537 } 538 539 string buildCommand = compiler~filelist ~ unittestCompilerSwitches; 540 541 if(isDMD) 542 { 543 buildCommand~=" -of"~unittestDirectory~"unittest"; 544 } 545 else if(isGDC) 546 { 547 buildCommand~=" -o"~unittestDirectory~"unittest"; 548 } 549 else 550 { 551 buildCommand~=" -of="~unittestDirectory~"unittest"; 552 } 553 554 if(isWindows) 555 { 556 buildCommand~=".exe" ; 557 } 558 559 //set up unit test library location 560 { 561 562 if(unittestLibraryLocation != "") 563 { 564 if(isDMD) 565 { 566 if(isWindows) 567 { 568 //on windows it is only useful for linking 569 buildCommand~=" -L+"~unittestLibraryLocation; 570 } 571 else 572 { 573 buildCommand~=" -L-L"~unittestLibraryLocation; 574 } 575 } 576 else if(isGDC) 577 { 578 buildCommand~=" -L"~unittestLibraryLocation; 579 } 580 else 581 { 582 buildCommand~=" -L=-L"~unittestLibraryLocation; 583 } 584 585 } 586 } 587 588 auto status = executeShell(buildCommand); 589 590 if(status.status !=0) 591 { 592 writeln(status.output); 593 return false; 594 } 595 return true; 596 } 597 598 void buildDoc() 599 { 600 writeln("Building documentation!"); 601 602 chdir("src"); 603 604 string filelist = ""; 605 foreach(theModule;modules) 606 { 607 foreach (string name; dirEntries("dsfml/"~theModule, SpanMode.depth)) 608 { 609 if(isDFile(name)) 610 { 611 filelist~= name ~ " "; 612 } 613 } 614 } 615 616 string buildCommand = compiler~filelist ~ docCompilerSwitches; 617 618 auto status = executeShell(buildCommand); 619 620 if(status.status !=0) 621 { 622 writeln(status.output); 623 } 624 625 chdir(".."); 626 } 627 void buildDocGDC() 628 { 629 writeln("Building documentation!"); 630 631 chdir("src"); 632 633 foreach(theModule;modules) 634 { 635 foreach (string name; dirEntries("dsfml/"~theModule, SpanMode.depth)) 636 { 637 if(isDFile(name)) 638 { 639 string buildCommand = compiler~ name ~ docCompilerSwitches ~ " -fdoc-dir="~docDirectory~"dsfml/"~theModule; 640 641 auto status = executeShell(buildCommand); 642 643 if(status.status !=0) 644 { 645 writeln(status.output); 646 } 647 } 648 } 649 } 650 651 chdir(".."); 652 } 653 654 void buildInterfaceFiles() 655 { 656 writeln("Building interface files!"); 657 658 chdir("src"); 659 660 string filelist = ""; 661 foreach(theModule;modules) 662 { 663 foreach (string name; dirEntries("dsfml/"~theModule, SpanMode.depth)) 664 { 665 if(isDFile(name)) 666 { 667 filelist~= name ~ " "; 668 } 669 } 670 } 671 672 //TODO: Fix this for GDC 673 string buildCommand = compiler~filelist ~ interfaceCompilerSwitches; 674 675 auto status = executeShell(buildCommand); 676 677 if(status.status !=0) 678 { 679 writeln(status.output); 680 } 681 682 chdir(".."); 683 } 684 685 void buildInterfaceFilesGDC() 686 { 687 writeln("Building interface files!"); 688 689 chdir("src"); 690 691 foreach(theModule;modules) 692 { 693 foreach (string name; dirEntries("dsfml/"~theModule, SpanMode.depth)) 694 { 695 696 if(isDFile(name)) 697 { 698 699 string buildCommand = compiler~ name ~ interfaceCompilerSwitches ~ " -fintfc-dir="~interfaceDirectory~"dsfml/"~theModule; 700 701 auto status = executeShell(buildCommand); 702 703 if(status.status !=0) 704 { 705 writeln(status.output); 706 } 707 } 708 709 } 710 } 711 712 chdir(".."); 713 } 714 715 void showHelp() 716 { 717 writeln("Main switches:"); 718 writeln("-help : Show all supported switches."); 719 writeln("-lib : Build static libraries"); 720 writeln("-doc : Build documentation"); 721 writeln("-import : Build interface files for importing"); 722 writeln("-unittest : Build static libs and unittests"); 723 writeln("-all : Build everything"); 724 writeln("-unittest:sharedDir : Build static libs and unittests, sharedDir is the location of DSFMLC shared libraries"); 725 writeln("-all:sharedDir : Build everything, sharedDir is the location of DSFMLC shared libraries"); 726 writeln(); 727 writeln("Modifier switches:"); 728 writeln("-m32 : force a 32 bit build"); 729 writeln("-m64 : force a 64 bit build"); 730 writeln("-dmd : force using dmd as the compiler"); 731 writeln("-gdc : force using gdc as the compiler"); 732 writeln("-ldc : force using ldc as the compiler"); 733 734 writeln(); 735 writeln("Default (no switches passed) will be to build static libraries only with the compiler that built this script."); 736 } 737 738 //used to add quotes around full directories 739 //To be used in the next update (2.3) 740 string quoteString(string s) 741 { 742 return `"`~s~`"`; 743 } 744 745 //checks if a file is a .d file. 746 //osx adds those stupid .DS_Store files when I am working on things, and I hate them. 747 bool isDFile(string name) 748 { 749 string[] splitName = split(name, "."); 750 751 return (splitName[$-1] == "d"); 752 } 753 754 int main(string[] args) 755 { 756 parseSwitches(args[1..$]); 757 758 if(!checkSwitchErrors()) 759 { 760 return -1; 761 } 762 763 764 if(unrecognizedSwitch || showingHelp) 765 { 766 if(unrecognizedSwitch) 767 { 768 writeln("Found unrecognized switch: ", unrecognizedSwitch); 769 } 770 771 showHelp(); 772 return -1; 773 } 774 775 writeln(); 776 initialize(); 777 if(buildingLibs) 778 { 779 if(!buildLibs()) 780 { 781 return -1; 782 } 783 } 784 if(buildingUnittests) 785 { 786 if(!buildLibs()) 787 { 788 return -1; 789 } 790 if(!buildUnittests()) 791 { 792 return -1; 793 } 794 } 795 if(buildingDoc) 796 { 797 if(isGDC) 798 { 799 buildDocGDC(); 800 } 801 else 802 { 803 buildDoc(); 804 } 805 } 806 if(buildingInterfaceFiles) 807 { 808 if(isGDC) 809 { 810 buildInterfaceFilesGDC(); 811 } 812 else 813 { 814 buildInterfaceFiles(); 815 } 816 } 817 if(buildingAll) 818 { 819 if(!buildLibs()) 820 { 821 return -1; 822 } 823 buildDoc(); 824 buildInterfaceFiles(); 825 if(!buildUnittests()) 826 { 827 return -1; 828 } 829 } 830 831 writeln("Done!"); 832 return 0; 833 }