1 /// 2 // Written in the D programming language. 3 /** 4 This is a build tool,compile *.d to exe or lib,and help to build dfl2 gui (or other you like). 5 now default DC is dmd ,default platform is windows. 6 7 If your DC is dmd, dco can start no config file. 8 9 Compiler dco.d :dmd dco.d -release,and dco ↓, 10 11 Usage: 12 "use before" run: dco -ini, config some infos to 'dco.ini' file,';' or '#' means you can do as it.Then copy dco.ini to your PATH: such as dmd's config file:sc.ini. 13 And dco.exe can auto copy itsself to EnvPath,such as dmd.exe 's path: dmd2\window\bin. 14 after that,you can run the 'dco.exe' anywhere. 15 16 For example: 17 to get the debug version( -release to get another) 18 19 build some *.d to lib or exe : dco ↓ 20 build for libs such as dfl,dgui : dco -lib 21 build for app.d use dfl2 : dco -gui 22 build app.d use dfl2 for console : dco -con 23 build one app.d in many *.d : dco app.d 24 build lib and copy to libs : dco -lib -c 25 build by custom : dco -arg -addlib -lib -c 26 27 if your exe's file works on console,you should add '-con' or '-console'. 28 29 Copyright: Copyright FrankLIKE 2014-. 30 31 License: $(LGPL-3.0). 32 33 Authors: FrankLIKE 34 35 Source: $(dco.d) 36 37 version: v0.0.5 38 Created Time:2014-10-27 39 Modify Time:2014-10-31~2014-11-5 40 */ 41 module dco; 42 /// dco 43 import std.stdio; 44 import std.datetime; 45 import std.process; 46 import std.string; 47 import std.file; 48 import std.path; 49 import std.exception; 50 import std.json; 51 import std.exception; 52 53 string strAddArgs,strAddArgsdfl = " -de -w -property -X "; 54 string strDebug,strDebugDefault=" -debug"; 55 string strTargetLflags,strConsole=" -L/su:console:4 ",strWindows = " -L/SUBSYSTEM:WINDOWS "; 56 string strTargetLib,SpecialLib = "dfl",strWinLibs=" ole32.lib oleAut32.lib gdi32.lib Comctl32.lib Comdlg32.lib advapi32.lib uuid.lib ws2_32.lib ";// $(DMDInstallDir)windows\\lib\\ 57 string strDFile; 58 string strAddLib; 59 string strOtherArgs; 60 string strImportDefault = " -I$(DMDInstallDir)windows/import "; 61 string strTargetPath,strTargetFileName,strTargetTypeSwitch,targetTypeDefault = "lib"; 62 string strDCEnv,strDCEnvFile; 63 SysTime sourceLastUpdateTime,targetTime; 64 65 bool bUseSpecialLib =false,bDebug =true,bBuildSpecialLib =false; 66 bool bCopy =false ,bDisplayBuildStr=false,bDisplayCopyInfo =true; 67 bool bDCO = false; 68 bool bForce = false; 69 bool bAssignTarget =false; 70 71 //ini 72 string configFile ="dco.ini"; 73 string[string] configKeyValue; 74 75 //ini args 76 string strPackageName,strArgs,strTargetName,strTargetType ="exe",strDC,strDCStandardEnvBin ="dmd2\\windows\\bin",strLibs ,strImport,strLflags; 77 78 void main(string[] args) 79 { 80 81 if(!findDCEnv()) return; 82 // readInJson(); 83 if(!checkArgs(args)) 84 { 85 if(!findFiles()) 86 { 87 ShowUsage(); 88 return; 89 } 90 } 91 if(args.length ==1) 92 { 93 if(!CheckBinFolderAndCopy()) return; 94 } 95 if(args.length == 2 && (toLower(args[1]) == "-h" || toLower(args[1]) == "-help")) 96 { 97 ShowUsage(); 98 return; 99 } 100 if(strPackageName =="") 101 { 102 strPackageName = strTargetName; 103 } 104 105 buildExe(args); 106 } 107 108 bool findDCEnv() 109 { 110 if(!readConfig(configFile)) return false; 111 auto path = environment["PATH"]; 112 113 ptrdiff_t i = path.indexOf(strDCStandardEnvBin); 114 int len = strDCStandardEnvBin.length; 115 string strNoDC = "Not found "~strDC~" in your computer,please setup it."; 116 if(i != -1) 117 { 118 path = path[0 .. i+len].idup; 119 120 ptrdiff_t j = path.lastIndexOf(";"); 121 strDCEnv = path[j+1 .. i+len]; 122 123 if(exists(strDCEnv~"\\"~strDC.stripRight()~".exe")) 124 { 125 strDCEnvFile = strDCEnv ~ "\\dco.exe"; 126 return true; 127 } 128 else 129 { 130 writeln("\nMaybe FirWall stop the 'dco',that can't know the 'dco.exe' exists."); 131 return false; 132 } 133 } 134 135 writeln(strNoDC); 136 return false; 137 } 138 139 bool readConfig(string configFile) 140 { 141 try 142 { 143 string strConfigPath = thisExePath(); 144 strConfigPath = strConfigPath[0..strConfigPath.lastIndexOf("\\")].idup; 145 strConfigPath ~= "\\" ~ configFile; 146 147 if(!exists(strConfigPath)) 148 { 149 writeln("if you known dco.ini is there,maybe your 'FireWall' stop to access the 'dco.ini',please stop it.Otherwise,dco not found dco.ini, it will help you to create a init dco.ini file ,but you should input something in it."); 150 initNewConfigFile(); 151 return false; 152 } 153 154 auto file = File(strConfigPath); 155 scope(failure) file.close(); 156 auto range = file.byLine(); 157 foreach (line; range) 158 { 159 if (!line.init && line[0] != '#' && line[0] != ';' && line.indexOf("=") != -1) 160 { 161 ptrdiff_t i =line.indexOf("="); 162 configKeyValue[line.strip()[0..i].idup] = line.strip()[i+1..$].idup; 163 } 164 } 165 166 file.close(); 167 168 strDC = configKeyValue.get("DC","dmd"); 169 170 strDCStandardEnvBin = configKeyValue.get("DCStandardEnvBin","dmd2\\windows\\bin"); 171 SpecialLib = configKeyValue.get("SpecialLib","dfl"); 172 strImport = configKeyValue.get("importPath",""); 173 strLflags = configKeyValue.get("lflags","/su:console:4"); 174 return true; 175 } 176 catch(Exception e) 177 { 178 writeln(" Read ini file err,you should input something in ini file.",e.msg); 179 return false; 180 } 181 } 182 183 184 bool checkArgs(string[] args) 185 { 186 string c; 187 int p; 188 bool bfindD =false; 189 foreach(int i,arg;args) 190 { 191 c = toLower(arg); 192 p = c.indexOf('-'); 193 if(p != -1) 194 { 195 c = c[p+1 .. $]; 196 } 197 if(i ==0) continue; 198 if(c.indexOf(".d") != -1) 199 { 200 bfindD = true; 201 202 } 203 else if(c == "force") 204 { 205 bForce = true; 206 } 207 else if(c.indexOf("of") != -1) 208 { 209 bAssignTarget = true; 210 strTargetName = c[(c.indexOf("of")+1)..$]; 211 } 212 else if(c == strPackageName || c == strPackageName~"lib") 213 { 214 bAssignTarget = true; 215 bBuildSpecialLib = true; 216 strTargetTypeSwitch = " -" ~ targetTypeDefault; 217 strTargetName = c~".lib"; 218 } 219 else if (c == "ini") 220 { 221 initNewConfigFile(); 222 return false; 223 } 224 } 225 return bfindD; 226 } 227 228 bool CheckBinFolderAndCopy() 229 { 230 if(checkIsUpToDate()) 231 { 232 writeln(strTargetName ~" file is up to date."); 233 return false; 234 } 235 return true; 236 } 237 238 bool checkIsUpToDate() 239 { 240 getTargetInfo(); 241 if(exists(strTargetFileName)) 242 { 243 targetTime = getTargetTime(strTargetFileName); 244 245 if(strTargetFileName.indexOf("dco.exe") != -1) 246 { 247 if(!checkIsUpToDate(strDCEnvFile ,targetTime)) 248 { 249 auto files = dirEntries(".","dco.{exe,ini}",SpanMode.shallow); 250 foreach(d;files) 251 { 252 string strcopy ="copy " ~ d ~" " ~ strDCEnv; 253 writeln(strcopy); 254 auto status = system(strcopy); 255 if(status !=0) 256 { 257 writeln("copy failed."); 258 } 259 } 260 //copy(strTargetFileName,strDCEnvFile); 261 } 262 } 263 264 bool bUpToDate = (targetTime >= sourceLastUpdateTime); 265 266 if(!bUpToDate || bForce) 267 { 268 removeExe(strTargetFileName); 269 } 270 return bUpToDate; 271 } 272 273 return false; 274 } 275 SysTime getTargetTime(string strPathFile) 276 { 277 return DirEntry(strPathFile).timeLastModified; 278 } 279 void removeExe(string strPathExe) 280 { 281 if(exists(strPathExe)) 282 { 283 if(system("del " ~ strPathExe) == 0) 284 { 285 writeln(strPathExe ~ ", remove ok!"); 286 return; 287 } 288 } 289 } 290 291 bool checkIsUpToDate(string strPathFile,SysTime targettime) 292 { 293 if(!exists(strPathFile)) return false; 294 auto testFile = DirEntry(strPathFile); 295 auto createTime = testFile.timeLastModified; 296 297 return (targettime <= createTime); 298 } 299 300 void buildExe(string[] args) 301 { 302 string c; 303 int p; 304 foreach(int i,arg;args) 305 { 306 c = toLower(arg); 307 p = c.indexOf('-'); 308 if(p != -1) 309 { 310 c = c[p+1 .. c.length]; 311 } 312 switch(c) 313 { 314 case "h","help": 315 ShowUsage(); 316 break; 317 case "gui": 318 strTargetLflags = strWindows; 319 bUseSpecialLib = true; 320 strAddArgs = strAddArgsdfl; 321 break; 322 case "win","windows","winexe": 323 strTargetLflags = strWindows; 324 break; 325 case "debug": 326 bDebug = true; 327 break; 328 case "release": 329 bDebug = false; 330 strDebug = " -" ~ c.idup; 331 break; 332 333 case "console","con","exe": 334 strTargetLflags = strConsole; 335 break; 336 case "all": 337 bUseSpecialLib = false; 338 strAddLib = strLibs; 339 strAddArgs = strAddArgsdfl; 340 strImport = strImportDefault; 341 strTargetLflags = strConsole; 342 break; 343 case "addlib": 344 strAddLib = strLibs~" "; 345 strImport = strImportDefault; 346 strTargetLflags = strConsole; 347 break; 348 case "arg": 349 strAddArgs = strAddArgsdfl; 350 break; 351 case "lib": 352 strTargetTypeSwitch = " -" ~ targetTypeDefault; 353 break; 354 case "dfl","dfllib": 355 bBuildSpecialLib = true; 356 strTargetTypeSwitch = " -" ~ targetTypeDefault; 357 break; 358 case "c","copy": 359 bCopy = true; 360 break; 361 case "force": 362 bForce = true; 363 break; 364 case "init": 365 366 break; 367 default: 368 if(i ==0) continue; 369 if(c.indexOf(".d") != -1) 370 { 371 strDFile ~= " "; 372 strDFile ~= arg; 373 } 374 else 375 { 376 strOtherArgs ~= " "; 377 strOtherArgs ~= arg; 378 } 379 break; 380 } 381 } 382 383 strTargetLib = bDebug ? SpecialLib ~ "_debug.lib" : SpecialLib ~ ".lib"; 384 385 if(bBuildSpecialLib) 386 { 387 strOtherArgs = " -of" ~ strTargetLib; 388 strAddLib = strLibs; 389 strTargetFileName = getcwd() ~ "\\" ~ strTargetLib; 390 } 391 392 if(bUseSpecialLib) 393 { 394 if(SpecialLib == "dfl") 395 { 396 strLibs =strWinLibs; 397 } 398 strAddLib = strTargetLib ~" " ~ strLibs; 399 } 400 401 buildExe(); 402 } 403 404 void buildExe() 405 { 406 if(bForce) 407 { 408 removeExe(strTargetFileName); 409 } 410 strDC ~= " "; 411 strDC ~= strTargetTypeSwitch; 412 string strCommon = strOtherArgs ~" " ~ strImportDefault ~ strImport ~ " " ~ strAddLib ~ strTargetLflags ~ strDFile ~ strDebug; 413 string buildstr = strDC ~ strAddArgsdfl ~ strCommon ~ "\r\n"; 414 buildstr = bUseSpecialLib ? buildstr : strDC ~ strCommon; 415 if(bDisplayBuildStr) 416 { 417 writeln(buildstr); 418 } 419 420 StopWatch sw; 421 sw.start(); 422 auto status = system(buildstr); 423 sw.stop(); 424 425 if (status != 0) 426 { 427 writeln("Compilation failed:\n", status); 428 } 429 else 430 { 431 writeln("\nCompile time :" , sw.peek().msecs/1000.0,"secs"); 432 433 if(bCopy) 434 { 435 copyFile(); 436 } 437 } 438 writeln("End."); 439 } 440 441 void copyFile() 442 { 443 string strcopy; 444 if(!exists(strTargetFileName)) 445 { 446 writeln(strTargetFileName," is not exists,stop copy."); 447 return; 448 } 449 /* 450 if( sourceLastUpdateTime >= getTargetTime(strTargetFileName)) 451 { 452 writeln(strTargetFileName," is up to date."); 453 return; 454 } 455 */ 456 if(strTargetFileName.indexOf("exe") != -1) 457 { 458 //copy(strTargetFileName,strDCEnv); // 459 strcopy = "copy " ~ strTargetFileName~" " ~ strDCEnv; 460 } 461 else 462 { 463 string strDCLibPath = strDCEnv[0..(strDCEnv.length - "bin".length)].idup ~ "lib"; 464 //copy(strDCEnv,strDCLibPath); 465 strcopy = "copy " ~ strTargetFileName ~ " " ~ strDCLibPath; 466 } 467 if(bDisplayCopyInfo) 468 { 469 writeln(strcopy); 470 } 471 472 auto status = system(strcopy); 473 if(status !=0) 474 { 475 writeln("Copy failed."); 476 } 477 } 478 479 bool findFiles() 480 { 481 int i=0; 482 bool bPackage = false; 483 auto packages = dirEntries(".","{package.d,all.d}",SpanMode.depth); 484 foreach(p; packages){i++;} 485 bPackage = (i > 0); 486 auto dFiles = dirEntries(".","*.{d,di}",SpanMode.depth); 487 int icount =0; 488 SysTime fileTime; 489 DirEntry rootDE ; 490 491 foreach(d; dFiles) 492 { 493 if(!bAssignTarget) 494 { 495 if(icount == 0) 496 { 497 strTargetName = d.name[(d.name.lastIndexOf("\\")+1) .. d.name.lastIndexOf(".")]; 498 strTargetName ~= "." ~ strTargetType; 499 } 500 } 501 if(icount ==0 ) 502 { 503 ReadDFile(d,bPackage); 504 } 505 506 strDFile ~= " "; 507 strDFile ~= d.name[2 ..$].idup; 508 509 //sourceLastUpdateTime 510 rootDE = DirEntry(d); 511 if(rootDE.timeLastModified > fileTime) 512 { 513 fileTime = rootDE.timeLastModified; 514 } 515 icount++; 516 } 517 sourceLastUpdateTime = fileTime; 518 519 strDFile = strDFile.stripRight().idup; 520 521 if(icount <= 0) 522 { 523 writeln("Not found any *.d files in current folder.If there is a 'source' or 'src' folder,dco will find the '*.d' from there."); 524 return false; 525 } 526 bCopy = (strDFile.indexOf("dco.d") != -1) ? true : false; 527 return true; 528 } 529 530 void getTargetInfo() 531 { 532 string root_path = getcwd(); 533 string strPath; 534 auto dFiles = dirEntries(root_path,"*.{lib,exe}",SpanMode.shallow); 535 int i =0; 536 foreach(d;dFiles) 537 { 538 i++; 539 strTargetFileName =d; 540 strTargetType = d.name[d.name.lastIndexOf(".")+1..$]; 541 break; 542 543 } 544 if(i ==0) 545 { 546 if(strTargetName.indexOf("." ~ strTargetType) == -1) 547 { 548 strTargetName = strTargetName ~ "." ~ strTargetType; 549 } 550 strTargetFileName = root_path ~ "\\" ~ strTargetName; 551 } 552 return; 553 } 554 555 void ShowUsage() 556 { 557 writeln(" 558 dco written by FrankLIKE. 559 Usage: 560 dco [<switches...>] <files...> 561 562 for example: dco ↓ 563 or: dco app.d 564 565 build for dfl2: dco ↓ 566 or: dco -gui 567 or: dco *.d -gui 568 build for other: dco -lib 569 or: dco *.d -lib 570 or: dco *.d -release 571 or: dco *.d -arg -addlib 572 573 Switches: 574 -h Print help(usage: -h,or -help). 575 -c Copy new exe or lib to 'windows/bin' or 'lib' Folder 576 (-copy also is ok). 577 -release Build files's Release version(Default version is 'debug'). 578 -gui Make a Windows GUI exe without a console(For DFL). 579 -win Make a Windows GUI exe without a console 580 (For any other: the same to -winexe,-windows). 581 -lib Build lib files. 582 -ini Create the ini file for config. 583 -all Build files by args,libs(Default no dfl_debug.lib) in Console. 584 -arg Build files by args(-de -w -property -X). 585 -addlib Build files by add libs(ole32.lib oleAut32.lib gdi32.lib 586 Comctl32.lib Comdlg32.lib advapi32.lib uuid.lib ws2_32.lib). 587 "); 588 } 589 590 void ReadDFile(string dFile,bool bPackage) 591 { 592 auto file = File(dFile); 593 scope(exit) file.close(); 594 auto range = file.byLine(); 595 int icount = 0; 596 foreach (line; range) 597 { 598 if (!line.init && line.indexOf("import") != -1) 599 { 600 bUseSpecialLib = !bPackage; 601 bBuildSpecialLib = bPackage; 602 if(bUseSpecialLib) strTargetLflags = strWindows; 603 604 if(line.indexOf("dfl") != -1) 605 { 606 SpecialLib = "dfl"; 607 break; 608 } 609 else if(line.indexOf("dgui") != -1) 610 { 611 strArgs = strAddArgsdfl = " -g -de -w -property -X "; 612 SpecialLib = "dgui"; 613 break; 614 } 615 } 616 icount++; 617 if(icount >100) break; 618 } 619 } 620 621 void initNewConfigFile() 622 { 623 auto ini = File("dco.ini","w"); 624 scope(failure) ini.close(); 625 ini.writeln(";DC=dmd"); 626 ini.writeln("DC="); 627 ini.writeln(";DCStandardEnvBin=dmd2\\windows\\bin"); 628 ini.writeln("DCStandardEnvBin="); 629 ini.writeln(";SpecialLib=dfl"); 630 ini.writeln("SpecialLib="); 631 ini.writeln(";importPath=-I$(DMDInstallDir)windows/import"); 632 ini.writeln("importPath="); 633 ini.writeln(";lflags=-L/su:console:4"); 634 ini.writeln(";lflags=-L/SUBSYSTEM:WINDOWS"); 635 ini.writeln("lflags="); 636 ini.close(); 637 638 auto pid = spawnProcess(["notepad.exe","dco.ini"]); 639 auto dmd = tryWait(pid); 640 if (dmd.terminated) 641 { 642 if (dmd.status == 0) writeln("open dco.ini succeeded!"); 643 else writeln("open dco.ini failed"); 644 } 645 else writeln("Still opening..."); 646 647 } 648 649 void readInJson() 650 { 651 if(!exists("dub.json") & !exists("package.json") ) return; 652 /* 653 strPackageName = configKeyValue.get("name",""); 654 strArgs = configKeyValue.get("args",strAddArgs); 655 strLibs = configKeyValue.get("libs",""); 656 strTargetName = configKeyValue.get("targetName",""); 657 strTargetType = configKeyValue.get("targetType",strTargetType); 658 */ 659 } 660