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.3 38 Created Time:2014-10-27 39 Modify Time:2014-10-31~2014-11-3 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 string strcopy ="copy dco.exe " ~ strDCEnvFile; 250 writeln(strcopy); 251 auto status = system(strcopy); 252 if(status !=0) 253 { 254 writeln("copy failed."); 255 } 256 //copy(strTargetFileName,strDCEnvFile); 257 } 258 } 259 260 bool bUpToDate = (targetTime >= sourceLastUpdateTime); 261 262 if(!bUpToDate || bForce) 263 { 264 removeExe(strTargetFileName); 265 } 266 return bUpToDate; 267 } 268 269 return false; 270 } 271 SysTime getTargetTime(string strPathFile) 272 { 273 return DirEntry(strPathFile).timeLastModified; 274 } 275 void removeExe(string strPathExe) 276 { 277 if(exists(strPathExe)) 278 { 279 if(system("del " ~ strPathExe) == 0) 280 { 281 writeln(strPathExe ~ ", remove ok!"); 282 return; 283 } 284 } 285 } 286 287 bool checkIsUpToDate(string strPathFile,SysTime targettime) 288 { 289 if(!exists(strPathFile)) return false; 290 auto testFile = DirEntry(strPathFile); 291 auto createTime = testFile.timeLastModified; 292 293 return (targettime <= createTime); 294 } 295 296 void buildExe(string[] args) 297 { 298 string c; 299 int p; 300 foreach(int i,arg;args) 301 { 302 c = toLower(arg); 303 p = c.indexOf('-'); 304 if(p != -1) 305 { 306 c = c[p+1 .. c.length]; 307 } 308 switch(c) 309 { 310 case "h","help": 311 ShowUsage(); 312 break; 313 case "gui": 314 strTargetLflags = strWindows; 315 bUseSpecialLib = true; 316 strAddArgs = strAddArgsdfl; 317 break; 318 case "win","windows","winexe": 319 strTargetLflags = strWindows; 320 break; 321 case "debug": 322 bDebug = true; 323 break; 324 case "release": 325 bDebug = false; 326 strDebug = " -" ~ c.idup; 327 break; 328 329 case "console","con","exe": 330 strTargetLflags = strConsole; 331 break; 332 case "all": 333 bUseSpecialLib = false; 334 strAddLib = strLibs; 335 strAddArgs = strAddArgsdfl; 336 strImport = strImportDefault; 337 strTargetLflags = strConsole; 338 break; 339 case "addlib": 340 strAddLib = strLibs~" "; 341 strImport = strImportDefault; 342 strTargetLflags = strConsole; 343 break; 344 case "arg": 345 strAddArgs = strAddArgsdfl; 346 break; 347 case "lib": 348 strTargetTypeSwitch = " -" ~ targetTypeDefault; 349 break; 350 case "dfl","dfllib": 351 bBuildSpecialLib = true; 352 strTargetTypeSwitch = " -" ~ targetTypeDefault; 353 break; 354 case "c","copy": 355 bCopy = true; 356 break; 357 case "force": 358 bForce = true; 359 break; 360 case "init": 361 362 break; 363 default: 364 if(i ==0) continue; 365 if(c.indexOf(".d") != -1) 366 { 367 strDFile ~= " "; 368 strDFile ~= arg; 369 } 370 else 371 { 372 strOtherArgs ~= " "; 373 strOtherArgs ~= arg; 374 } 375 break; 376 } 377 } 378 379 strTargetLib = bDebug ? SpecialLib ~ "_debug.lib" : SpecialLib ~ ".lib"; 380 381 if(bBuildSpecialLib) 382 { 383 strOtherArgs = " -of" ~ strTargetLib; 384 strAddLib = strLibs; 385 } 386 387 if(bUseSpecialLib) 388 { 389 if(SpecialLib == "dfl") 390 { 391 strLibs =strWinLibs; 392 } 393 strAddLib = strTargetLib ~" " ~ strLibs; 394 } 395 396 buildExe(); 397 } 398 399 void buildExe() 400 { 401 if(bForce) 402 { 403 removeExe(strTargetFileName); 404 } 405 strDC ~= " "; 406 strDC ~= strTargetTypeSwitch; 407 string strCommon = strAddLib ~ strTargetLflags ~ strDFile ~ strDebug; 408 409 string buildstr = strDC ~ strAddArgsdfl ~ strOtherArgs ~ " " ~ strImportDefault ~ strCommon ~ "\r\n"; 410 buildstr = bUseSpecialLib ? buildstr : strDC ~ strAddArgs ~ strOtherArgs ~ " " ~ strImport ~ strCommon; 411 if(bDisplayBuildStr) 412 { 413 writeln(buildstr); 414 } 415 416 StopWatch sw; 417 sw.start(); 418 auto status = system(buildstr); 419 sw.stop(); 420 421 if (status != 0) 422 { 423 writeln("Compilation failed:\n", status); 424 } 425 else 426 { 427 writeln("\nCompile time :" , sw.peek().msecs/1000.0,"secs"); 428 429 if(bCopy) 430 { 431 copyFile(); 432 } 433 } 434 writeln("End."); 435 } 436 437 void copyFile() 438 { 439 string strcopy; 440 if(!exists(strTargetFileName)) return; 441 if( sourceLastUpdateTime >= getTargetTime(strTargetFileName)) 442 { 443 writeln(strTargetFileName," is up to date."); 444 return; 445 } 446 if(strTargetFileName.indexOf("exe") != -1) 447 { 448 //copy(strTargetFileName,strDCEnv); // 449 strcopy = "copy " ~ strTargetFileName~" " ~ strDCEnv; 450 } 451 else 452 { 453 string strDCLibPath = strDCEnv[0..(strDCEnv.length - "bin".length)].idup ~ "lib"; 454 //copy(strDCEnv,strDCLibPath); 455 strcopy = "copy " ~ strTargetFileName ~ " " ~ strDCLibPath; 456 } 457 if(bDisplayCopyInfo) 458 { 459 writeln(strcopy); 460 } 461 462 auto status = system(strcopy); 463 if(status !=0) 464 { 465 writeln("Copy failed."); 466 } 467 } 468 469 bool findFiles() 470 { 471 bool bPackage = false; 472 auto packages = dirEntries(".","{package.d,all.d}",SpanMode.depth); 473 if(packages.count >0) bPackage = true; 474 auto dFiles = dirEntries(".","*.{d,di}",SpanMode.depth); 475 int icount =0; 476 SysTime fileTime; 477 DirEntry rootDE ; 478 479 foreach(d; dFiles) 480 { 481 if(!bAssignTarget) 482 { 483 if(icount == 0) 484 { 485 strTargetName = d.name[(d.name.lastIndexOf("\\")+1) .. d.name.lastIndexOf(".")]; 486 strTargetName ~= "." ~ strTargetType; 487 } 488 } 489 if(icount ==0 ) 490 { 491 ReadDFile(d,bPackage); 492 } 493 494 strDFile ~= " "; 495 strDFile ~= d.name[2 ..$].idup; 496 497 //sourceLastUpdateTime 498 rootDE = DirEntry(d); 499 if(rootDE.timeLastModified > fileTime) 500 { 501 fileTime = rootDE.timeLastModified; 502 } 503 icount++; 504 } 505 sourceLastUpdateTime = fileTime; 506 507 strDFile = strDFile.stripRight().idup; 508 509 if(icount <= 0) 510 { 511 writeln("Not found any *.d files in current folder.If there is a 'source' or 'src' folder,dco will find the '*.d' from there."); 512 return false; 513 } 514 bCopy = (strDFile.indexOf("dco.d") != -1) ? true : false; 515 return true; 516 } 517 518 void getTargetInfo() 519 { 520 string root_path = getcwd(); 521 string strPath; 522 auto dFiles = dirEntries(root_path,"*.{lib,exe}",SpanMode.shallow); 523 int i =0; 524 foreach(d;dFiles) 525 { 526 i++; 527 strTargetFileName =d; 528 strTargetType = d.name[d.name.lastIndexOf(".")+1..$]; 529 break; 530 531 } 532 if(i ==0) 533 { 534 if(strTargetName.indexOf("." ~ strTargetType) == -1) 535 { 536 strTargetName = strTargetName ~ "." ~ strTargetType; 537 } 538 strTargetFileName = root_path ~ "\\" ~ strTargetName; 539 } 540 return; 541 } 542 543 void ShowUsage() 544 { 545 writeln(" 546 dco written by FrankLIKE. 547 Usage: 548 dco [<switches...>] <files...> 549 550 for example: dco ↓ 551 or: dco app.d 552 553 build for dfl2: dco ↓ 554 or: dco -gui 555 or: dco *.d -gui 556 build for other: dco -lib 557 or: dco *.d -lib 558 or: dco *.d -release 559 or: dco *.d -arg -addlib 560 561 Switches: 562 -h Print help(usage: -h,or -help). 563 -c Copy new exe or lib to 'windows/bin' or 'lib' Folder 564 (-copy also is ok). 565 -release Build files's Release version(Default version is 'debug'). 566 -gui Make a Windows GUI exe without a console(For DFL). 567 -win Make a Windows GUI exe without a console 568 (For any other: the same to -winexe,-windows). 569 -lib Build lib files. 570 -ini Create the ini file for config. 571 -all Build files by args,libs(Default no dfl_debug.lib) in Console. 572 -arg Build files by args(-de -w -property -X). 573 -addlib Build files by add libs(ole32.lib oleAut32.lib gdi32.lib 574 Comctl32.lib Comdlg32.lib advapi32.lib uuid.lib ws2_32.lib). 575 "); 576 } 577 578 void ReadDFile(string dFile,bool bPackage) 579 { 580 auto file = File(dFile); 581 scope(failure) file.close(); 582 auto range = file.byLine(); 583 int icount = 0; 584 foreach (line; range) 585 { 586 if (!line.init && line.indexOf("import") != -1) 587 { 588 bUseSpecialLib = !bPackage; 589 bBuildSpecialLib = bPackage; 590 if(bUseSpecialLib) strTargetLflags = strWindows; 591 592 if(line.indexOf("dfl") != -1) 593 { 594 SpecialLib = "dfl"; 595 break; 596 } 597 else if(line.indexOf("dgui") != -1) 598 { 599 strArgs = strAddArgsdfl = " -g -de -w -property -X "; 600 SpecialLib = "dgui"; 601 break; 602 } 603 } 604 icount++; 605 if(icount >100) break; 606 } 607 file.close(); 608 } 609 610 void initNewConfigFile() 611 { 612 auto ini = File("dco.ini","w"); 613 ini.writeln(";DC=dmd"); 614 ini.writeln("DC="); 615 ini.writeln(";DCStandardEnvBin=dmd2\\windows\\bin"); 616 ini.writeln("DCStandardEnvBin="); 617 ini.writeln(";SpecialLib=dfl"); 618 ini.writeln("SpecialLib="); 619 ini.writeln(";importPath=-I$(DMDInstallDir)windows/import"); 620 ini.writeln("importPath="); 621 ini.writeln(";lflags=-L/su:console:4"); 622 ini.writeln(";lflags=-L/SUBSYSTEM:WINDOWS"); 623 ini.writeln("lflags="); 624 ini.close(); 625 /* 626 auto pid = spawnProcess("notepad.exe dco.ini"); 627 auto dmd = tryWait(pid); 628 if (dmd.terminated) 629 { 630 if (dmd.status == 0) writeln("open dco.ini succeeded!"); 631 else writeln("open dco.ini failed"); 632 } 633 else writeln("Still opening..."); 634 */ 635 } 636 637 void readInJson() 638 { 639 if(!exists("dub.json") & !exists("package.json") ) return; 640 /* 641 strPackageName = configKeyValue.get("name",""); 642 strArgs = configKeyValue.get("args",strAddArgs); 643 strLibs = configKeyValue.get("libs",""); 644 strTargetName = configKeyValue.get("targetName",""); 645 strTargetType = configKeyValue.get("targetType",strTargetType); 646 */ 647 } 648