From fcd67b52005283cb22d0668b462827fd65924654 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Mon, 24 Mar 2014 09:41:00 -0700 Subject: [PATCH 1/6] Refactor HXCPP run tool into multiple files --- run.n | Bin 108149 -> 107463 bytes tools/run/BuildTool.hx | 896 +--------------------------------------- tools/run/Compiler.hx | 265 ++++++++++++ tools/run/DirManager.hx | 96 +++++ tools/run/File.hx | 64 +++ tools/run/FileGroup.hx | 142 +++++++ tools/run/HLSL.hx | 40 ++ tools/run/Linker.hx | 201 +++++++++ tools/run/Stripper.hx | 23 ++ tools/run/Target.hx | 64 +++ 10 files changed, 896 insertions(+), 895 deletions(-) create mode 100644 tools/run/Compiler.hx create mode 100644 tools/run/DirManager.hx create mode 100644 tools/run/File.hx create mode 100644 tools/run/FileGroup.hx create mode 100644 tools/run/HLSL.hx create mode 100644 tools/run/Linker.hx create mode 100644 tools/run/Stripper.hx create mode 100644 tools/run/Target.hx diff --git a/run.n b/run.n index 2c8f8e08429bd708f4d961dee92593edc477f318..92917a7f18a9fb99c3d93f464607afcd557c0693 100644 GIT binary patch delta 30478 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�Ya%Cbk&ShhA8sv-Ml8pH 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 delta 30501 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 diff --git a/tools/run/BuildTool.hx b/tools/run/BuildTool.hx index af5d950c4..c1c6c3d0f 100644 --- a/tools/run/BuildTool.hx +++ b/tools/run/BuildTool.hx @@ -1,5 +1,5 @@ -import haxe.io.Path; import sys.FileSystem; + #if neko import neko.vm.Thread; import neko.vm.Mutex; @@ -11,905 +11,11 @@ import cpp.vm.Mutex; import cpp.vm.Tls; #end -class DirManager -{ - static var mMade = new Hash(); - - static public function make(inDir:String) - { - var parts = inDir.split("/"); - var total = ""; - for(part in parts) - { - if (part!="." && part!="") - { - if (total!="") total+="/"; - total += part; - if (!mMade.exists(total)) - { - mMade.set(total,true); - if (!FileSystem.exists(total)) - { - try - { - #if haxe3 - FileSystem.createDirectory(total + "/"); - #else - FileSystem.createDirectory(total ); - #end - } catch (e:Dynamic) - { - return false; - } - } - } - } - } - return true; - } - public static function reset() - { - mMade = new Hash(); - } - static public function makeFileDir(inFile:String) - { - var parts = StringTools.replace (inFile, "\\", "/").split("/"); - if (parts.length<2) - return; - parts.pop(); - make(parts.join("/")); - } - - static public function deleteFile(inName:String) - { - if (FileSystem.exists(inName)) - { - BuildTool.log("rm " + inName); - FileSystem.deleteFile(inName); - } - } - - static public function deleteExtension(inExt:String) - { - var contents = FileSystem.readDirectory("."); - for(item in contents) - { - if (item.length > inExt.length && item.substr(item.length-inExt.length)==inExt) - deleteFile(item); - } - } - - static public function deleteRecurse(inDir:String) - { - if (FileSystem.exists(inDir)) - { - var contents = FileSystem.readDirectory(inDir); - for(item in contents) - { - if (item!="." && item!="..") - { - var name = inDir + "/" + item; - if (FileSystem.isDirectory(name)) - deleteRecurse(name); - else - { - BuildTool.log("rm " + name); - FileSystem.deleteFile(name); - } - } - } - BuildTool.log("rmdir " + inDir); - FileSystem.deleteDirectory(inDir); - } - } - -} - -class Compiler -{ - public var mFlags : Array; - public var mCFlags : Array; - public var mMMFlags : Array; - public var mCPPFlags : Array; - public var mOBJCFlags : Array; - public var mPCHFlags : Array; - public var mAddGCCIdentity: Bool; - public var mExe:String; - public var mOutFlag:String; - public var mObjDir:String; - public var mExt:String; - - public var mPCHExt:String; - public var mPCHCreate:String; - public var mPCHUse:String; - public var mPCHFilename:String; - public var mPCH:String; - - public var mGetCompilerVersion:String; - public var mCompilerVersion:String; - public var mCached:Bool; - - public var mID:String; - - public function new(inID,inExe:String,inGCCFileTypes:Bool) - { - mFlags = []; - mCFlags = []; - mCPPFlags = []; - mOBJCFlags = []; - mMMFlags = []; - mPCHFlags = []; - mAddGCCIdentity = inGCCFileTypes; - mCompilerVersion = null; - mObjDir = "obj"; - mOutFlag = "-o"; - mExe = inExe; - mID = inID; - mExt = ".o"; - mPCHExt = ".pch"; - mPCHCreate = "-Yc"; - mPCHUse = "-Yu"; - mPCHFilename = "/Fp"; - mCached = false; - } - - function addIdentity(ext:String,ioArgs:Array) - { - if (mAddGCCIdentity) - { - var identity = switch(ext) - { - case "c" : "c"; - case "m" : "objective-c"; - case "mm" : "objective-c++"; - case "cpp" : "c++"; - case "c++" : "c++"; - default:""; - } - if (identity!="") - { - ioArgs.push("-x"); - ioArgs.push(identity); - } - } - } - - public function setPCH(inPCH:String) - { - mPCH = inPCH; - if (mPCH=="gcc") - { - mPCHExt = ".h.gch"; - mPCHUse = ""; - mPCHFilename = ""; - } - } - - public function needsPchObj() - { - return !mCached && mPCH!="gcc"; - } - - public function createCompilerVersion(inGroup:FileGroup) - { - if (mGetCompilerVersion!=null && mCompilerVersion==null) - { - var exe = mGetCompilerVersion; - var args = new Array(); - if (exe.indexOf (" ") > -1) - { - var splitExe = exe.split(" "); - exe = splitExe.shift(); - args = splitExe.concat(args); - } - - var versionString = Setup.readStderr(exe,args).join(" "); - if (BuildTool.verbose) - { - BuildTool.println("--- Compiler verison ---" ); - BuildTool.println( versionString ); - BuildTool.println("------------------"); - } - - mCompilerVersion = haxe.crypto.Md5.encode(versionString); - mCached = true; - } - - return mCached; - } - - public function precompile(inObjDir:String,inGroup:FileGroup) - { - var header = inGroup.mPrecompiledHeader; - var file = inGroup.getPchName(); - - var args = inGroup.mCompilerFlags.concat(mFlags).concat( mCPPFlags ).concat( mPCHFlags ); - - var dir = inObjDir + "/" + inGroup.getPchDir() + "/"; - var pch_name = dir + file + mPCHExt; - - BuildTool.log("Make pch dir " + dir ); - DirManager.make(dir); - - if (mPCH!="gcc") - { - args.push( mPCHCreate + header + ".h" ); - - // Create a temp file for including ... - var tmp_cpp = dir + file + ".cpp"; - var outFile = sys.io.File.write(tmp_cpp,false); - outFile.writeString("#include <" + header + ".h>\n"); - outFile.close(); - - args.push( tmp_cpp ); - args.push(mPCHFilename + pch_name); - args.push(mOutFlag + dir + file + mExt); - } - else - { - BuildTool.log("Make pch dir " + dir + header ); - DirManager.make(dir + header); - args.push( "-o" ); - args.push(pch_name); - args.push( inGroup.mPrecompiledHeaderDir + "/" + inGroup.mPrecompiledHeader + ".h" ); - } - - - BuildTool.println("Creating " + pch_name + "..."); - var result = BuildTool.runCommand( mExe, args, true, false ); - if (result!=0) - { - if (FileSystem.exists(pch_name)) - FileSystem.deleteFile(pch_name); - throw "Error creating pch: " + result + " - build cancelled"; - } - } - - public function getObjName(inFile:File) - { - var path = new haxe.io.Path(inFile.mName); - var dirId = - haxe.crypto.Md5.encode(BuildTool.targetKey + path.dir).substr(0,8) + "_"; - - return mObjDir + "/" + dirId + path.file + mExt; - } - - public function compile(inFile:File,inTid:Int) - { - var path = new haxe.io.Path(mObjDir + "/" + inFile.mName); - var obj_name = getObjName(inFile); - - var args = new Array(); - - args = args.concat(inFile.mCompilerFlags).concat(inFile.mGroup.mCompilerFlags).concat(mFlags); - - var ext = path.ext.toLowerCase(); - addIdentity(ext,args); - - var allowPch = false; - if (ext=="c") - args = args.concat(mCFlags); - else if (ext=="m") - args = args.concat(mOBJCFlags); - else if (ext=="mm") - args = args.concat(mMMFlags); - else if (ext=="cpp" || ext=="c++") - { - allowPch = true; - args = args.concat(mCPPFlags); - } - - - if (!mCached && inFile.mGroup.mPrecompiledHeader!="" && allowPch) - { - var pchDir = inFile.mGroup.getPchDir(); - if (mPCHUse!="") - { - args.push(mPCHUse + inFile.mGroup.mPrecompiledHeader + ".h"); - args.push(mPCHFilename + mObjDir + "/" + pchDir + "/" + inFile.mGroup.getPchName() + mPCHExt); - } - else - args.unshift("-I"+mObjDir + "/" + pchDir); - } - - - var found = false; - var cacheName:String = null; - if (mCompilerVersion!=null) - { - var sourceName = inFile.mDir + inFile.mName; - var contents = sys.io.File.getContent(sourceName); - if (contents!="") - { - var md5 = haxe.crypto.Md5.encode(contents + args.join(" ") + - inFile.mGroup.mDependHash + mCompilerVersion + inFile.mDependHash ); - cacheName = BuildTool.compileCache + "/" + md5; - if (FileSystem.exists(cacheName)) - { - sys.io.File.copy(cacheName, obj_name); - BuildTool.println("use cache for " + obj_name + "(" + md5 + ")" ); - found = true; - } - else - { - BuildTool.log(" not in cache " + cacheName); - } - } - else - throw "Unkown source contents " + sourceName; - } - - if (!found) - { - args.push( (new haxe.io.Path( inFile.mDir + inFile.mName)).toString() ); - - var out = mOutFlag; - if (out.substr(-1)==" ") - { - args.push(out.substr(0,out.length-1)); - out = ""; - } - - args.push(out + obj_name); - var result = BuildTool.runCommand( mExe, args, true, inTid>=0 ); - if (result!=0) - { - if (FileSystem.exists(obj_name)) - FileSystem.deleteFile(obj_name); - throw "Error : " + result + " - build cancelled"; - } - if (cacheName!=null) - { - sys.io.File.copy(obj_name, cacheName ); - BuildTool.log(" caching " + cacheName); - } - } - - return obj_name; - } -} - - -class Linker -{ - public var mExe:String; - public var mFlags : Array; - public var mOutFlag:String; - public var mExt:String; - public var mNamePrefix:String; - public var mLibDir:String; - public var mRanLib:String; - public var mFromFile:String; - public var mLibs:Array; - public var mExpandArchives : Bool; - public var mRecreate:Bool; - - public function new(inExe:String) - { - mFlags = []; - mOutFlag = "-o"; - mExe = inExe; - mNamePrefix = ""; - mLibDir = ""; - mRanLib = ""; - mExpandArchives = false; - // Default to on... - mFromFile = "@"; - mLibs = []; - mRecreate = false; - } - public function link(inTarget:Target,inObjs:Array,inCompiler:Compiler) - { - var ext = inTarget.mExt=="" ? mExt : inTarget.mExt; - var file_name = mNamePrefix + inTarget.mOutput + ext; - if(!DirManager.make(inTarget.mOutputDir)) - { - throw "Unable to create output directory " + inTarget.mOutputDir; - } - var out_name = inTarget.mOutputDir + file_name; - - var libs = inTarget.mLibs.concat(mLibs); - var v18Added = false; - var isOutOfDateLibs = false; - - for(i in 0...libs.length) - { - var lib = libs[i]; - var parts = lib.split("{MSVC_VER}"); - if (parts.length==2) - { - var ver = ""; - if (BuildTool.isMsvc()) - { - var current = parts[0] + "-" + BuildTool.getMsvcVer() + parts[1]; - if (FileSystem.exists(current)) - { - BuildTool.log("Using current compiler library " + current); - libs[i]=current; - } - else - { - var v18 = parts[0] + "-18" + parts[1]; - if (FileSystem.exists(v18)) - { - BuildTool.log("Using msvc18 compatible library " + v18); - libs[i]=v18; - if (!v18Added) - { - v18Added=true; - libs.push( BuildTool.HXCPP + "/lib/Windows/libmsvccompat-18.lib"); - } - } - else - { - throw "Could not find compatible library for " + lib + ", " + v18 + " does not exist"; - } - } - } - else - libs[i] = parts[0] + parts[1]; - } - if (!isOutOfDateLibs) - { - var lib = libs[i]; - if (FileSystem.exists(lib)) - isOutOfDateLibs = isOutOfDate(out_name,[lib]); - } - } - - - if (isOutOfDateLibs || isOutOfDate(out_name,inObjs) || isOutOfDate(out_name,inTarget.mDepends)) - { - var args = new Array(); - var out = mOutFlag; - if (out.substr(-1)==" ") - { - args.push(out.substr(0,out.length-1)); - out = ""; - } - // Build in temp dir, and then move out so all the crap windows - // creates stays out of the way - if (mLibDir!="") - { - DirManager.make(mLibDir); - args.push(out + mLibDir + "/" + file_name); - } - else - { - if (mRecreate && FileSystem.exists(out_name)) - { - BuildTool.println(" clean " + out_name ); - FileSystem.deleteFile(out_name); - } - args.push(out + out_name); - } - - args = args.concat(mFlags).concat(inTarget.mFlags); - - - var objs = inObjs.copy(); - - if (mExpandArchives) - { - var isArchive = ~/\.a$/; - var libArgs = new Array(); - for(lib in libs) - { - if (isArchive.match(lib)) - { - var libName = Path.withoutDirectory(lib); - var libObjs = Setup.readStdout( mExe , ["t", lib] ); - var objDir = inCompiler.mObjDir + "/" + libName; - DirManager.make(objDir); - var here = Sys.getCwd(); - Sys.setCwd(objDir); - BuildTool.runCommand( mExe , ["x", lib], true, false ); - Sys.setCwd(here); - for(obj in libObjs) - objs.push( objDir+"/"+obj ); - } - else - libArgs.push(lib); - } - libs = libArgs; - } - - - // Place list of obj files in a file called "all_objs" - if (mFromFile=="@") - { - var fname = inCompiler.mObjDir + "/all_objs"; - var fout = sys.io.File.write(fname,false); - for(obj in objs) - fout.writeString(obj + "\n"); - fout.close(); - args.push("@" + fname ); - } - else - args = args.concat(objs); - - args = args.concat(libs); - - var result = BuildTool.runCommand( mExe, args, true, false ); - if (result!=0) - throw "Error : " + result + " - build cancelled"; - - if (mRanLib!="") - { - args = [out_name]; - var result = BuildTool.runCommand( mRanLib, args, true, false ); - if (result!=0) - throw "Error : " + result + " - build cancelled"; - } - - if (mLibDir!="") - { - sys.io.File.copy( mLibDir+"/"+file_name, out_name ); - FileSystem.deleteFile( mLibDir+"/"+file_name ); - } - return out_name; - } - - return ""; - } - function isOutOfDate(inName:String, inObjs:Array) - { - if (!FileSystem.exists(inName)) - return true; - var stamp = FileSystem.stat(inName).mtime.getTime(); - for(obj in inObjs) - { - if (!FileSystem.exists(obj)) - throw "Could not find " + obj + " required by " + inName; - var obj_stamp = FileSystem.stat(obj).mtime.getTime(); - if (obj_stamp > stamp) - return true; - } - return false; - } -} - - - -class Stripper -{ - public var mExe:String; - public var mFlags : Array; - - public function new(inExe:String) - { - mFlags = []; - mExe = inExe; - } - public function strip(inTarget:String) - { - var args = new Array(); - - args = args.concat(mFlags); - - args.push(inTarget); - - var result = BuildTool.runCommand( mExe, args, true,false ); - if (result!=0) - throw "Error : " + result + " - build cancelled"; - } -} - -class File -{ - public function new(inName:String, inGroup:FileGroup) - { - mName = inName; - mDir = inGroup.mDir; - if (mDir!="") mDir += "/"; - // Do not take copy - use reference so it can be updated - mGroup = inGroup; - mDepends = []; - mCompilerFlags = []; - } - public function computeDependHash() - { - mDependHash = ""; - for(depend in mDepends) - mDependHash += getFileHash(depend); - mDependHash = haxe.crypto.Md5.encode(mDependHash); - } - - public static function getFileHash(inName:String) - { - if (mFileHashes.exists(inName)) - return mFileHashes.get(inName); - - var content = sys.io.File.getContent(inName); - var md5 = haxe.crypto.Md5.encode(content); - mFileHashes.set(inName,md5); - return md5; - } - - public function isOutOfDate(inObj:String) - { - if (!FileSystem.exists(inObj)) - return true; - var obj_stamp = FileSystem.stat(inObj).mtime.getTime(); - if (mGroup.isOutOfDate(obj_stamp)) - return true; - - var source_name = mDir+mName; - if (!FileSystem.exists(source_name)) - throw "Could not find source '" + source_name + "'"; - var source_stamp = FileSystem.stat(source_name).mtime.getTime(); - if (obj_stamp < source_stamp) - return true; - for(depend in mDepends) - { - if (!FileSystem.exists(depend)) - throw "Could not find dependency '" + depend + "' for '" + mName + "'"; - if (FileSystem.stat(depend).mtime.getTime() > obj_stamp ) - return true; - } - return false; - } - static var mFileHashes = new Map(); - public var mName:String; - public var mDir:String; - public var mDependHash:String; - public var mDepends:Array; - public var mCompilerFlags:Array; - public var mGroup:FileGroup; -} - - -class HLSL -{ - var file:String; - var profile:String; - var target:String; - var variable:String; - - public function new(inFile:String, inProfile:String, inVariable:String, inTarget:String) - { - file = inFile; - profile = inProfile; - variable = inVariable; - target = inTarget; - } - - public function build() - { - if (!FileSystem.exists (Path.directory (target))) - { - DirManager.make(Path.directory (target)); - } - - DirManager.makeFileDir(target); - - var srcStamp = FileSystem.stat(file).mtime.getTime(); - if ( !FileSystem.exists(target) || FileSystem.stat(target).mtime.getTime() < srcStamp) - { - var exe = "fxc.exe"; - var args = [ "/nologo", "/T", profile, file, "/Vn", variable, "/Fh", target ]; - var result = BuildTool.runCommand(exe,args,BuildTool.verbose,false); - if (result!=0) - { - throw "Error : Could not compile shader " + file + " - build cancelled"; - } - } - } -} - - - -class FileGroup -{ - public function new(inDir:String,inId:String) - { - mNewest = 0; - mFiles = []; - mCompilerFlags = []; - mPrecompiledHeader = ""; - mDepends = []; - mMissingDepends = []; - mOptions = []; - mHLSLs = []; - mDir = inDir; - mId = inId; - } - - public function preBuild() - { - for(hlsl in mHLSLs) - hlsl.build(); - - if (BuildTool.useCache) - { - mDependHash = ""; - for(depend in mDepends) - mDependHash += File.getFileHash(depend); - mDependHash = haxe.crypto.Md5.encode(mDependHash); - } - } - - public function addHLSL(inFile:String,inProfile:String,inVariable:String,inTarget:String) - { - addDepend(inFile); - - mHLSLs.push( new HLSL(inFile,inProfile,inVariable,inTarget) ); - } - - - public function addDepend(inFile:String) - { - if (!FileSystem.exists(inFile)) - { - mMissingDepends.push(inFile); - return; - } - var stamp = FileSystem.stat(inFile).mtime.getTime(); - if (stamp>mNewest) - mNewest = stamp; - - mDepends.push(inFile); - } - - - public function addOptions(inFile:String) - { - mOptions.push(inFile); - } - - public function getPchDir() - { - return "__pch/" + mId ; - } - - public function checkOptions(inObjDir:String) - { - var changed = false; - for(option in mOptions) - { - if (!FileSystem.exists(option)) - { - mMissingDepends.push(option); - } - else - { - var contents = sys.io.File.getContent(option); - - var dest = inObjDir + "/" + haxe.io.Path.withoutDirectory(option); - var skip = false; - - if (FileSystem.exists(dest)) - { - var dest_content = sys.io.File.getContent(dest); - if (dest_content==contents) - skip = true; - } - if (!skip) - { - DirManager.make(inObjDir); - var stream = sys.io.File.write(dest,true); - stream.writeString(contents); - stream.close(); - changed = true; - } - addDepend(dest); - } - } - return changed; - } - - public function checkDependsExist() - { - if (mMissingDepends.length>0) - throw "Could not find dependencies: " + mMissingDepends.join(","); - } - - public function addCompilerFlag(inFlag:String) - { - mCompilerFlags.push(inFlag); - } - - public function isOutOfDate(inStamp:Float) - { - return inStamp; - public var mMissingDepends:Array; - public var mOptions:Array; - public var mPrecompiledHeader:String; - public var mPrecompiledHeaderDir:String; - public var mFiles: Array; - public var mHLSLs: Array; - public var mDir : String; - public var mId : String; - public var mDepends:Array; - public var mDependHash : String; -} - #if haxe3 typedef Hash = haxe.ds.StringMap; #end typedef FileGroups = Hash; - -class Target -{ - public function new(inOutput:String, inTool:String,inToolID:String) - { - mOutput = inOutput; - mOutputDir = ""; - mBuildDir = ""; - mToolID = inToolID; - mTool = inTool; - mFiles = []; - mDepends = []; - mLibs = []; - mFlags = []; - mExt = ""; - mSubTargets = []; - mFileGroups = []; - mFlags = []; - mErrors=[]; - mDirs=[]; - } - - public function addFiles(inGroup:FileGroup) - { - mFiles = mFiles.concat(inGroup.mFiles); - mFileGroups.push(inGroup); - } - public function addError(inError:String) - { - mErrors.push(inError); - } - public function checkError() - { - if (mErrors.length>0) - throw mErrors.join("/"); - } - public function clean() - { - for(dir in mDirs) - { - BuildTool.println("Remove " + dir + "..."); - DirManager.deleteRecurse(dir); - } - } - - public function getKey() - { - return mOutput + mExt; - } - - public var mBuildDir:String; - public var mOutput:String; - public var mOutputDir:String; - public var mTool:String; - public var mToolID:String; - public var mFiles:Array; - public var mFileGroups:Array; - public var mDepends:Array; - public var mSubTargets:Array; - public var mLibs:Array; - public var mFlags:Array; - public var mErrors:Array; - public var mDirs:Array; - public var mExt:String; -} - typedef Targets = Hash; typedef Linkers = Hash; diff --git a/tools/run/Compiler.hx b/tools/run/Compiler.hx new file mode 100644 index 000000000..7bf33325f --- /dev/null +++ b/tools/run/Compiler.hx @@ -0,0 +1,265 @@ +import sys.FileSystem; + +class Compiler +{ + public var mFlags : Array; + public var mCFlags : Array; + public var mMMFlags : Array; + public var mCPPFlags : Array; + public var mOBJCFlags : Array; + public var mPCHFlags : Array; + public var mAddGCCIdentity: Bool; + public var mExe:String; + public var mOutFlag:String; + public var mObjDir:String; + public var mExt:String; + + public var mPCHExt:String; + public var mPCHCreate:String; + public var mPCHUse:String; + public var mPCHFilename:String; + public var mPCH:String; + + public var mGetCompilerVersion:String; + public var mCompilerVersion:String; + public var mCached:Bool; + + public var mID:String; + + public function new(inID,inExe:String,inGCCFileTypes:Bool) + { + mFlags = []; + mCFlags = []; + mCPPFlags = []; + mOBJCFlags = []; + mMMFlags = []; + mPCHFlags = []; + mAddGCCIdentity = inGCCFileTypes; + mCompilerVersion = null; + mObjDir = "obj"; + mOutFlag = "-o"; + mExe = inExe; + mID = inID; + mExt = ".o"; + mPCHExt = ".pch"; + mPCHCreate = "-Yc"; + mPCHUse = "-Yu"; + mPCHFilename = "/Fp"; + mCached = false; + } + + function addIdentity(ext:String,ioArgs:Array) + { + if (mAddGCCIdentity) + { + var identity = switch(ext) + { + case "c" : "c"; + case "m" : "objective-c"; + case "mm" : "objective-c++"; + case "cpp" : "c++"; + case "c++" : "c++"; + default:""; + } + if (identity!="") + { + ioArgs.push("-x"); + ioArgs.push(identity); + } + } + } + + public function setPCH(inPCH:String) + { + mPCH = inPCH; + if (mPCH=="gcc") + { + mPCHExt = ".h.gch"; + mPCHUse = ""; + mPCHFilename = ""; + } + } + + public function needsPchObj() + { + return !mCached && mPCH!="gcc"; + } + + public function createCompilerVersion(inGroup:FileGroup) + { + if (mGetCompilerVersion!=null && mCompilerVersion==null) + { + var exe = mGetCompilerVersion; + var args = new Array(); + if (exe.indexOf (" ") > -1) + { + var splitExe = exe.split(" "); + exe = splitExe.shift(); + args = splitExe.concat(args); + } + + var versionString = Setup.readStderr(exe,args).join(" "); + if (BuildTool.verbose) + { + BuildTool.println("--- Compiler verison ---" ); + BuildTool.println( versionString ); + BuildTool.println("------------------"); + } + + mCompilerVersion = haxe.crypto.Md5.encode(versionString); + mCached = true; + } + + return mCached; + } + + public function precompile(inObjDir:String,inGroup:FileGroup) + { + var header = inGroup.mPrecompiledHeader; + var file = inGroup.getPchName(); + + var args = inGroup.mCompilerFlags.concat(mFlags).concat( mCPPFlags ).concat( mPCHFlags ); + + var dir = inObjDir + "/" + inGroup.getPchDir() + "/"; + var pch_name = dir + file + mPCHExt; + + BuildTool.log("Make pch dir " + dir ); + DirManager.make(dir); + + if (mPCH!="gcc") + { + args.push( mPCHCreate + header + ".h" ); + + // Create a temp file for including ... + var tmp_cpp = dir + file + ".cpp"; + var outFile = sys.io.File.write(tmp_cpp,false); + outFile.writeString("#include <" + header + ".h>\n"); + outFile.close(); + + args.push( tmp_cpp ); + args.push(mPCHFilename + pch_name); + args.push(mOutFlag + dir + file + mExt); + } + else + { + BuildTool.log("Make pch dir " + dir + header ); + DirManager.make(dir + header); + args.push( "-o" ); + args.push(pch_name); + args.push( inGroup.mPrecompiledHeaderDir + "/" + inGroup.mPrecompiledHeader + ".h" ); + } + + + BuildTool.println("Creating " + pch_name + "..."); + var result = BuildTool.runCommand( mExe, args, true, false ); + if (result!=0) + { + if (FileSystem.exists(pch_name)) + FileSystem.deleteFile(pch_name); + throw "Error creating pch: " + result + " - build cancelled"; + } + } + + public function getObjName(inFile:File) + { + var path = new haxe.io.Path(inFile.mName); + var dirId = + haxe.crypto.Md5.encode(BuildTool.targetKey + path.dir).substr(0,8) + "_"; + + return mObjDir + "/" + dirId + path.file + mExt; + } + + public function compile(inFile:File,inTid:Int) + { + var path = new haxe.io.Path(mObjDir + "/" + inFile.mName); + var obj_name = getObjName(inFile); + + var args = new Array(); + + args = args.concat(inFile.mCompilerFlags).concat(inFile.mGroup.mCompilerFlags).concat(mFlags); + + var ext = path.ext.toLowerCase(); + addIdentity(ext,args); + + var allowPch = false; + if (ext=="c") + args = args.concat(mCFlags); + else if (ext=="m") + args = args.concat(mOBJCFlags); + else if (ext=="mm") + args = args.concat(mMMFlags); + else if (ext=="cpp" || ext=="c++") + { + allowPch = true; + args = args.concat(mCPPFlags); + } + + + if (!mCached && inFile.mGroup.mPrecompiledHeader!="" && allowPch) + { + var pchDir = inFile.mGroup.getPchDir(); + if (mPCHUse!="") + { + args.push(mPCHUse + inFile.mGroup.mPrecompiledHeader + ".h"); + args.push(mPCHFilename + mObjDir + "/" + pchDir + "/" + inFile.mGroup.getPchName() + mPCHExt); + } + else + args.unshift("-I"+mObjDir + "/" + pchDir); + } + + + var found = false; + var cacheName:String = null; + if (mCompilerVersion!=null) + { + var sourceName = inFile.mDir + inFile.mName; + var contents = sys.io.File.getContent(sourceName); + if (contents!="") + { + var md5 = haxe.crypto.Md5.encode(contents + args.join(" ") + + inFile.mGroup.mDependHash + mCompilerVersion + inFile.mDependHash ); + cacheName = BuildTool.compileCache + "/" + md5; + if (FileSystem.exists(cacheName)) + { + sys.io.File.copy(cacheName, obj_name); + BuildTool.println("use cache for " + obj_name + "(" + md5 + ")" ); + found = true; + } + else + { + BuildTool.log(" not in cache " + cacheName); + } + } + else + throw "Unkown source contents " + sourceName; + } + + if (!found) + { + args.push( (new haxe.io.Path( inFile.mDir + inFile.mName)).toString() ); + + var out = mOutFlag; + if (out.substr(-1)==" ") + { + args.push(out.substr(0,out.length-1)); + out = ""; + } + + args.push(out + obj_name); + var result = BuildTool.runCommand( mExe, args, true, inTid>=0 ); + if (result!=0) + { + if (FileSystem.exists(obj_name)) + FileSystem.deleteFile(obj_name); + throw "Error : " + result + " - build cancelled"; + } + if (cacheName!=null) + { + sys.io.File.copy(obj_name, cacheName ); + BuildTool.log(" caching " + cacheName); + } + } + + return obj_name; + } +} \ No newline at end of file diff --git a/tools/run/DirManager.hx b/tools/run/DirManager.hx new file mode 100644 index 000000000..73bc2654e --- /dev/null +++ b/tools/run/DirManager.hx @@ -0,0 +1,96 @@ +import sys.FileSystem; +import BuildTool; + +class DirManager +{ + static var mMade = new Hash(); + + static public function make(inDir:String) + { + var parts = inDir.split("/"); + var total = ""; + for(part in parts) + { + if (part!="." && part!="") + { + if (total!="") total+="/"; + total += part; + if (!mMade.exists(total)) + { + mMade.set(total,true); + if (!FileSystem.exists(total)) + { + try + { + #if haxe3 + FileSystem.createDirectory(total + "/"); + #else + FileSystem.createDirectory(total ); + #end + } catch (e:Dynamic) + { + return false; + } + } + } + } + } + return true; + } + public static function reset() + { + mMade = new Hash(); + } + static public function makeFileDir(inFile:String) + { + var parts = StringTools.replace (inFile, "\\", "/").split("/"); + if (parts.length<2) + return; + parts.pop(); + make(parts.join("/")); + } + + static public function deleteFile(inName:String) + { + if (FileSystem.exists(inName)) + { + BuildTool.log("rm " + inName); + FileSystem.deleteFile(inName); + } + } + + static public function deleteExtension(inExt:String) + { + var contents = FileSystem.readDirectory("."); + for(item in contents) + { + if (item.length > inExt.length && item.substr(item.length-inExt.length)==inExt) + deleteFile(item); + } + } + + static public function deleteRecurse(inDir:String) + { + if (FileSystem.exists(inDir)) + { + var contents = FileSystem.readDirectory(inDir); + for(item in contents) + { + if (item!="." && item!="..") + { + var name = inDir + "/" + item; + if (FileSystem.isDirectory(name)) + deleteRecurse(name); + else + { + BuildTool.log("rm " + name); + FileSystem.deleteFile(name); + } + } + } + BuildTool.log("rmdir " + inDir); + FileSystem.deleteDirectory(inDir); + } + } + +} \ No newline at end of file diff --git a/tools/run/File.hx b/tools/run/File.hx new file mode 100644 index 000000000..f78e29748 --- /dev/null +++ b/tools/run/File.hx @@ -0,0 +1,64 @@ +import sys.FileSystem; + +class File +{ + public function new(inName:String, inGroup:FileGroup) + { + mName = inName; + mDir = inGroup.mDir; + if (mDir!="") mDir += "/"; + // Do not take copy - use reference so it can be updated + mGroup = inGroup; + mDepends = []; + mCompilerFlags = []; + } + public function computeDependHash() + { + mDependHash = ""; + for(depend in mDepends) + mDependHash += getFileHash(depend); + mDependHash = haxe.crypto.Md5.encode(mDependHash); + } + + public static function getFileHash(inName:String) + { + if (mFileHashes.exists(inName)) + return mFileHashes.get(inName); + + var content = sys.io.File.getContent(inName); + var md5 = haxe.crypto.Md5.encode(content); + mFileHashes.set(inName,md5); + return md5; + } + + public function isOutOfDate(inObj:String) + { + if (!FileSystem.exists(inObj)) + return true; + var obj_stamp = FileSystem.stat(inObj).mtime.getTime(); + if (mGroup.isOutOfDate(obj_stamp)) + return true; + + var source_name = mDir+mName; + if (!FileSystem.exists(source_name)) + throw "Could not find source '" + source_name + "'"; + var source_stamp = FileSystem.stat(source_name).mtime.getTime(); + if (obj_stamp < source_stamp) + return true; + for(depend in mDepends) + { + if (!FileSystem.exists(depend)) + throw "Could not find dependency '" + depend + "' for '" + mName + "'"; + if (FileSystem.stat(depend).mtime.getTime() > obj_stamp ) + return true; + } + return false; + } + static var mFileHashes = new Map(); + public var mName:String; + public var mDir:String; + public var mDependHash:String; + public var mDepends:Array; + public var mCompilerFlags:Array; + public var mGroup:FileGroup; +} \ No newline at end of file diff --git a/tools/run/FileGroup.hx b/tools/run/FileGroup.hx new file mode 100644 index 000000000..ba04f994a --- /dev/null +++ b/tools/run/FileGroup.hx @@ -0,0 +1,142 @@ +import haxe.io.Path; +import sys.FileSystem; + +class FileGroup +{ + public function new(inDir:String,inId:String) + { + mNewest = 0; + mFiles = []; + mCompilerFlags = []; + mPrecompiledHeader = ""; + mDepends = []; + mMissingDepends = []; + mOptions = []; + mHLSLs = []; + mDir = inDir; + mId = inId; + } + + public function preBuild() + { + for(hlsl in mHLSLs) + hlsl.build(); + + if (BuildTool.useCache) + { + mDependHash = ""; + for(depend in mDepends) + mDependHash += File.getFileHash(depend); + mDependHash = haxe.crypto.Md5.encode(mDependHash); + } + } + + public function addHLSL(inFile:String,inProfile:String,inVariable:String,inTarget:String) + { + addDepend(inFile); + + mHLSLs.push( new HLSL(inFile,inProfile,inVariable,inTarget) ); + } + + + public function addDepend(inFile:String) + { + if (!FileSystem.exists(inFile)) + { + mMissingDepends.push(inFile); + return; + } + var stamp = FileSystem.stat(inFile).mtime.getTime(); + if (stamp>mNewest) + mNewest = stamp; + + mDepends.push(inFile); + } + + + public function addOptions(inFile:String) + { + mOptions.push(inFile); + } + + public function getPchDir() + { + return "__pch/" + mId ; + } + + public function checkOptions(inObjDir:String) + { + var changed = false; + for(option in mOptions) + { + if (!FileSystem.exists(option)) + { + mMissingDepends.push(option); + } + else + { + var contents = sys.io.File.getContent(option); + + var dest = inObjDir + "/" + haxe.io.Path.withoutDirectory(option); + var skip = false; + + if (FileSystem.exists(dest)) + { + var dest_content = sys.io.File.getContent(dest); + if (dest_content==contents) + skip = true; + } + if (!skip) + { + DirManager.make(inObjDir); + var stream = sys.io.File.write(dest,true); + stream.writeString(contents); + stream.close(); + changed = true; + } + addDepend(dest); + } + } + return changed; + } + + public function checkDependsExist() + { + if (mMissingDepends.length>0) + throw "Could not find dependencies: " + mMissingDepends.join(","); + } + + public function addCompilerFlag(inFlag:String) + { + mCompilerFlags.push(inFlag); + } + + public function isOutOfDate(inStamp:Float) + { + return inStamp; + public var mMissingDepends:Array; + public var mOptions:Array; + public var mPrecompiledHeader:String; + public var mPrecompiledHeaderDir:String; + public var mFiles: Array; + public var mHLSLs: Array; + public var mDir : String; + public var mId : String; + public var mDepends:Array; + public var mDependHash : String; +} \ No newline at end of file diff --git a/tools/run/HLSL.hx b/tools/run/HLSL.hx new file mode 100644 index 000000000..b8f412f41 --- /dev/null +++ b/tools/run/HLSL.hx @@ -0,0 +1,40 @@ +import haxe.io.Path; +import sys.FileSystem; + +class HLSL +{ + var file:String; + var profile:String; + var target:String; + var variable:String; + + public function new(inFile:String, inProfile:String, inVariable:String, inTarget:String) + { + file = inFile; + profile = inProfile; + variable = inVariable; + target = inTarget; + } + + public function build() + { + if (!FileSystem.exists (Path.directory (target))) + { + DirManager.make(Path.directory (target)); + } + + DirManager.makeFileDir(target); + + var srcStamp = FileSystem.stat(file).mtime.getTime(); + if ( !FileSystem.exists(target) || FileSystem.stat(target).mtime.getTime() < srcStamp) + { + var exe = "fxc.exe"; + var args = [ "/nologo", "/T", profile, file, "/Vn", variable, "/Fh", target ]; + var result = BuildTool.runCommand(exe,args,BuildTool.verbose,false); + if (result!=0) + { + throw "Error : Could not compile shader " + file + " - build cancelled"; + } + } + } +} \ No newline at end of file diff --git a/tools/run/Linker.hx b/tools/run/Linker.hx new file mode 100644 index 000000000..486400b2b --- /dev/null +++ b/tools/run/Linker.hx @@ -0,0 +1,201 @@ +import haxe.io.Path; +import sys.FileSystem; + +class Linker +{ + public var mExe:String; + public var mFlags : Array; + public var mOutFlag:String; + public var mExt:String; + public var mNamePrefix:String; + public var mLibDir:String; + public var mRanLib:String; + public var mFromFile:String; + public var mLibs:Array; + public var mExpandArchives : Bool; + public var mRecreate:Bool; + + public function new(inExe:String) + { + mFlags = []; + mOutFlag = "-o"; + mExe = inExe; + mNamePrefix = ""; + mLibDir = ""; + mRanLib = ""; + mExpandArchives = false; + // Default to on... + mFromFile = "@"; + mLibs = []; + mRecreate = false; + } + public function link(inTarget:Target,inObjs:Array,inCompiler:Compiler) + { + var ext = inTarget.mExt=="" ? mExt : inTarget.mExt; + var file_name = mNamePrefix + inTarget.mOutput + ext; + if(!DirManager.make(inTarget.mOutputDir)) + { + throw "Unable to create output directory " + inTarget.mOutputDir; + } + var out_name = inTarget.mOutputDir + file_name; + + var libs = inTarget.mLibs.concat(mLibs); + var v18Added = false; + var isOutOfDateLibs = false; + + for(i in 0...libs.length) + { + var lib = libs[i]; + var parts = lib.split("{MSVC_VER}"); + if (parts.length==2) + { + var ver = ""; + if (BuildTool.isMsvc()) + { + var current = parts[0] + "-" + BuildTool.getMsvcVer() + parts[1]; + if (FileSystem.exists(current)) + { + BuildTool.log("Using current compiler library " + current); + libs[i]=current; + } + else + { + var v18 = parts[0] + "-18" + parts[1]; + if (FileSystem.exists(v18)) + { + BuildTool.log("Using msvc18 compatible library " + v18); + libs[i]=v18; + if (!v18Added) + { + v18Added=true; + libs.push( BuildTool.HXCPP + "/lib/Windows/libmsvccompat-18.lib"); + } + } + else + { + throw "Could not find compatible library for " + lib + ", " + v18 + " does not exist"; + } + } + } + else + libs[i] = parts[0] + parts[1]; + } + if (!isOutOfDateLibs) + { + var lib = libs[i]; + if (FileSystem.exists(lib)) + isOutOfDateLibs = isOutOfDate(out_name,[lib]); + } + } + + + if (isOutOfDateLibs || isOutOfDate(out_name,inObjs) || isOutOfDate(out_name,inTarget.mDepends)) + { + var args = new Array(); + var out = mOutFlag; + if (out.substr(-1)==" ") + { + args.push(out.substr(0,out.length-1)); + out = ""; + } + // Build in temp dir, and then move out so all the crap windows + // creates stays out of the way + if (mLibDir!="") + { + DirManager.make(mLibDir); + args.push(out + mLibDir + "/" + file_name); + } + else + { + if (mRecreate && FileSystem.exists(out_name)) + { + BuildTool.println(" clean " + out_name ); + FileSystem.deleteFile(out_name); + } + args.push(out + out_name); + } + + args = args.concat(mFlags).concat(inTarget.mFlags); + + + var objs = inObjs.copy(); + + if (mExpandArchives) + { + var isArchive = ~/\.a$/; + var libArgs = new Array(); + for(lib in libs) + { + if (isArchive.match(lib)) + { + var libName = Path.withoutDirectory(lib); + var libObjs = Setup.readStdout( mExe , ["t", lib] ); + var objDir = inCompiler.mObjDir + "/" + libName; + DirManager.make(objDir); + var here = Sys.getCwd(); + Sys.setCwd(objDir); + BuildTool.runCommand( mExe , ["x", lib], true, false ); + Sys.setCwd(here); + for(obj in libObjs) + objs.push( objDir+"/"+obj ); + } + else + libArgs.push(lib); + } + libs = libArgs; + } + + + // Place list of obj files in a file called "all_objs" + if (mFromFile=="@") + { + var fname = inCompiler.mObjDir + "/all_objs"; + var fout = sys.io.File.write(fname,false); + for(obj in objs) + fout.writeString(obj + "\n"); + fout.close(); + args.push("@" + fname ); + } + else + args = args.concat(objs); + + args = args.concat(libs); + + var result = BuildTool.runCommand( mExe, args, true, false ); + if (result!=0) + throw "Error : " + result + " - build cancelled"; + + if (mRanLib!="") + { + args = [out_name]; + var result = BuildTool.runCommand( mRanLib, args, true, false ); + if (result!=0) + throw "Error : " + result + " - build cancelled"; + } + + if (mLibDir!="") + { + sys.io.File.copy( mLibDir+"/"+file_name, out_name ); + FileSystem.deleteFile( mLibDir+"/"+file_name ); + } + return out_name; + } + + return ""; + } + function isOutOfDate(inName:String, inObjs:Array) + { + if (!FileSystem.exists(inName)) + return true; + var stamp = FileSystem.stat(inName).mtime.getTime(); + for(obj in inObjs) + { + if (!FileSystem.exists(obj)) + throw "Could not find " + obj + " required by " + inName; + var obj_stamp = FileSystem.stat(obj).mtime.getTime(); + if (obj_stamp > stamp) + return true; + } + return false; + } +} \ No newline at end of file diff --git a/tools/run/Stripper.hx b/tools/run/Stripper.hx new file mode 100644 index 000000000..11abb9775 --- /dev/null +++ b/tools/run/Stripper.hx @@ -0,0 +1,23 @@ +class Stripper +{ + public var mExe:String; + public var mFlags : Array; + + public function new(inExe:String) + { + mFlags = []; + mExe = inExe; + } + public function strip(inTarget:String) + { + var args = new Array(); + + args = args.concat(mFlags); + + args.push(inTarget); + + var result = BuildTool.runCommand( mExe, args, true,false ); + if (result!=0) + throw "Error : " + result + " - build cancelled"; + } +} \ No newline at end of file diff --git a/tools/run/Target.hx b/tools/run/Target.hx new file mode 100644 index 000000000..83ab8afe2 --- /dev/null +++ b/tools/run/Target.hx @@ -0,0 +1,64 @@ +class Target +{ + public function new(inOutput:String, inTool:String,inToolID:String) + { + mOutput = inOutput; + mOutputDir = ""; + mBuildDir = ""; + mToolID = inToolID; + mTool = inTool; + mFiles = []; + mDepends = []; + mLibs = []; + mFlags = []; + mExt = ""; + mSubTargets = []; + mFileGroups = []; + mFlags = []; + mErrors=[]; + mDirs=[]; + } + + public function addFiles(inGroup:FileGroup) + { + mFiles = mFiles.concat(inGroup.mFiles); + mFileGroups.push(inGroup); + } + public function addError(inError:String) + { + mErrors.push(inError); + } + public function checkError() + { + if (mErrors.length>0) + throw mErrors.join("/"); + } + public function clean() + { + for(dir in mDirs) + { + BuildTool.println("Remove " + dir + "..."); + DirManager.deleteRecurse(dir); + } + } + + public function getKey() + { + return mOutput + mExt; + } + + public var mBuildDir:String; + public var mOutput:String; + public var mOutputDir:String; + public var mTool:String; + public var mToolID:String; + public var mFiles:Array; + public var mFileGroups:Array; + public var mDepends:Array; + public var mSubTargets:Array; + public var mLibs:Array; + public var mFlags:Array; + public var mErrors:Array; + public var mDirs:Array; + public var mExt:String; +} \ No newline at end of file From 316be8d5be1933e9cab9ec4b94ef3e05a5204357 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Mon, 24 Mar 2014 10:35:02 -0700 Subject: [PATCH 2/6] More consistent code style --- tools/run/BuildTool.hx | 905 ++++++++++++++++++++-------------------- tools/run/Compiler.hx | 220 +++++----- tools/run/DirManager.hx | 91 ++-- tools/run/File.hx | 16 +- tools/run/FileGroup.hx | 86 ++-- tools/run/HLSL.hx | 12 +- tools/run/Linker.hx | 39 +- tools/run/Setup.hx | 312 +++++++------- tools/run/Stripper.hx | 5 +- tools/run/Target.hx | 41 +- 10 files changed, 852 insertions(+), 875 deletions(-) diff --git a/tools/run/BuildTool.hx b/tools/run/BuildTool.hx index c1c6c3d0f..7587fabf5 100644 --- a/tools/run/BuildTool.hx +++ b/tools/run/BuildTool.hx @@ -1,5 +1,5 @@ +import haxe.xml.Fast; import sys.FileSystem; - #if neko import neko.vm.Thread; import neko.vm.Mutex; @@ -14,20 +14,19 @@ import cpp.vm.Tls; #if haxe3 typedef Hash = haxe.ds.StringMap; #end - typedef FileGroups = Hash; typedef Targets = Hash; typedef Linkers = Hash; class BuildTool { - var mDefines : Hash; + var mDefines:Hash; var mIncludePath:Array; - var mCompiler : Compiler; - var mStripper : Stripper; - var mLinkers : Linkers; - var mFileGroups : FileGroups; - var mTargets : Targets; + var mCompiler:Compiler; + var mStripper:Stripper; + var mLinkers:Linkers; + var mFileGroups:FileGroups; + var mTargets:Targets; public static var sAllowNumProcs = true; public static var HXCPP = ""; public static var verbose = false; @@ -40,7 +39,7 @@ class BuildTool public static var helperThread = new Tls(); public static var instance:BuildTool; static var printMutex:Mutex; - + static var mVarMatch = new EReg("\\${(.*?)}",""); public function new(inMakefile:String,inDefines:Hash,inTargets:Array, inIncludePath:Array ) @@ -55,7 +54,7 @@ class BuildTool mIncludePath = inIncludePath; instance = this; var make_contents = ""; - try { + try { make_contents = sys.io.File.getContent(inMakefile); } catch (e:Dynamic) { println("Could not open build file '" + inMakefile + "'"); @@ -66,7 +65,7 @@ class BuildTool mDefines.set("HXCPP_COMPILE_THREADS", Std.string(getNumberOfProcesses())); var xml_slow = Xml.parse(make_contents); - var xml = new haxe.xml.Fast(xml_slow.firstElement()); + var xml = new Fast(xml_slow.firstElement()); parseXML(xml,""); @@ -115,268 +114,6 @@ class BuildTool buildTarget(target); } - public static function isMsvc() - { - return instance.mDefines.get("toolchain")=="msvc"; - } - static public function getMsvcVer() - { - return instance.mDefines.get("MSVC_VER"); - } - - inline public static function log(s:String) - { - if (verbose) - Sys.println(s); - } - - - - inline public static function println(s:String) - { - Sys.println(s); - } - - - function findIncludeFile(inBase:String) : String - { - if (inBase=="") return ""; - var c0 = inBase.substr(0,1); - if (c0!="/" && c0!="\\") - { - var c1 = inBase.substr(1,1); - if (c1!=":") - { - for(p in mIncludePath) - { - var name = p + "/" + inBase; - if (FileSystem.exists(name)) - return name; - } - return ""; - } - } - if (FileSystem.exists(inBase)) - return inBase; - return ""; - } - - function parseXML(inXML:haxe.xml.Fast,inSection :String) - { - for(el in inXML.elements) - { - if (valid(el,inSection)) - { - switch(el.name) - { - case "set" : - var name = el.att.name; - var value = substitute(el.att.value); - mDefines.set(name,value); - if (name == "BLACKBERRY_NDK_ROOT") - { - Setup.setupBlackBerryNativeSDK(mDefines); - } - case "unset" : - var name = el.att.name; - mDefines.remove(name); - case "setup" : - var name = substitute(el.att.name); - Setup.setup(name,mDefines); - case "echo" : - Sys.println(substitute(el.att.value)); - case "setenv" : - var name = el.att.name; - var value = substitute(el.att.value); - mDefines.set(name,value); - Sys.putEnv(name,value); - case "error" : - var error = substitute(el.att.value); - throw(error); - case "path" : - var path = substitute(el.att.name); - if (verbose) - println("Adding path " + path ); - var os = Sys.systemName(); - var sep = mDefines.exists("windows_host") ? ";" : ":"; - var add = path + sep + Sys.getEnv("PATH"); - Sys.putEnv("PATH", add); - //trace(Sys.getEnv("PATH")); - case "compiler" : - mCompiler = createCompiler(el,mCompiler); - - case "stripper" : - mStripper = createStripper(el,mStripper); - - case "linker" : - if (mLinkers.exists(el.att.id)) - createLinker(el,mLinkers.get(el.att.id)); - else - mLinkers.set( el.att.id, createLinker(el,null) ); - - case "files" : - var name = el.att.id; - if (mFileGroups.exists(name)) - createFileGroup(el, mFileGroups.get(name), name); - else - mFileGroups.set(name,createFileGroup(el,null,name)); - - case "include" : - var name = substitute(el.att.name); - var full_name = findIncludeFile(name); - if (full_name!="") - { - var make_contents = sys.io.File.getContent(full_name); - var xml_slow = Xml.parse(make_contents); - var section = el.has.section ? el.att.section : ""; - - parseXML(new haxe.xml.Fast(xml_slow.firstElement()),section); - } - else if (!el.has.noerror) - { - throw "Could not find include file " + name; - } - case "target" : - var name = substitute(el.att.id); - var overwrite = name=="default"; - if (el.has.overwrite) - overwrite = true; - if (el.has.append) - overwrite = false; - if (mTargets.exists(name) && !overwrite) - createTarget(el,mTargets.get(name)); - else - mTargets.set( name, createTarget(el,null) ); - case "section" : - parseXML(el,""); - } - } - } - } - - - public static function runCommand(exe:String, args:Array,inPrint:Bool, inMultiThread:Bool ):Int - { - if (exe.indexOf (" ") > -1) - { - var splitExe = exe.split (" "); - exe = splitExe.shift (); - args = splitExe.concat (args); - } - - var useSysCommand = !inMultiThread; - - if ( useSysCommand ) - { - if (inPrint) - println(exe + " " + args.join(" ")); - return Sys.command(exe,args); - } - else - { - var output = new Array(); - if (inPrint) - output.push(exe + " " + args.join(" ")); - var proc = new sys.io.Process(exe, args); - var err = proc.stderr; - var out = proc.stdout; - var reader = BuildTool.helperThread.value; - // Read stderr in separate hreead to avoid blocking ... - if (reader==null) - { - var contoller = Thread.current(); - BuildTool.helperThread.value = reader = Thread.create(function() - { - while(true) - { - var stream = Thread.readMessage(true); - var output:Array = null; - try - { - while(true) - { - var line = stream.readLine(); - if (output==null) - output = [ line ]; - else - output.push(line); - } - } - catch(e:Dynamic){ } - contoller.sendMessage(output); - } - }); - } - - // Start up the error reader ... - reader.sendMessage(err); - - try - { - while(true) - { - var line = out.readLine(); - output.push(line); - } - } - catch(e:Dynamic){ } - - var errOut:Array = Thread.readMessage(true); - - if (errOut!=null && errOut.length>0) - output = output.concat(errOut); - - if (output.length>0) - { - if (printMutex!=null) - printMutex.acquire(); - println(output.join("\n")); - if (printMutex!=null) - printMutex.release(); - } - - var code = proc.exitCode(); - proc.close(); - return code; - } - } - - public function cleanTarget(inTarget:String,allObj:Bool) - { - // Sys.println("Build : " + inTarget ); - if (!mTargets.exists(inTarget)) - throw "Could not find target '" + inTarget + "' to build."; - if (mCompiler==null) - throw "No compiler defined"; - - var target = mTargets.get(inTarget); - target.checkError(); - - for(sub in target.mSubTargets) - cleanTarget(sub,allObj); - - var restoreDir = ""; - if (target.mBuildDir!="") - { - restoreDir = Sys.getCwd(); - if (verbose) - Sys.println("Enter " + target.mBuildDir); - Sys.setCwd(target.mBuildDir); - } - - DirManager.deleteRecurse(mCompiler.mObjDir); - DirManager.deleteFile("all_objs"); - DirManager.deleteExtension(".pdb"); - if (allObj) - DirManager.deleteRecurse("obj"); - - if (restoreDir!="") - Sys.setCwd(restoreDir); - } - - - - public function buildTarget(inTarget:String) { // Sys.println("Build : " + inTarget ); @@ -454,9 +191,9 @@ class BuildTool { var pchDir = group.getPchDir(); if (pchDir != "") - { + { objs.push(mCompiler.mObjDir + "/" + pchDir + "/" + group.getPchName() + mCompiler.mExt); - } + } } } @@ -525,7 +262,40 @@ class BuildTool Sys.setCwd(restoreDir); } - public function createCompiler(inXML:haxe.xml.Fast,inBase:Compiler) : Compiler + public function cleanTarget(inTarget:String,allObj:Bool) + { + // Sys.println("Build : " + inTarget ); + if (!mTargets.exists(inTarget)) + throw "Could not find target '" + inTarget + "' to build."; + if (mCompiler==null) + throw "No compiler defined"; + + var target = mTargets.get(inTarget); + target.checkError(); + + for(sub in target.mSubTargets) + cleanTarget(sub,allObj); + + var restoreDir = ""; + if (target.mBuildDir!="") + { + restoreDir = Sys.getCwd(); + if (verbose) + Sys.println("Enter " + target.mBuildDir); + Sys.setCwd(target.mBuildDir); + } + + DirManager.deleteRecurse(mCompiler.mObjDir); + DirManager.deleteFile("all_objs"); + DirManager.deleteExtension(".pdb"); + if (allObj) + DirManager.deleteRecurse("obj"); + + if (restoreDir!="") + Sys.setCwd(restoreDir); + } + + public function createCompiler(inXML:Fast,inBase:Compiler) : Compiler { var c = inBase; if (inBase==null || inXML.has.replace) @@ -540,63 +310,74 @@ class BuildTool if (valid(el,"")) switch(el.name) { - case "flag" : c.mFlags.push(substitute(el.att.value)); - case "cflag" : c.mCFlags.push(substitute(el.att.value)); - case "cppflag" : c.mCPPFlags.push(substitute(el.att.value)); - case "objcflag" : c.mOBJCFlags.push(substitute(el.att.value)); - case "mmflag" : c.mMMFlags.push(substitute(el.att.value)); - case "pchflag" : c.mPCHFlags.push(substitute(el.att.value)); - case "objdir" : c.mObjDir = substitute((el.att.value)); - case "outflag" : c.mOutFlag = substitute((el.att.value)); - case "exe" : c.mExe = substitute((el.att.name)); - case "ext" : c.mExt = substitute((el.att.value)); - case "pch" : c.setPCH( substitute((el.att.value)) ); - case "getversion" : c.mGetCompilerVersion = substitute((el.att.value)); - case "section" : - createCompiler(el,c); - case "include" : - var name = substitute(el.att.name); - var full_name = findIncludeFile(name); - if (full_name!="") - { - var make_contents = sys.io.File.getContent(full_name); - var xml_slow = Xml.parse(make_contents); - createCompiler(new haxe.xml.Fast(xml_slow.firstElement()),c); - } - else if (!el.has.noerror) - { - throw "Could not find include file " + name; - } + case "flag" : c.mFlags.push(substitute(el.att.value)); + case "cflag" : c.mCFlags.push(substitute(el.att.value)); + case "cppflag" : c.mCPPFlags.push(substitute(el.att.value)); + case "objcflag" : c.mOBJCFlags.push(substitute(el.att.value)); + case "mmflag" : c.mMMFlags.push(substitute(el.att.value)); + case "pchflag" : c.mPCHFlags.push(substitute(el.att.value)); + case "objdir" : c.mObjDir = substitute((el.att.value)); + case "outflag" : c.mOutFlag = substitute((el.att.value)); + case "exe" : c.mExe = substitute((el.att.name)); + case "ext" : c.mExt = substitute((el.att.value)); + case "pch" : c.setPCH( substitute((el.att.value)) ); + case "getversion" : c.mGetCompilerVersion = substitute((el.att.value)); + case "section" : createCompiler(el,c); + case "include" : + var name = substitute(el.att.name); + var full_name = findIncludeFile(name); + if (full_name!="") + { + var make_contents = sys.io.File.getContent(full_name); + var xml_slow = Xml.parse(make_contents); + createCompiler(new haxe.xml.Fast(xml_slow.firstElement()),c); + } + else if (!el.has.noerror) + { + throw "Could not find include file " + name; + } default: - throw "Unknown compiler option: '" + el.name + "'"; - - + throw "Unknown compiler option: '" + el.name + "'"; } } return c; } - public function createStripper(inXML:haxe.xml.Fast,inBase:Stripper) : Stripper + public function createFileGroup(inXML:Fast,inFiles:FileGroup,inName:String):FileGroup { - var s = (inBase!=null && !inXML.has.replace) ? inBase : - new Stripper(inXML.att.exe); + var dir = inXML.has.dir ? substitute(inXML.att.dir) : "."; + var group = inFiles==null ? new FileGroup(dir,inName) : inFiles; for(el in inXML.elements) { if (valid(el,"")) switch(el.name) { - case "flag" : s.mFlags.push(substitute(el.att.value)); - case "exe" : s.mExe = substitute((el.att.name)); + case "file" : + var file = new File(substitute(el.att.name),group); + for(f in el.elements) + if (valid(f,"") && f.name=="depend") + file.mDepends.push( substitute(f.att.name) ); + group.mFiles.push( file ); + case "section" : createFileGroup(el,group,inName); + case "depend" : group.addDepend( substitute(el.att.name) ); + case "hlsl" : + group.addHLSL( substitute(el.att.name), substitute(el.att.profile), + substitute(el.att.variable), substitute(el.att.target) ); + case "options" : group.addOptions( substitute(el.att.name) ); + case "compilerflag" : group.addCompilerFlag( substitute(el.att.value) ); + case "compilervalue" : + group.addCompilerFlag( substitute(el.att.name) ); + group.addCompilerFlag( substitute(el.att.value) ); + case "precompiledheader" : + group.setPrecompiled( substitute(el.att.name), substitute(el.att.dir) ); } } - return s; + return group; } - - - public function createLinker(inXML:haxe.xml.Fast,inBase:Linker) : Linker + public function createLinker(inXML:Fast,inBase:Linker):Linker { var l = (inBase!=null && !inXML.has.replace) ? inBase : new Linker(inXML.att.exe); for(el in inXML.elements) @@ -604,56 +385,41 @@ class BuildTool if (valid(el,"")) switch(el.name) { - case "flag" : l.mFlags.push(substitute(el.att.value)); - case "ext" : l.mExt = (substitute(el.att.value)); - case "outflag" : l.mOutFlag = (substitute(el.att.value)); - case "libdir" : l.mLibDir = (substitute(el.att.name)); - case "lib" : l.mLibs.push( substitute(el.att.name) ); - case "prefix" : l.mNamePrefix = substitute(el.att.value); - case "ranlib" : l.mRanLib = (substitute(el.att.name)); - case "recreate" : l.mRecreate = (substitute(el.att.value)) != ""; - case "expandAr" : l.mExpandArchives = substitute(el.att.value) != ""; - case "fromfile" : l.mFromFile = (substitute(el.att.value)); - case "exe" : l.mExe = (substitute(el.att.name)); - case "section" : createLinker(el,l); + case "flag" : l.mFlags.push(substitute(el.att.value)); + case "ext" : l.mExt = (substitute(el.att.value)); + case "outflag" : l.mOutFlag = (substitute(el.att.value)); + case "libdir" : l.mLibDir = (substitute(el.att.name)); + case "lib" : l.mLibs.push( substitute(el.att.name) ); + case "prefix" : l.mNamePrefix = substitute(el.att.value); + case "ranlib" : l.mRanLib = (substitute(el.att.name)); + case "recreate" : l.mRecreate = (substitute(el.att.value)) != ""; + case "expandAr" : l.mExpandArchives = substitute(el.att.value) != ""; + case "fromfile" : l.mFromFile = (substitute(el.att.value)); + case "exe" : l.mExe = (substitute(el.att.name)); + case "section" : createLinker(el,l); } } return l; } - public function createFileGroup(inXML:haxe.xml.Fast,inFiles:FileGroup,inName:String) : FileGroup + public function createStripper(inXML:Fast,inBase:Stripper):Stripper { - var dir = inXML.has.dir ? substitute(inXML.att.dir) : "."; - var group = inFiles==null ? new FileGroup(dir,inName) : inFiles; + var s = (inBase!=null && !inXML.has.replace) ? inBase : + new Stripper(inXML.att.exe); for(el in inXML.elements) { if (valid(el,"")) switch(el.name) { - case "file" : - var file = new File(substitute(el.att.name),group); - for(f in el.elements) - if (valid(f,"") && f.name=="depend") - file.mDepends.push( substitute(f.att.name) ); - group.mFiles.push( file ); - case "section" : createFileGroup(el,group,inName); - case "depend" : group.addDepend( substitute(el.att.name) ); - case "hlsl" : group.addHLSL( substitute(el.att.name), substitute(el.att.profile), - substitute(el.att.variable), substitute(el.att.target) ); - case "options" : group.addOptions( substitute(el.att.name) ); - case "compilerflag" : group.addCompilerFlag( substitute(el.att.value) ); - case "compilervalue" : group.addCompilerFlag( substitute(el.att.name) ); - group.addCompilerFlag( substitute(el.att.value) ); - case "precompiledheader" : group.setPrecompiled( substitute(el.att.name), - substitute(el.att.dir) ); + case "flag" : s.mFlags.push(substitute(el.att.value)); + case "exe" : s.mExe = substitute((el.att.name)); } } - return group; + return s; } - public function createTarget(inXML:haxe.xml.Fast,?inTarget:Target) : Target { var target:Target = inTarget; @@ -670,61 +436,61 @@ class BuildTool if (valid(el,"")) switch(el.name) { - case "target" : target.mSubTargets.push( substitute(el.att.id) ); - case "lib" : target.mLibs.push( substitute(el.att.name) ); - case "flag" : target.mFlags.push( substitute(el.att.value) ); - case "depend" : target.mDepends.push( substitute(el.att.name) ); - case "vflag" : target.mFlags.push( substitute(el.att.name) ); - target.mFlags.push( substitute(el.att.value) ); - case "dir" : target.mDirs.push( substitute(el.att.name) ); - case "outdir" : target.mOutputDir = substitute(el.att.name)+"/"; - case "ext" : target.mExt = (substitute(el.att.value)); - case "builddir" : target.mBuildDir = substitute(el.att.name); - case "files" : var id = el.att.id; - if (!mFileGroups.exists(id)) - target.addError( "Could not find filegroup " + id ); - else - target.addFiles( mFileGroups.get(id) ); - case "section" : createTarget(el,target); + case "target" : target.mSubTargets.push( substitute(el.att.id) ); + case "lib" : target.mLibs.push( substitute(el.att.name) ); + case "flag" : target.mFlags.push( substitute(el.att.value) ); + case "depend" : target.mDepends.push( substitute(el.att.name) ); + case "vflag" : + target.mFlags.push( substitute(el.att.name) ); + target.mFlags.push( substitute(el.att.value) ); + case "dir" : target.mDirs.push( substitute(el.att.name) ); + case "outdir" : target.mOutputDir = substitute(el.att.name)+"/"; + case "ext" : target.mExt = (substitute(el.att.value)); + case "builddir" : target.mBuildDir = substitute(el.att.name); + case "files" : + var id = el.att.id; + if (!mFileGroups.exists(id)) + target.addError( "Could not find filegroup " + id ); + else + target.addFiles( mFileGroups.get(id) ); + case "section" : createTarget(el,target); } } return target; } - - public function valid(inEl:haxe.xml.Fast,inSection:String) : Bool + public function defined(inString:String):Bool { - if (inEl.x.get("if")!=null) - if (!defined(inEl.x.get("if"))) return false; - - if (inEl.has.unless) - if (defined(inEl.att.unless)) return false; - - if (inEl.has.ifExists) - if (!FileSystem.exists( substitute(inEl.att.ifExists) )) return false; - - if (inSection!="") - { - if (inEl.name!="section") - return false; - if (!inEl.has.id) - return false; - if (inEl.att.id!=inSection) - return false; - } - - return true; + return mDefines.exists(inString); } - public function defined(inString:String) : Bool + function findIncludeFile(inBase:String):String { - return mDefines.exists(inString); + if (inBase=="") return ""; + var c0 = inBase.substr(0,1); + if (c0!="/" && c0!="\\") + { + var c1 = inBase.substr(1,1); + if (c1!=":") + { + for(p in mIncludePath) + { + var name = p + "/" + inBase; + if (FileSystem.exists(name)) + return name; + } + return ""; + } + } + if (FileSystem.exists(inBase)) + return inBase; + return ""; } public static function getHaxelib(library:String):String { - var proc = new sys.io.Process("haxelib",["path",library]); + var proc = new Process("haxelib",["path",library]); var result = ""; try { @@ -747,7 +513,12 @@ class BuildTool return result; } - + + static public function getMsvcVer() + { + return instance.mDefines.get("MSVC_VER"); + } + // Setting HXCPP_COMPILE_THREADS to 2x number or cores can help with hyperthreading public static function getNumberOfProcesses():String { @@ -759,7 +530,7 @@ class BuildTool if (isLinux) { var proc = null; - proc = new sys.io.Process("nproc",[]); + proc = new Process("nproc",[]); try { result = proc.stdout.readLine(); @@ -768,7 +539,7 @@ class BuildTool } else if (isMac) { - var proc = new sys.io.Process("/usr/sbin/system_profiler", ["-detailLevel", "full", "SPHardwareDataType"]); + var proc = new Process("/usr/sbin/system_profiler", ["-detailLevel", "full", "SPHardwareDataType"]); var cores = ~/Total Number of Cores: (\d+)/; try { @@ -787,42 +558,18 @@ class BuildTool } return result; } - - static var mVarMatch = new EReg("\\${(.*?)}",""); - public function substitute(str:String) : String - { - while( mVarMatch.match(str) ) - { - var sub = mVarMatch.matched(1); - if (sub.substr(0,8)=="haxelib:") - { - sub = getHaxelib(sub.substr(8)); - } - else - sub = mDefines.get(sub); - if (sub==null) sub=""; - str = mVarMatch.matchedLeft() + sub + mVarMatch.matchedRight(); - } - - return str; + public static function isMsvc() + { + return instance.mDefines.get("toolchain")=="msvc"; } - static function set64(outDefines:Hash, in64:Bool) + inline public static function log(s:String) { - if (in64) - { - outDefines.set("HXCPP_M64","1"); - outDefines.remove("HXCPP_32"); - } - else - { - outDefines.set("HXCPP_M32","1"); - outDefines.remove("HXCPP_M64"); - } + if (verbose) + Sys.println(s); } - - + // Process args and environment. static public function main() { @@ -857,18 +604,17 @@ class BuildTool } var os = Sys.systemName(); isWindows = (new EReg("window","i")).match(os); - if (isWindows) - defines.set("windows_host", "1"); + if (isWindows) + defines.set("windows_host", "1"); isMac = (new EReg("mac","i")).match(os); - if (isMac) - defines.set("mac_host", "1"); + if (isMac) + defines.set("mac_host", "1"); isLinux = (new EReg("linux","i")).match(os); - if (isLinux) - defines.set("linux_host", "1"); + if (isLinux) + defines.set("linux_host", "1"); var isRPi = isLinux && Setup.isRaspberryPi(); - for(arg in args) { if (arg.substr(0,2)=="-D") @@ -911,7 +657,6 @@ class BuildTool if (verbose) BuildTool.println("HXCPP : " + HXCPP); - include_path.push("."); if (env.exists("HOME")) include_path.push(env.get("HOME")); @@ -930,22 +675,22 @@ class BuildTool } var msvc = false; - - if (defines.exists("ios")) - { - if (defines.exists("simulator")) - { - defines.set("iphonesim", "iphonesim"); - } - else if (!defines.exists ("iphonesim")) - { - defines.set("iphoneos", "iphoneos"); - } - } + + if (defines.exists("ios")) + { + if (defines.exists("simulator")) + { + defines.set("iphonesim", "iphonesim"); + } + else if (!defines.exists ("iphonesim")) + { + defines.set("iphoneos", "iphoneos"); + } + } if (defines.exists("iphoneos")) { - defines.set("toolchain","iphoneos"); + defines.set("toolchain","iphoneos"); defines.set("iphone","iphone"); defines.set("apple","apple"); defines.set("BINDIR","iPhone"); @@ -994,26 +739,26 @@ class BuildTool defines.set("tizen","tizen"); defines.set("BINDIR","Tizen"); } - else if (defines.exists("blackberry")) + else if (defines.exists("blackberry")) { - if (defines.exists("simulator")) - { - defines.set("toolchain", "blackberry-x86"); - } - else - { - defines.set("toolchain", "blackberry"); - } + if (defines.exists("simulator")) + { + defines.set("toolchain", "blackberry-x86"); + } + else + { + defines.set("toolchain", "blackberry"); + } defines.set("blackberry","blackberry"); defines.set("BINDIR","BlackBerry"); } - else if (defines.exists("emcc") || defines.exists("emscripten")) - { + else if (defines.exists("emcc") || defines.exists("emscripten")) + { defines.set("toolchain","emscripten"); - defines.set("emcc","emcc"); - defines.set("emscripten","emscripten"); - defines.set("BINDIR","Emscripten"); - } + defines.set("emcc","emcc"); + defines.set("emscripten","emscripten"); + defines.set("BINDIR","Emscripten"); + } else if (defines.exists("gph")) { defines.set("toolchain","gph"); @@ -1116,7 +861,7 @@ class BuildTool var developer_dir = proc.stdout.readLine(); proc.close(); if (developer_dir == "" || developer_dir.indexOf ("Run xcode-select") > -1) - developer_dir = "/Applications/Xcode.app/Contents/Developer"; + developer_dir = "/Applications/Xcode.app/Contents/Developer"; if (developer_dir == "/Developer") defines.set("LEGACY_XCODE_LOCATION","1"); defines.set("DEVELOPER_DIR",developer_dir); @@ -1186,5 +931,241 @@ class BuildTool new BuildTool(makefile,defines,targets,include_path); } } - -} + + function parseXML(inXML:Fast,inSection:String) + { + for(el in inXML.elements) + { + if (valid(el,inSection)) + { + switch(el.name) + { + case "set" : + var name = el.att.name; + var value = substitute(el.att.value); + mDefines.set(name,value); + if (name == "BLACKBERRY_NDK_ROOT") + { + Setup.setupBlackBerryNativeSDK(mDefines); + } + case "unset" : + var name = el.att.name; + mDefines.remove(name); + case "setup" : + var name = substitute(el.att.name); + Setup.setup(name,mDefines); + case "echo" : + Sys.println(substitute(el.att.value)); + case "setenv" : + var name = el.att.name; + var value = substitute(el.att.value); + mDefines.set(name,value); + Sys.putEnv(name,value); + case "error" : + var error = substitute(el.att.value); + throw(error); + case "path" : + var path = substitute(el.att.name); + if (verbose) + println("Adding path " + path ); + var os = Sys.systemName(); + var sep = mDefines.exists("windows_host") ? ";" : ":"; + var add = path + sep + Sys.getEnv("PATH"); + Sys.putEnv("PATH", add); + //trace(Sys.getEnv("PATH")); + case "compiler" : + mCompiler = createCompiler(el,mCompiler); + case "stripper" : + mStripper = createStripper(el,mStripper); + case "linker" : + if (mLinkers.exists(el.att.id)) + createLinker(el,mLinkers.get(el.att.id)); + else + mLinkers.set( el.att.id, createLinker(el,null) ); + case "files" : + var name = el.att.id; + if (mFileGroups.exists(name)) + createFileGroup(el, mFileGroups.get(name), name); + else + mFileGroups.set(name,createFileGroup(el,null,name)); + case "include" : + var name = substitute(el.att.name); + var full_name = findIncludeFile(name); + if (full_name!="") + { + var make_contents = sys.io.File.getContent(full_name); + var xml_slow = Xml.parse(make_contents); + var section = el.has.section ? el.att.section : ""; + + parseXML(new Fast(xml_slow.firstElement()),section); + } + else if (!el.has.noerror) + { + throw "Could not find include file " + name; + } + case "target" : + var name = substitute(el.att.id); + var overwrite = name=="default"; + if (el.has.overwrite) + overwrite = true; + if (el.has.append) + overwrite = false; + if (mTargets.exists(name) && !overwrite) + createTarget(el,mTargets.get(name)); + else + mTargets.set( name, createTarget(el,null) ); + case "section" : + parseXML(el,""); + } + } + } + } + + inline public static function println(s:String) + { + Sys.println(s); + } + + public static function runCommand(exe:String,args:Array,inPrint:Bool,inMultiThread:Bool):Int + { + if (exe.indexOf (" ") > -1) + { + var splitExe = exe.split (" "); + exe = splitExe.shift (); + args = splitExe.concat (args); + } + + var useSysCommand = !inMultiThread; + + if ( useSysCommand ) + { + if (inPrint) + println(exe + " " + args.join(" ")); + return Sys.command(exe,args); + } + else + { + var output = new Array(); + if (inPrint) + output.push(exe + " " + args.join(" ")); + var proc = new sys.io.Process(exe, args); + var err = proc.stderr; + var out = proc.stdout; + var reader = BuildTool.helperThread.value; + // Read stderr in separate hreead to avoid blocking ... + if (reader==null) + { + var contoller = Thread.current(); + BuildTool.helperThread.value = reader = Thread.create(function() + { + while(true) + { + var stream = Thread.readMessage(true); + var output:Array = null; + try + { + while(true) + { + var line = stream.readLine(); + if (output==null) + output = [ line ]; + else + output.push(line); + } + } + catch(e:Dynamic){ } + contoller.sendMessage(output); + } + }); + } + + // Start up the error reader ... + reader.sendMessage(err); + + try + { + while(true) + { + var line = out.readLine(); + output.push(line); + } + } + catch(e:Dynamic){ } + + var errOut:Array = Thread.readMessage(true); + + if (errOut!=null && errOut.length>0) + output = output.concat(errOut); + + if (output.length>0) + { + if (printMutex!=null) + printMutex.acquire(); + println(output.join("\n")); + if (printMutex!=null) + printMutex.release(); + } + + var code = proc.exitCode(); + proc.close(); + return code; + } + } + + static function set64(outDefines:Hash, in64:Bool) + { + if (in64) + { + outDefines.set("HXCPP_M64","1"); + outDefines.remove("HXCPP_32"); + } + else + { + outDefines.set("HXCPP_M32","1"); + outDefines.remove("HXCPP_M64"); + } + } + + public function substitute(str:String):String + { + while( mVarMatch.match(str) ) + { + var sub = mVarMatch.matched(1); + if (sub.substr(0,8)=="haxelib:") + { + sub = getHaxelib(sub.substr(8)); + } + else + sub = mDefines.get(sub); + + if (sub==null) sub=""; + str = mVarMatch.matchedLeft() + sub + mVarMatch.matchedRight(); + } + + return str; + } + + public function valid(inEl:Fast,inSection:String):Bool + { + if (inEl.x.get("if")!=null) + if (!defined(inEl.x.get("if"))) return false; + + if (inEl.has.unless) + if (defined(inEl.att.unless)) return false; + + if (inEl.has.ifExists) + if (!FileSystem.exists( substitute(inEl.att.ifExists) )) return false; + + if (inSection!="") + { + if (inEl.name!="section") + return false; + if (!inEl.has.id) + return false; + if (inEl.att.id!=inSection) + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/tools/run/Compiler.hx b/tools/run/Compiler.hx index 7bf33325f..f87da9c5a 100644 --- a/tools/run/Compiler.hx +++ b/tools/run/Compiler.hx @@ -1,14 +1,16 @@ +import haxe.crypto.Md5; +import haxe.io.Path; import sys.FileSystem; class Compiler { - public var mFlags : Array; - public var mCFlags : Array; - public var mMMFlags : Array; - public var mCPPFlags : Array; - public var mOBJCFlags : Array; - public var mPCHFlags : Array; - public var mAddGCCIdentity: Bool; + public var mFlags:Array; + public var mCFlags:Array; + public var mMMFlags:Array; + public var mCPPFlags:Array; + public var mOBJCFlags:Array; + public var mPCHFlags:Array; + public var mAddGCCIdentity:Bool; public var mExe:String; public var mOutFlag:String; public var mObjDir:String; @@ -69,109 +71,9 @@ class Compiler } } - public function setPCH(inPCH:String) - { - mPCH = inPCH; - if (mPCH=="gcc") - { - mPCHExt = ".h.gch"; - mPCHUse = ""; - mPCHFilename = ""; - } - } - - public function needsPchObj() - { - return !mCached && mPCH!="gcc"; - } - - public function createCompilerVersion(inGroup:FileGroup) - { - if (mGetCompilerVersion!=null && mCompilerVersion==null) - { - var exe = mGetCompilerVersion; - var args = new Array(); - if (exe.indexOf (" ") > -1) - { - var splitExe = exe.split(" "); - exe = splitExe.shift(); - args = splitExe.concat(args); - } - - var versionString = Setup.readStderr(exe,args).join(" "); - if (BuildTool.verbose) - { - BuildTool.println("--- Compiler verison ---" ); - BuildTool.println( versionString ); - BuildTool.println("------------------"); - } - - mCompilerVersion = haxe.crypto.Md5.encode(versionString); - mCached = true; - } - - return mCached; - } - - public function precompile(inObjDir:String,inGroup:FileGroup) - { - var header = inGroup.mPrecompiledHeader; - var file = inGroup.getPchName(); - - var args = inGroup.mCompilerFlags.concat(mFlags).concat( mCPPFlags ).concat( mPCHFlags ); - - var dir = inObjDir + "/" + inGroup.getPchDir() + "/"; - var pch_name = dir + file + mPCHExt; - - BuildTool.log("Make pch dir " + dir ); - DirManager.make(dir); - - if (mPCH!="gcc") - { - args.push( mPCHCreate + header + ".h" ); - - // Create a temp file for including ... - var tmp_cpp = dir + file + ".cpp"; - var outFile = sys.io.File.write(tmp_cpp,false); - outFile.writeString("#include <" + header + ".h>\n"); - outFile.close(); - - args.push( tmp_cpp ); - args.push(mPCHFilename + pch_name); - args.push(mOutFlag + dir + file + mExt); - } - else - { - BuildTool.log("Make pch dir " + dir + header ); - DirManager.make(dir + header); - args.push( "-o" ); - args.push(pch_name); - args.push( inGroup.mPrecompiledHeaderDir + "/" + inGroup.mPrecompiledHeader + ".h" ); - } - - - BuildTool.println("Creating " + pch_name + "..."); - var result = BuildTool.runCommand( mExe, args, true, false ); - if (result!=0) - { - if (FileSystem.exists(pch_name)) - FileSystem.deleteFile(pch_name); - throw "Error creating pch: " + result + " - build cancelled"; - } - } - - public function getObjName(inFile:File) - { - var path = new haxe.io.Path(inFile.mName); - var dirId = - haxe.crypto.Md5.encode(BuildTool.targetKey + path.dir).substr(0,8) + "_"; - - return mObjDir + "/" + dirId + path.file + mExt; - } - public function compile(inFile:File,inTid:Int) { - var path = new haxe.io.Path(mObjDir + "/" + inFile.mName); + var path = new Path(mObjDir + "/" + inFile.mName); var obj_name = getObjName(inFile); var args = new Array(); @@ -194,7 +96,6 @@ class Compiler args = args.concat(mCPPFlags); } - if (!mCached && inFile.mGroup.mPrecompiledHeader!="" && allowPch) { var pchDir = inFile.mGroup.getPchDir(); @@ -207,7 +108,6 @@ class Compiler args.unshift("-I"+mObjDir + "/" + pchDir); } - var found = false; var cacheName:String = null; if (mCompilerVersion!=null) @@ -236,7 +136,7 @@ class Compiler if (!found) { - args.push( (new haxe.io.Path( inFile.mDir + inFile.mName)).toString() ); + args.push( (new Path( inFile.mDir + inFile.mName)).toString() ); var out = mOutFlag; if (out.substr(-1)==" ") @@ -262,4 +162,102 @@ class Compiler return obj_name; } + + public function createCompilerVersion(inGroup:FileGroup) + { + if (mGetCompilerVersion!=null && mCompilerVersion==null) + { + var exe = mGetCompilerVersion; + var args = new Array(); + if (exe.indexOf (" ") > -1) + { + var splitExe = exe.split(" "); + exe = splitExe.shift(); + args = splitExe.concat(args); + } + + var versionString = Setup.readStderr(exe,args).join(" "); + if (BuildTool.verbose) + { + BuildTool.println("--- Compiler verison ---" ); + BuildTool.println( versionString ); + BuildTool.println("------------------"); + } + + mCompilerVersion = haxe.crypto.Md5.encode(versionString); + mCached = true; + } + + return mCached; + } + + public function getObjName(inFile:File) + { + var path = new Path(inFile.mName); + var dirId = Md5.encode(BuildTool.targetKey + path.dir).substr(0,8) + "_"; + + return mObjDir + "/" + dirId + path.file + mExt; + } + + public function needsPchObj() + { + return !mCached && mPCH!="gcc"; + } + + public function precompile(inObjDir:String,inGroup:FileGroup) + { + var header = inGroup.mPrecompiledHeader; + var file = inGroup.getPchName(); + + var args = inGroup.mCompilerFlags.concat(mFlags).concat( mCPPFlags ).concat( mPCHFlags ); + + var dir = inObjDir + "/" + inGroup.getPchDir() + "/"; + var pch_name = dir + file + mPCHExt; + + BuildTool.log("Make pch dir " + dir ); + DirManager.make(dir); + + if (mPCH!="gcc") + { + args.push( mPCHCreate + header + ".h" ); + + // Create a temp file for including ... + var tmp_cpp = dir + file + ".cpp"; + var outFile = sys.io.File.write(tmp_cpp,false); + outFile.writeString("#include <" + header + ".h>\n"); + outFile.close(); + + args.push( tmp_cpp ); + args.push(mPCHFilename + pch_name); + args.push(mOutFlag + dir + file + mExt); + } + else + { + BuildTool.log("Make pch dir " + dir + header ); + DirManager.make(dir + header); + args.push( "-o" ); + args.push(pch_name); + args.push( inGroup.mPrecompiledHeaderDir + "/" + inGroup.mPrecompiledHeader + ".h" ); + } + + BuildTool.println("Creating " + pch_name + "..."); + var result = BuildTool.runCommand( mExe, args, true, false ); + if (result!=0) + { + if (FileSystem.exists(pch_name)) + FileSystem.deleteFile(pch_name); + throw "Error creating pch: " + result + " - build cancelled"; + } + } + + public function setPCH(inPCH:String) + { + mPCH = inPCH; + if (mPCH=="gcc") + { + mPCHExt = ".h.gch"; + mPCHUse = ""; + mPCHFilename = ""; + } + } } \ No newline at end of file diff --git a/tools/run/DirManager.hx b/tools/run/DirManager.hx index 73bc2654e..ca20a7a34 100644 --- a/tools/run/DirManager.hx +++ b/tools/run/DirManager.hx @@ -5,6 +5,49 @@ class DirManager { static var mMade = new Hash(); + static public function deleteExtension(inExt:String) + { + var contents = FileSystem.readDirectory("."); + for(item in contents) + { + if (item.length > inExt.length && item.substr(item.length-inExt.length)==inExt) + deleteFile(item); + } + } + + static public function deleteFile(inName:String) + { + if (FileSystem.exists(inName)) + { + BuildTool.log("rm " + inName); + FileSystem.deleteFile(inName); + } + } + + static public function deleteRecurse(inDir:String) + { + if (FileSystem.exists(inDir)) + { + var contents = FileSystem.readDirectory(inDir); + for(item in contents) + { + if (item!="." && item!="..") + { + var name = inDir + "/" + item; + if (FileSystem.isDirectory(name)) + deleteRecurse(name); + else + { + BuildTool.log("rm " + name); + FileSystem.deleteFile(name); + } + } + } + BuildTool.log("rmdir " + inDir); + FileSystem.deleteDirectory(inDir); + } + } + static public function make(inDir:String) { var parts = inDir.split("/"); @@ -37,10 +80,7 @@ class DirManager } return true; } - public static function reset() - { - mMade = new Hash(); - } + static public function makeFileDir(inFile:String) { var parts = StringTools.replace (inFile, "\\", "/").split("/"); @@ -50,47 +90,8 @@ class DirManager make(parts.join("/")); } - static public function deleteFile(inName:String) - { - if (FileSystem.exists(inName)) - { - BuildTool.log("rm " + inName); - FileSystem.deleteFile(inName); - } - } - - static public function deleteExtension(inExt:String) - { - var contents = FileSystem.readDirectory("."); - for(item in contents) - { - if (item.length > inExt.length && item.substr(item.length-inExt.length)==inExt) - deleteFile(item); - } - } - - static public function deleteRecurse(inDir:String) + public static function reset() { - if (FileSystem.exists(inDir)) - { - var contents = FileSystem.readDirectory(inDir); - for(item in contents) - { - if (item!="." && item!="..") - { - var name = inDir + "/" + item; - if (FileSystem.isDirectory(name)) - deleteRecurse(name); - else - { - BuildTool.log("rm " + name); - FileSystem.deleteFile(name); - } - } - } - BuildTool.log("rmdir " + inDir); - FileSystem.deleteDirectory(inDir); - } + mMade = new Hash(); } - } \ No newline at end of file diff --git a/tools/run/File.hx b/tools/run/File.hx index f78e29748..0d09c5b0c 100644 --- a/tools/run/File.hx +++ b/tools/run/File.hx @@ -2,6 +2,14 @@ import sys.FileSystem; class File { + static var mFileHashes = new Map(); + public var mName:String; + public var mDir:String; + public var mDependHash:String; + public var mDepends:Array; + public var mCompilerFlags:Array; + public var mGroup:FileGroup; + public function new(inName:String, inGroup:FileGroup) { mName = inName; @@ -12,6 +20,7 @@ class File mDepends = []; mCompilerFlags = []; } + public function computeDependHash() { mDependHash = ""; @@ -54,11 +63,4 @@ class File } return false; } - static var mFileHashes = new Map(); - public var mName:String; - public var mDir:String; - public var mDependHash:String; - public var mDepends:Array; - public var mCompilerFlags:Array; - public var mGroup:FileGroup; } \ No newline at end of file diff --git a/tools/run/FileGroup.hx b/tools/run/FileGroup.hx index ba04f994a..519dbf542 100644 --- a/tools/run/FileGroup.hx +++ b/tools/run/FileGroup.hx @@ -3,6 +3,19 @@ import sys.FileSystem; class FileGroup { + public var mNewest:Float; + public var mCompilerFlags:Array; + public var mMissingDepends:Array; + public var mOptions:Array; + public var mPrecompiledHeader:String; + public var mPrecompiledHeaderDir:String; + public var mFiles:Array; + public var mHLSLs:Array; + public var mDir:String; + public var mId:String; + public var mDepends:Array; + public var mDependHash:String; + public function new(inDir:String,inId:String) { mNewest = 0; @@ -17,28 +30,11 @@ class FileGroup mId = inId; } - public function preBuild() - { - for(hlsl in mHLSLs) - hlsl.build(); - - if (BuildTool.useCache) - { - mDependHash = ""; - for(depend in mDepends) - mDependHash += File.getFileHash(depend); - mDependHash = haxe.crypto.Md5.encode(mDependHash); - } - } - - public function addHLSL(inFile:String,inProfile:String,inVariable:String,inTarget:String) + public function addCompilerFlag(inFlag:String) { - addDepend(inFile); - - mHLSLs.push( new HLSL(inFile,inProfile,inVariable,inTarget) ); + mCompilerFlags.push(inFlag); } - public function addDepend(inFile:String) { if (!FileSystem.exists(inFile)) @@ -53,15 +49,22 @@ class FileGroup mDepends.push(inFile); } + public function addHLSL(inFile:String,inProfile:String,inVariable:String,inTarget:String) + { + addDepend(inFile); + + mHLSLs.push( new HLSL(inFile,inProfile,inVariable,inTarget) ); + } public function addOptions(inFile:String) { mOptions.push(inFile); } - public function getPchDir() + public function checkDependsExist() { - return "__pch/" + mId ; + if (mMissingDepends.length>0) + throw "Could not find dependencies: " + mMissingDepends.join(","); } public function checkOptions(inObjDir:String) @@ -100,15 +103,14 @@ class FileGroup return changed; } - public function checkDependsExist() + public function getPchDir() { - if (mMissingDepends.length>0) - throw "Could not find dependencies: " + mMissingDepends.join(","); + return "__pch/" + mId ; } - public function addCompilerFlag(inFlag:String) + public function getPchName() { - mCompilerFlags.push(inFlag); + return Path.withoutDirectory(mPrecompiledHeader); } public function isOutOfDate(inStamp:Float) @@ -116,27 +118,23 @@ class FileGroup return inStamp; - public var mMissingDepends:Array; - public var mOptions:Array; - public var mPrecompiledHeader:String; - public var mPrecompiledHeaderDir:String; - public var mFiles: Array; - public var mHLSLs: Array; - public var mDir : String; - public var mId : String; - public var mDepends:Array; - public var mDependHash : String; } \ No newline at end of file diff --git a/tools/run/HLSL.hx b/tools/run/HLSL.hx index b8f412f41..70ffceafd 100644 --- a/tools/run/HLSL.hx +++ b/tools/run/HLSL.hx @@ -18,15 +18,15 @@ class HLSL public function build() { - if (!FileSystem.exists (Path.directory (target))) - { - DirManager.make(Path.directory (target)); - } - + if (!FileSystem.exists(Path.directory (target))) + { + DirManager.make(Path.directory (target)); + } + DirManager.makeFileDir(target); var srcStamp = FileSystem.stat(file).mtime.getTime(); - if ( !FileSystem.exists(target) || FileSystem.stat(target).mtime.getTime() < srcStamp) + if (!FileSystem.exists(target) || FileSystem.stat(target).mtime.getTime() < srcStamp) { var exe = "fxc.exe"; var args = [ "/nologo", "/T", profile, file, "/Vn", variable, "/Fh", target ]; diff --git a/tools/run/Linker.hx b/tools/run/Linker.hx index 486400b2b..e05ef67ea 100644 --- a/tools/run/Linker.hx +++ b/tools/run/Linker.hx @@ -4,7 +4,7 @@ import sys.FileSystem; class Linker { public var mExe:String; - public var mFlags : Array; + public var mFlags:Array; public var mOutFlag:String; public var mExt:String; public var mNamePrefix:String; @@ -12,7 +12,7 @@ class Linker public var mRanLib:String; public var mFromFile:String; public var mLibs:Array; - public var mExpandArchives : Bool; + public var mExpandArchives:Bool; public var mRecreate:Bool; public function new(inExe:String) @@ -29,6 +29,23 @@ class Linker mLibs = []; mRecreate = false; } + + function isOutOfDate(inName:String, inObjs:Array) + { + if (!FileSystem.exists(inName)) + return true; + var stamp = FileSystem.stat(inName).mtime.getTime(); + for(obj in inObjs) + { + if (!FileSystem.exists(obj)) + throw "Could not find " + obj + " required by " + inName; + var obj_stamp = FileSystem.stat(obj).mtime.getTime(); + if (obj_stamp > stamp) + return true; + } + return false; + } + public function link(inTarget:Target,inObjs:Array,inCompiler:Compiler) { var ext = inTarget.mExt=="" ? mExt : inTarget.mExt; @@ -88,7 +105,6 @@ class Linker } } - if (isOutOfDateLibs || isOutOfDate(out_name,inObjs) || isOutOfDate(out_name,inTarget.mDepends)) { var args = new Array(); @@ -117,7 +133,6 @@ class Linker args = args.concat(mFlags).concat(inTarget.mFlags); - var objs = inObjs.copy(); if (mExpandArchives) @@ -145,7 +160,6 @@ class Linker libs = libArgs; } - // Place list of obj files in a file called "all_objs" if (mFromFile=="@") { @@ -183,19 +197,4 @@ class Linker return ""; } - function isOutOfDate(inName:String, inObjs:Array) - { - if (!FileSystem.exists(inName)) - return true; - var stamp = FileSystem.stat(inName).mtime.getTime(); - for(obj in inObjs) - { - if (!FileSystem.exists(obj)) - throw "Could not find " + obj + " required by " + inName; - var obj_stamp = FileSystem.stat(obj).mtime.getTime(); - if (obj_stamp > stamp) - return true; - } - return false; - } } \ No newline at end of file diff --git a/tools/run/Setup.hx b/tools/run/Setup.hx index 8302350df..609267279 100644 --- a/tools/run/Setup.hx +++ b/tools/run/Setup.hx @@ -1,10 +1,63 @@ +import haxe.io.Eof; +import sys.io.Process; import sys.FileSystem; import BuildTool; - class Setup { - public static function initHXCPPConfig(ioDefines:Hash ) + static function findAndroidNdkRoot(inDir:String) + { + var files:Array = null; + try + { + files = FileSystem.readDirectory(inDir); + } + catch (e:Dynamic) + { + throw 'ANDROID_NDK_DIR "$inDir" does not point to a valid directory.'; + } + + var extract_version = ~/^android-ndk-r(\d+)([a-z]?)$/; + var bestMajor = 0; + var bestMinor = ""; + var result = ""; + for(file in files) + if (extract_version.match(file)) + { + var major = Std.parseInt( extract_version.matched(1) ); + var minor = extract_version.matched(2); + if ( major>bestMajor || (major==bestMajor && minor>bestMinor)) + { + bestMajor = major; + bestMinor = minor; + result = inDir + "/" + file; + } + } + + if (BuildTool.verbose) + { + var message = "Found NDK " + result; + BuildTool.println(message); + } + + if (result=="") + throw 'ANDROID_NDK_DIR "$inDir" does not contain matching ndk downloads.'; + + return result; + } + + static public function getNdkVersion(inDirName:String):Int + { + var extract_version = ~/android-ndk-r(\d+)*/; + if (extract_version.match(inDirName)) + { + return Std.parseInt( extract_version.matched(1) ); + } + //throw 'Could not deduce NDK version from "$inDirName"'; + return 8; + } + + public static function initHXCPPConfig(ioDefines:Hash) { var env = Sys.environment(); // If the user has set it themselves, they mush know what they are doing... @@ -13,9 +66,9 @@ class Setup var home = ""; if (env.exists("HOME")) - home = env.get("HOME"); + home = env.get("HOME"); else if (env.exists("USERPROFILE")) - home = env.get("USERPROFILE"); + home = env.get("USERPROFILE"); else { Sys.println("Warning: No 'HOME' variable set - .hxcpp_config.xml might be missing."); @@ -32,7 +85,7 @@ class Setup { try { if (BuildTool.verbose) - BuildTool.println("Copy config: " + src + " -> " + config ); + BuildTool.println("Copy config: " + src + " -> " + config ); sys.io.File.copy(src,config); } catch(e:Dynamic) @@ -43,18 +96,57 @@ class Setup } } - static public function getNdkVersion(inDirName:String) : Int + public static function isRaspberryPi() + { + var proc = new Process("uname",["-a"]); + var str = proc.stdout.readLine(); + proc.close(); + return str.split(" ")[1]=="raspberrypi"; + } + + public static function readStderr(inCommand:String,inArgs:Array) { - var extract_version = ~/android-ndk-r(\d+)*/; - if (extract_version.match(inDirName)) + var result = new Array(); + var proc = new Process(inCommand,inArgs); + try { - return Std.parseInt( extract_version.matched(1) ); - } - //throw 'Could not deduce NDK version from "$inDirName"'; - return 8; + while(true) + { + var out = proc.stderr.readLine(); + result.push(out); + } + } catch(e:Dynamic){} + proc.close(); + return result; } - static public function setupAndroidNdk(defines: Map) + public static function readStdout(inCommand:String,inArgs:Array) + { + var result = new Array(); + var proc = new Process(inCommand,inArgs); + try + { + while(true) + { + var out = proc.stdout.readLine(); + result.push(out); + } + } catch(e:Dynamic){} + proc.close(); + return result; + } + + public static function setup(inWhat:String,ioDefines: Map) + { + if (inWhat=="androidNdk") + setupAndroidNdk(ioDefines); + else if (inWhat=="msvc") + setupMSVC(ioDefines, ioDefines.exists("HXCPP_M64")); + else + throw 'Unknown setup feature $inWhat'; + } + + static public function setupAndroidNdk(defines:Map) { var root:String = null; @@ -176,67 +268,6 @@ class Setup } } - - static function findAndroidNdkRoot(inDir:String) - { - var files:Array = null; - try - { - files = FileSystem.readDirectory(inDir); - } - catch (e:Dynamic) - { - throw 'ANDROID_NDK_DIR "$inDir" does not point to a valid directory.'; - } - - var extract_version = ~/^android-ndk-r(\d+)([a-z]?)$/; - var bestMajor = 0; - var bestMinor = ""; - var result = ""; - for(file in files) - if (extract_version.match(file)) - { - var major = Std.parseInt( extract_version.matched(1) ); - var minor = extract_version.matched(2); - if ( major>bestMajor || (major==bestMajor && minor>bestMinor)) - { - bestMajor = major; - bestMinor = minor; - result = inDir + "/" + file; - } - } - - - if (BuildTool.verbose) - { - var message = "Found NDK " + result; - BuildTool.println(message); - } - - if (result=="") - throw 'ANDROID_NDK_DIR "$inDir" does not contain matching ndk downloads.'; - - return result; - } - - public static function setup(inWhat:String,ioDefines: Map) - { - if (inWhat=="androidNdk") - setupAndroidNdk(ioDefines); - else if (inWhat=="msvc") - setupMSVC(ioDefines, ioDefines.exists("HXCPP_M64")); - else - throw 'Unknown setup feature $inWhat'; - } - - static function toPath(inPath:String) - { - if (!BuildTool.isWindows) - return inPath; - var bits = inPath.split("/"); - return bits.join("\\"); - } - public static function setupBlackBerryNativeSDK(ioDefines:Hash) { if (ioDefines.exists ("BLACKBERRY_NDK_ROOT") && (!ioDefines.exists("QNX_HOST") || !ioDefines.exists("QNX_TARGET"))) @@ -263,11 +294,11 @@ class Setup switch (name) { case "QNX_HOST", "QNX_TARGET", "QNX_HOST_VERSION", "QNX_TARGET_VERSION": - var value = split[1]; - if (StringTools.startsWith (value, "${") && split.length > 2) - { - value = split[2].substr (0, split[2].length - 1); - } + var value = split[1]; + if (StringTools.startsWith (value, "${") && split.length > 2) + { + value = split[2].substr (0, split[2].length - 1); + } if (StringTools.startsWith(value, "\"")) { value = value.substr (1); @@ -287,7 +318,7 @@ class Setup { value = StringTools.replace (value, "$QNX_HOST_VERSION", Sys.getEnv("QNX_HOST_VERSION")); value = StringTools.replace (value, "$QNX_TARGET_VERSION", Sys.getEnv("QNX_TARGET_VERSION")); - value = StringTools.replace (value, "%QNX_HOST_VERSION%", Sys.getEnv("QNX_HOST_VERSION")); + value = StringTools.replace (value, "%QNX_HOST_VERSION%", Sys.getEnv("QNX_HOST_VERSION")); value = StringTools.replace (value, "%QNX_TARGET_VERSION%", Sys.getEnv("QNX_TARGET_VERSION")); } ioDefines.set(name,value); @@ -295,14 +326,14 @@ class Setup } } } - catch( ex:haxe.io.Eof ) + catch( ex:Eof ) {} fin.close(); } } } - public static function setupMSVC(ioDefines:Hash, in64:Bool ) + public static function setupMSVC(ioDefines:Hash, in64:Bool) { var detectMsvc = !ioDefines.exists("NO_AUTO_MSVC") && !ioDefines.exists("HXCPP_MSVC_CUSTOM"); @@ -351,7 +382,7 @@ class Setup xpCompat = true; } - var vc_setup_proc = new sys.io.Process("cmd.exe", ["/C", BuildTool.HXCPP + "build-tool\\msvc" + extra + "-setup.bat" ]); + var vc_setup_proc = new Process("cmd.exe", ["/C", BuildTool.HXCPP + "build-tool\\msvc" + extra + "-setup.bat" ]); var vars_found = false; var error_string = ""; var output = new Array(); @@ -384,90 +415,55 @@ class Setup } } } - } catch (e:Dynamic) { - }; + } catch (e:Dynamic) { + }; - vc_setup_proc.close(); - if (!vars_found || error_string!="") - { - for(o in output) - BuildTool.println(o); - if (error_string!="") - throw(error_string); - else - BuildTool.println("Missing HXCPP_VARS"); - - throw("Could not automatically setup MSVC"); - } - } - - - try - { - var proc = new sys.io.Process("cl.exe",[]); - var str = proc.stderr.readLine(); - proc.close(); - if (str>"") - { - var reg = ~/Version\s+(\d+)/i; - if (reg.match(str)) - { - var cl_version = Std.parseInt(reg.matched(1)); - if (BuildTool.verbose) - BuildTool.println("Using msvc cl version " + cl_version); - ioDefines.set("MSVC_VER", cl_version+""); - if (cl_version>=17) - ioDefines.set("MSVC17+","1"); - if (cl_version>=18) - ioDefines.set("MSVC18+","1"); - BuildTool.sAllowNumProcs = cl_version >= 14; - if (Std.parseInt(ioDefines.get("HXCPP_COMPILE_THREADS"))>1 && cl_version>=18) - ioDefines.set("HXCPP_FORCE_PDB_SERVER","1"); - } - } - } catch(e:Dynamic){} - //if (cl_version!="") BuildTool.println("Using cl version: " + cl_version); - } + vc_setup_proc.close(); + if (!vars_found || error_string!="") + { + for(o in output) + BuildTool.println(o); + if (error_string!="") + throw(error_string); + else + BuildTool.println("Missing HXCPP_VARS"); - public static function isRaspberryPi() - { - var proc = new sys.io.Process("uname",["-a"]); - var str = proc.stdout.readLine(); - proc.close(); - return str.split(" ")[1]=="raspberrypi"; - } + throw("Could not automatically setup MSVC"); + } + } - public static function readStderr(inCommand:String,inArgs:Array) - { - var result = new Array(); - var proc = new sys.io.Process(inCommand,inArgs); try { - while(true) + var proc = new Process("cl.exe",[]); + var str = proc.stderr.readLine(); + proc.close(); + if (str>"") { - var out = proc.stderr.readLine(); - result.push(out); + var reg = ~/Version\s+(\d+)/i; + if (reg.match(str)) + { + var cl_version = Std.parseInt(reg.matched(1)); + if (BuildTool.verbose) + BuildTool.println("Using msvc cl version " + cl_version); + ioDefines.set("MSVC_VER", cl_version+""); + if (cl_version>=17) + ioDefines.set("MSVC17+","1"); + if (cl_version>=18) + ioDefines.set("MSVC18+","1"); + BuildTool.sAllowNumProcs = cl_version >= 14; + if (Std.parseInt(ioDefines.get("HXCPP_COMPILE_THREADS"))>1 && cl_version>=18) + ioDefines.set("HXCPP_FORCE_PDB_SERVER","1"); + } } } catch(e:Dynamic){} - proc.close(); - return result; + //if (cl_version!="") BuildTool.println("Using cl version: " + cl_version); } - public static function readStdout(inCommand:String,inArgs:Array) + static function toPath(inPath:String) { - var result = new Array(); - var proc = new sys.io.Process(inCommand,inArgs); - try - { - while(true) - { - var out = proc.stdout.readLine(); - result.push(out); - } - } catch(e:Dynamic){} - proc.close(); - return result; + if (!BuildTool.isWindows) + return inPath; + var bits = inPath.split("/"); + return bits.join("\\"); } - -} - +} \ No newline at end of file diff --git a/tools/run/Stripper.hx b/tools/run/Stripper.hx index 11abb9775..341fd19e0 100644 --- a/tools/run/Stripper.hx +++ b/tools/run/Stripper.hx @@ -1,19 +1,18 @@ class Stripper { public var mExe:String; - public var mFlags : Array; + public var mFlags:Array; public function new(inExe:String) { mFlags = []; mExe = inExe; } + public function strip(inTarget:String) { var args = new Array(); - args = args.concat(mFlags); - args.push(inTarget); var result = BuildTool.runCommand( mExe, args, true,false ); diff --git a/tools/run/Target.hx b/tools/run/Target.hx index 83ab8afe2..fd216facc 100644 --- a/tools/run/Target.hx +++ b/tools/run/Target.hx @@ -1,5 +1,20 @@ class Target { + public var mBuildDir:String; + public var mOutput:String; + public var mOutputDir:String; + public var mTool:String; + public var mToolID:String; + public var mFiles:Array; + public var mFileGroups:Array; + public var mDepends:Array; + public var mSubTargets:Array; + public var mLibs:Array; + public var mFlags:Array; + public var mErrors:Array; + public var mDirs:Array; + public var mExt:String; + public function new(inOutput:String, inTool:String,inToolID:String) { mOutput = inOutput; @@ -19,20 +34,23 @@ class Target mDirs=[]; } + public function addError(inError:String) + { + mErrors.push(inError); + } + public function addFiles(inGroup:FileGroup) { mFiles = mFiles.concat(inGroup.mFiles); mFileGroups.push(inGroup); } - public function addError(inError:String) - { - mErrors.push(inError); - } + public function checkError() { if (mErrors.length>0) throw mErrors.join("/"); } + public function clean() { for(dir in mDirs) @@ -46,19 +64,4 @@ class Target { return mOutput + mExt; } - - public var mBuildDir:String; - public var mOutput:String; - public var mOutputDir:String; - public var mTool:String; - public var mToolID:String; - public var mFiles:Array; - public var mFileGroups:Array; - public var mDepends:Array; - public var mSubTargets:Array; - public var mLibs:Array; - public var mFlags:Array; - public var mErrors:Array; - public var mDirs:Array; - public var mExt:String; } \ No newline at end of file From c5f6c66bb57a56bdc5b33df9e1d96fd303107f77 Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Mon, 24 Mar 2014 14:29:11 -0700 Subject: [PATCH 3/6] Tool improvements --- run.n | Bin 107463 -> 118973 bytes tools/run/BuildTool.hx | 486 ++++++++++++++++++------------------ tools/run/Compiler.hx | 69 +++-- tools/run/File.hx | 10 +- tools/run/FileGroup.hx | 9 +- tools/run/HLSL.hx | 12 +- tools/run/Linker.hx | 57 +++-- tools/run/LogManager.hx | 123 +++++++++ tools/run/PathManager.hx | 299 ++++++++++++++++++++++ tools/run/ProcessManager.hx | 244 ++++++++++++++++++ tools/run/Setup.hx | 294 ++++++++++++---------- tools/run/Stripper.hx | 11 +- tools/run/Target.hx | 11 +- 13 files changed, 1186 insertions(+), 439 deletions(-) create mode 100644 tools/run/LogManager.hx create mode 100644 tools/run/PathManager.hx create mode 100644 tools/run/ProcessManager.hx diff --git a/run.n b/run.n index 92917a7f18a9fb99c3d93f464607afcd557c0693..e636a743b9f12b3e0ea66735ba4cf13d2222b2ff 100644 GIT binary patch literal 118973 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 literal 107463 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 W8G);mWpJsrvW&a1`)!vT) diff --git a/tools/run/BuildTool.hx b/tools/run/BuildTool.hx index 7587fabf5..9b7563a1c 100644 --- a/tools/run/BuildTool.hx +++ b/tools/run/BuildTool.hx @@ -1,4 +1,6 @@ +import haxe.io.Path; import haxe.xml.Fast; +import sys.io.Process; import sys.FileSystem; #if neko import neko.vm.Thread; @@ -29,14 +31,13 @@ class BuildTool var mTargets:Targets; public static var sAllowNumProcs = true; public static var HXCPP = ""; - public static var verbose = false; + public static var is64 = false; public static var isWindows = false; public static var isLinux = false; public static var isMac = false; public static var useCache = false; public static var compileCache:String; public static var targetKey:String; - public static var helperThread = new Tls(); public static var instance:BuildTool; static var printMutex:Mutex; static var mVarMatch = new EReg("\\${(.*?)}",""); @@ -57,8 +58,9 @@ class BuildTool try { make_contents = sys.io.File.getContent(inMakefile); } catch (e:Dynamic) { - println("Could not open build file '" + inMakefile + "'"); - Sys.exit(1); + LogManager.error("Could not open build file \"" + inMakefile + "\""); + //println("Could not open build file '" + inMakefile + "'"); + //Sys.exit(1); } if (!mDefines.exists("HXCPP_COMPILE_THREADS")) @@ -85,22 +87,25 @@ class BuildTool if (FileSystem.exists(compileCache) && FileSystem.isDirectory(compileCache)) { - useCache = true; + useCache = true; } else - throw "Could not find compiler cache: " + compileCache; - + { + LogManager.error("Could not find compiler cache \"" + compileCache + "\""); + //throw "Could not find compiler cache: " + compileCache; + } } if (useCache && (!mDefines.exists("haxe_ver") && !mDefines.exists("HXCPP_DEPENDS_OK"))) { - if (verbose) - println("ignoring cache because of possible missing dependencies"); + LogManager.info("", "Ignoring compiler cache because of possible missing dependencies"); useCache = false; } - if (useCache && verbose) - println("Using cache " + compileCache ); + if (useCache) + { + LogManager.info("", "Using compiler cache \"" + compileCache + "\""); + } if (inTargets.remove("clear")) for(target in mTargets.keys()) @@ -118,9 +123,15 @@ class BuildTool { // Sys.println("Build : " + inTarget ); if (!mTargets.exists(inTarget)) - throw "Could not find target '" + inTarget + "' to build."; + { + LogManager.error ("Could not find build target \"" + inTarget + "\""); + //throw "Could not find target '" + inTarget + "' to build."; + } if (mCompiler==null) - throw "No compiler defined"; + { + LogManager.error("No compiler defined for the current build target"); + //throw "No compiler defined"; + } var target = mTargets.get(inTarget); target.checkError(); @@ -135,20 +146,23 @@ class BuildTool { var thread_var = mDefines.exists("HXCPP_COMPILE_THREADS") ? mDefines.get("HXCPP_COMPILE_THREADS") : Sys.getEnv("HXCPP_COMPILE_THREADS"); - - if (thread_var==null) - thread_var = getNumberOfProcesses(); - threads = (thread_var==null || Std.parseInt(thread_var)<2) ? 1 : - Std.parseInt(thread_var); + + if (thread_var == null) + { + threads = getNumberOfProcesses(); + } + else + { + threads = (Std.parseInt(thread_var)<2) ? 1 : Std.parseInt(thread_var); + } } - DirManager.reset(); + PathManager.resetDirectoryCache(); var restoreDir = ""; if (target.mBuildDir!="") { restoreDir = Sys.getCwd(); - if (verbose) - Sys.println("Enter " + target.mBuildDir); + LogManager.info("", "Enter \"" + target.mBuildDir + "\""); Sys.setCwd(target.mBuildDir); } @@ -157,7 +171,7 @@ class BuildTool var objs = new Array(); if (target.mFileGroups.length > 0) - DirManager.make(mCompiler.mObjDir); + PathManager.mkdir(mCompiler.mObjDir); for(group in target.mFileGroups) { group.checkOptions(mCompiler.mObjDir); @@ -239,9 +253,13 @@ class BuildTool // Wait for theads to finish... for(t in 0...threads) { - var result = Thread.readMessage(true); - if (result=="Error") - throw "Error in building thread"; + var result = Thread.readMessage(true); + if (result=="Error") + { + // Already printed the error from the thread, just need to exit + Sys.exit (1); + //throw "Error in building thread"; + } } } } @@ -250,7 +268,10 @@ class BuildTool { case "linker": if (!mLinkers.exists(target.mToolID)) - throw "Missing linker :\"" + target.mToolID + "\""; + { + LogManager.error ("Could not find linker for \"" + target.mToolID + "\""); + //throw "Missing linker :\"" + target.mToolID + "\""; + } var exe = mLinkers.get(target.mToolID).link(target,objs, mCompiler); if (exe!="" && mStripper!=null) @@ -266,9 +287,15 @@ class BuildTool { // Sys.println("Build : " + inTarget ); if (!mTargets.exists(inTarget)) - throw "Could not find target '" + inTarget + "' to build."; + { + LogManager.error("Could not find build target \"" + inTarget + "\""); + //throw "Could not find target '" + inTarget + "' to build."; + } if (mCompiler==null) - throw "No compiler defined"; + { + LogManager.error("No compiler defined"); + //throw "No compiler defined"; + } var target = mTargets.get(inTarget); target.checkError(); @@ -280,16 +307,15 @@ class BuildTool if (target.mBuildDir!="") { restoreDir = Sys.getCwd(); - if (verbose) - Sys.println("Enter " + target.mBuildDir); + LogManager.info("", "Enter \"" + target.mBuildDir + "\""); Sys.setCwd(target.mBuildDir); } - DirManager.deleteRecurse(mCompiler.mObjDir); - DirManager.deleteFile("all_objs"); - DirManager.deleteExtension(".pdb"); + PathManager.removeDirectory(mCompiler.mObjDir); + PathManager.removeFile("all_objs"); + PathManager.removeFilesWithExtension(".pdb"); if (allObj) - DirManager.deleteRecurse("obj"); + PathManager.removeDirectory("obj"); if (restoreDir!="") Sys.setCwd(restoreDir); @@ -300,7 +326,7 @@ class BuildTool var c = inBase; if (inBase==null || inXML.has.replace) { - c = new Compiler(inXML.att.id,inXML.att.exe,mDefines.exists("USE_GCC_FILETYPES")); + c = new Compiler(substitute(inXML.att.id),substitute(inXML.att.exe),mDefines.exists("USE_GCC_FILETYPES")); if (mDefines.exists("USE_PRECOMPILED_HEADERS")) c.setPCH(mDefines.get("USE_PRECOMPILED_HEADERS")); } @@ -330,14 +356,16 @@ class BuildTool { var make_contents = sys.io.File.getContent(full_name); var xml_slow = Xml.parse(make_contents); - createCompiler(new haxe.xml.Fast(xml_slow.firstElement()),c); + createCompiler(new Fast(xml_slow.firstElement()),c); } else if (!el.has.noerror) { - throw "Could not find include file " + name; + LogManager.error("Could not find include file \"" + name + "\""); + //throw "Could not find include file " + name; } default: - throw "Unknown compiler option: '" + el.name + "'"; + LogManager.error("Unknown compiler option \"" + el.name + "\""); + //throw "Unknown compiler option: '" + el.name + "'"; } } @@ -420,7 +448,7 @@ class BuildTool return s; } - public function createTarget(inXML:haxe.xml.Fast,?inTarget:Target) : Target + public function createTarget(inXML:Fast,?inTarget:Target) : Target { var target:Target = inTarget; if (target==null) @@ -467,7 +495,7 @@ class BuildTool function findIncludeFile(inBase:String):String { - if (inBase=="") return ""; + if (inBase == null || inBase=="") return ""; var c0 = inBase.substr(0,1); if (c0!="/" && c0!="\\") { @@ -476,7 +504,7 @@ class BuildTool { for(p in mIncludePath) { - var name = p + "/" + inBase; + var name = PathManager.combine(p, inBase); if (FileSystem.exists(name)) return name; } @@ -487,31 +515,38 @@ class BuildTool return inBase; return ""; } - - public static function getHaxelib(library:String):String + + private static function getIs64():Bool { - var proc = new Process("haxelib",["path",library]); - var result = ""; - try + if (isWindows) { - while(true) + var architecture = Sys.getEnv ("PROCESSOR_ARCHITEW6432"); + if (architecture != null && architecture.indexOf ("64") > -1) { - var line = proc.stdout.readLine(); - if (line.substr(0,1) != "-") - { - result = line; - break; - } + return true; } - - } catch (e:Dynamic) { }; - - proc.close(); - - if (result == "") - throw ("Could not find haxelib path " + library + " required by a source file."); - - return result; + else + { + return false; + } + } + else + { + var process = new Process("uname", [ "-m" ]); + var output = process.stdout.readAll().toString(); + var error = process.stderr.readAll().toString(); + process.exitCode(); + process.close(); + + if (output.indexOf("64") > -1) + { + return true; + } + else + { + return false; + } + } } static public function getMsvcVer() @@ -520,43 +555,48 @@ class BuildTool } // Setting HXCPP_COMPILE_THREADS to 2x number or cores can help with hyperthreading - public static function getNumberOfProcesses():String + public static function getNumberOfProcesses():Int { - var env = Sys.getEnv("NUMBER_OF_PROCESSORS"); - if (env!=null) - return env; - var result = null; - if (isLinux) + if (isWindows) { - var proc = null; - proc = new Process("nproc",[]); - try + var env = Sys.getEnv("NUMBER_OF_PROCESSORS"); + if (env != null) + { + result = env; + } + } + else if (isLinux) + { + result = ProcessManager.runProcess("", "nproc", [], true, true, true); + if (result == null) { - result = proc.stdout.readLine(); - proc.close (); - } catch (e:Dynamic) {} + var cpuinfo = ProcessManager.runProcess("", "cat", [ "/proc/cpuinfo" ], true, true, true); + if (cpuinfo != null) + { + var split = cpuinfo.split("processor"); + result = Std.string(split.length - 1); + } + } } else if (isMac) { - var proc = new Process("/usr/sbin/system_profiler", ["-detailLevel", "full", "SPHardwareDataType"]); var cores = ~/Total Number of Cores: (\d+)/; - try + var output = ProcessManager.runProcess("", "/usr/sbin/system_profiler", [ "-detailLevel", "full", "SPHardwareDataType" ]); + if (cores.match(output)) { - while(true) - { - var line = proc.stdout.readLine(); - if (cores.match(line)) - { - result = cores.matched(1); - break; - } - } - } catch (e:Dynamic) {} - if (proc!=null) - proc.close(); + result = cores.matched(1); + } + } + + if (result == null || Std.parseInt(result) < 1) + { + return 1; + } + else + { + return Std.parseInt(result); } - return result; } public static function isMsvc() @@ -564,12 +604,6 @@ class BuildTool return instance.mDefines.get("toolchain")=="msvc"; } - inline public static function log(s:String) - { - if (verbose) - Sys.println(s); - } - // Process args and environment. static public function main() { @@ -583,12 +617,12 @@ class BuildTool var args = Sys.args(); var env = Sys.environment(); - verbose = env.exists("HXCPP_VERBOSE"); + LogManager.verbose = env.exists("HXCPP_VERBOSE"); // Check for calling from haxelib ... if (args.length>0) { - var last:String = (new haxe.io.Path(args[args.length-1])).toString(); + var last:String = (new Path(args[args.length-1])).toString(); var slash = last.substr(-1); if (slash=="/"|| slash=="\\") last = last.substr(0,last.length-1); @@ -596,7 +630,7 @@ class BuildTool { // When called from haxelib, the last arg is the original directory, and // the current direcory is the library directory. - HXCPP = Sys.getCwd(); + HXCPP = PathManager.standardize(Sys.getCwd()); defines.set("HXCPP",HXCPP); args.pop(); Sys.setCwd(last); @@ -614,7 +648,8 @@ class BuildTool defines.set("linux_host", "1"); var isRPi = isLinux && Setup.isRaspberryPi(); - + is64 = getIs64(); + for(arg in args) { if (arg.substr(0,2)=="-D") @@ -626,12 +661,12 @@ class BuildTool else defines.set(val,""); if (val=="verbose") - verbose = true; + LogManager.verbose = true; } else if (arg=="-v" || arg=="-verbose") - verbose = true; + LogManager.verbose = true; else if (arg.substr(0,2)=="-I") - include_path.push(arg.substr(2)); + include_path.push(PathManager.standardize(arg.substr(2))); else if (makefile.length==0) makefile = arg; else @@ -642,21 +677,23 @@ class BuildTool if (HXCPP=="" && env.exists("HXCPP")) { - HXCPP = env.get("HXCPP") + "/"; + HXCPP = PathManager.standardize(env.get("HXCPP")); defines.set("HXCPP",HXCPP); } if (HXCPP=="") { if (!defines.exists("HXCPP")) - throw "HXCPP not set, and not run from haxelib"; - HXCPP = defines.get("HXCPP") + "/"; + { + LogManager.error("Please run hxcpp using haxelib"); + //throw "HXCPP not set, and not run from haxelib"; + } + HXCPP = PathManager.standardize(defines.get("HXCPP")); defines.set("HXCPP",HXCPP); } - - if (verbose) - BuildTool.println("HXCPP : " + HXCPP); - + + LogManager.info("", "HXCPP : " + HXCPP); + include_path.push("."); if (env.exists("HOME")) include_path.push(env.get("HOME")); @@ -676,6 +713,14 @@ class BuildTool var msvc = false; + if (defines.exists ("toolchain")) + { + if (!defines.exists ("BINDIR")) + { + defines.set ("BINDIR", Path.withoutDirectory(Path.withoutExtension(defines.get ("toolchain")))); + } + } + if (defines.exists("ios")) { if (defines.exists("simulator")) @@ -686,6 +731,7 @@ class BuildTool { defines.set("iphoneos", "iphoneos"); } + defines.set("iphone", "iphone"); } if (defines.exists("iphoneos")) @@ -717,7 +763,10 @@ class BuildTool else if ( (new EReg("linux","i")).match(os) ) defines.set("ANDROID_HOST","linux-x86"); else - throw "Unknown android host:" + os; + { + LogManager.error ("Unknown android host \"" + os + "\""); + //throw "Unknown android host:" + os; + } } } else if (defines.exists("webos")) @@ -739,26 +788,26 @@ class BuildTool defines.set("tizen","tizen"); defines.set("BINDIR","Tizen"); } - else if (defines.exists("blackberry")) + else if (defines.exists("blackberry")) { - if (defines.exists("simulator")) - { - defines.set("toolchain", "blackberry-x86"); - } - else - { - defines.set("toolchain", "blackberry"); - } + if (defines.exists("simulator")) + { + defines.set("toolchain", "blackberry-x86"); + } + else + { + defines.set("toolchain", "blackberry"); + } defines.set("blackberry","blackberry"); defines.set("BINDIR","BlackBerry"); } - else if (defines.exists("emcc") || defines.exists("emscripten")) - { + else if (defines.exists("emcc") || defines.exists("emscripten")) + { defines.set("toolchain","emscripten"); - defines.set("emcc","emcc"); - defines.set("emscripten","emscripten"); - defines.set("BINDIR","Emscripten"); - } + defines.set("emcc","emcc"); + defines.set("emscripten","emscripten"); + defines.set("BINDIR","Emscripten"); + } else if (defines.exists("gph")) { defines.set("toolchain","gph"); @@ -807,7 +856,7 @@ class BuildTool { defines.set("BINDIR",m64 ? "Windows64":"Windows"); } - } + } } else if ( isRPi ) { @@ -847,24 +896,21 @@ class BuildTool if (defines.exists("dll_import")) { - var path = new haxe.io.Path(defines.get("dll_import")); + var path = new Path(defines.get("dll_import")); if (!defines.exists("dll_import_include")) defines.set("dll_import_include", path.dir + "/include" ); if (!defines.exists("dll_import_link")) defines.set("dll_import_link", defines.get("dll_import") ); } - if (defines.exists("apple") && !defines.exists("DEVELOPER_DIR")) { - var proc = new sys.io.Process("xcode-select", ["--print-path"]); - var developer_dir = proc.stdout.readLine(); - proc.close(); - if (developer_dir == "" || developer_dir.indexOf ("Run xcode-select") > -1) - developer_dir = "/Applications/Xcode.app/Contents/Developer"; - if (developer_dir == "/Developer") - defines.set("LEGACY_XCODE_LOCATION","1"); - defines.set("DEVELOPER_DIR",developer_dir); + var developer_dir = ProcessManager.runProcess("", "xcode-select", ["--print-path"]); + if (developer_dir == null || developer_dir == "" || developer_dir.indexOf ("Run xcode-select") > -1) + developer_dir = "/Applications/Xcode.app/Contents/Developer"; + if (developer_dir == "/Developer") + defines.set("LEGACY_XCODE_LOCATION","1"); + defines.set("DEVELOPER_DIR",developer_dir); } if (defines.exists("iphone") && !defines.exists("IPHONE_VER")) @@ -921,7 +967,7 @@ class BuildTool if (makefile=="") { - Sys.println("Usage : BuildTool makefile.xml [-DFLAG1] ... [-DFLAGN] ... [target1]...[targetN]"); + LogManager.info("Usage : BuildTool makefile.xml [-DFLAG1] ... [-DFLAGN] ... [target1]...[targetN]"); } else { @@ -955,7 +1001,7 @@ class BuildTool var name = substitute(el.att.name); Setup.setup(name,mDefines); case "echo" : - Sys.println(substitute(el.att.value)); + LogManager.info(substitute(el.att.value)); case "setenv" : var name = el.att.name; var value = substitute(el.att.value); @@ -966,8 +1012,7 @@ class BuildTool throw(error); case "path" : var path = substitute(el.att.name); - if (verbose) - println("Adding path " + path ); + LogManager.info("", "Adding path " + path); var os = Sys.systemName(); var sep = mDefines.exists("windows_host") ? ";" : ":"; var add = path + sep + Sys.getEnv("PATH"); @@ -1001,7 +1046,8 @@ class BuildTool } else if (!el.has.noerror) { - throw "Could not find include file " + name; + LogManager.error("Could not find include file \"" + name + "\""); + //throw "Could not find include file " + name; } case "target" : var name = substitute(el.att.id); @@ -1021,97 +1067,6 @@ class BuildTool } } - inline public static function println(s:String) - { - Sys.println(s); - } - - public static function runCommand(exe:String,args:Array,inPrint:Bool,inMultiThread:Bool):Int - { - if (exe.indexOf (" ") > -1) - { - var splitExe = exe.split (" "); - exe = splitExe.shift (); - args = splitExe.concat (args); - } - - var useSysCommand = !inMultiThread; - - if ( useSysCommand ) - { - if (inPrint) - println(exe + " " + args.join(" ")); - return Sys.command(exe,args); - } - else - { - var output = new Array(); - if (inPrint) - output.push(exe + " " + args.join(" ")); - var proc = new sys.io.Process(exe, args); - var err = proc.stderr; - var out = proc.stdout; - var reader = BuildTool.helperThread.value; - // Read stderr in separate hreead to avoid blocking ... - if (reader==null) - { - var contoller = Thread.current(); - BuildTool.helperThread.value = reader = Thread.create(function() - { - while(true) - { - var stream = Thread.readMessage(true); - var output:Array = null; - try - { - while(true) - { - var line = stream.readLine(); - if (output==null) - output = [ line ]; - else - output.push(line); - } - } - catch(e:Dynamic){ } - contoller.sendMessage(output); - } - }); - } - - // Start up the error reader ... - reader.sendMessage(err); - - try - { - while(true) - { - var line = out.readLine(); - output.push(line); - } - } - catch(e:Dynamic){ } - - var errOut:Array = Thread.readMessage(true); - - if (errOut!=null && errOut.length>0) - output = output.concat(errOut); - - if (output.length>0) - { - if (printMutex!=null) - printMutex.acquire(); - println(output.join("\n")); - if (printMutex!=null) - printMutex.release(); - } - - var code = proc.exitCode(); - proc.close(); - return code; - } - } - static function set64(outDefines:Hash, in64:Bool) { if (in64) @@ -1133,7 +1088,8 @@ class BuildTool var sub = mVarMatch.matched(1); if (sub.substr(0,8)=="haxelib:") { - sub = getHaxelib(sub.substr(8)); + sub = PathManager.getHaxelib(sub.substr(8)); + sub = PathManager.standardize(sub); } else sub = mDefines.get(sub); @@ -1147,15 +1103,65 @@ class BuildTool public function valid(inEl:Fast,inSection:String):Bool { - if (inEl.x.get("if")!=null) - if (!defined(inEl.x.get("if"))) return false; - + if (inEl.x.get("if") != null) + { + var value = inEl.x.get("if"); + var optionalDefines = value.split("||"); + var matchOptional = false; + for (optional in optionalDefines) + { + var requiredDefines = optional.split(" "); + var matchRequired = true; + for (required in requiredDefines) + { + var check = StringTools.trim(required); + if (check != "" && !defined(check)) + { + matchRequired = false; + } + } + if (matchRequired) + { + matchOptional = true; + } + } + if (optionalDefines.length > 0 && !matchOptional) + { + return false; + } + } + if (inEl.has.unless) - if (defined(inEl.att.unless)) return false; - + { + var value = substitute(inEl.att.unless); + var optionalDefines = value.split("||"); + var matchOptional = false; + for (optional in optionalDefines) + { + var requiredDefines = optional.split(" "); + var matchRequired = true; + for (required in requiredDefines) + { + var check = StringTools.trim(required); + if (check != "" && !defined(check)) + { + matchRequired = false; + } + } + if (matchRequired) + { + matchOptional = true; + } + } + if (optionalDefines.length > 0 && matchOptional) + { + return false; + } + } + if (inEl.has.ifExists) if (!FileSystem.exists( substitute(inEl.att.ifExists) )) return false; - + if (inSection!="") { if (inEl.name!="section") @@ -1165,7 +1171,7 @@ class BuildTool if (inEl.att.id!=inSection) return false; } - + return true; } } \ No newline at end of file diff --git a/tools/run/Compiler.hx b/tools/run/Compiler.hx index f87da9c5a..e68b85488 100644 --- a/tools/run/Compiler.hx +++ b/tools/run/Compiler.hx @@ -73,14 +73,12 @@ class Compiler public function compile(inFile:File,inTid:Int) { - var path = new Path(mObjDir + "/" + inFile.mName); var obj_name = getObjName(inFile); - var args = new Array(); args = args.concat(inFile.mCompilerFlags).concat(inFile.mGroup.mCompilerFlags).concat(mFlags); - var ext = path.ext.toLowerCase(); + var ext = mExt.toLowerCase(); addIdentity(ext,args); var allowPch = false; @@ -116,18 +114,18 @@ class Compiler var contents = sys.io.File.getContent(sourceName); if (contents!="") { - var md5 = haxe.crypto.Md5.encode(contents + args.join(" ") + + var md5 = Md5.encode(contents + args.join(" ") + inFile.mGroup.mDependHash + mCompilerVersion + inFile.mDependHash ); cacheName = BuildTool.compileCache + "/" + md5; if (FileSystem.exists(cacheName)) { sys.io.File.copy(cacheName, obj_name); - BuildTool.println("use cache for " + obj_name + "(" + md5 + ")" ); + LogManager.info("use cache for " + obj_name + "(" + md5 + ")" ); found = true; } else { - BuildTool.log(" not in cache " + cacheName); + LogManager.info("", " not in cache " + cacheName); } } else @@ -146,17 +144,31 @@ class Compiler } args.push(out + obj_name); - var result = BuildTool.runCommand( mExe, args, true, inTid>=0 ); - if (result!=0) + + var split = mExe.split (" "); + var exe = split.shift (); + args = split.concat (args); + + if (inTid >= 0) { - if (FileSystem.exists(obj_name)) - FileSystem.deleteFile(obj_name); - throw "Error : " + result + " - build cancelled"; + ProcessManager.runProcess("", exe, args); + } + else + { + var result = ProcessManager.runCommand("", exe, args); + if (result!=0) + { + if (FileSystem.exists(obj_name)) + FileSystem.deleteFile(obj_name); + Sys.exit (result); + //throw "Error : " + result + " - build cancelled"; + } } + if (cacheName!=null) { - sys.io.File.copy(obj_name, cacheName ); - BuildTool.log(" caching " + cacheName); + sys.io.File.copy(obj_name, cacheName); + LogManager.info("", " caching " + cacheName); } } @@ -177,14 +189,11 @@ class Compiler } var versionString = Setup.readStderr(exe,args).join(" "); - if (BuildTool.verbose) - { - BuildTool.println("--- Compiler verison ---" ); - BuildTool.println( versionString ); - BuildTool.println("------------------"); - } + LogManager.info("", "--- Compiler version ---"); + LogManager.info("", versionString); + LogManager.info("", "------------------------"); - mCompilerVersion = haxe.crypto.Md5.encode(versionString); + mCompilerVersion = Md5.encode(versionString); mCached = true; } @@ -214,8 +223,8 @@ class Compiler var dir = inObjDir + "/" + inGroup.getPchDir() + "/"; var pch_name = dir + file + mPCHExt; - BuildTool.log("Make pch dir " + dir ); - DirManager.make(dir); + //LogManager.info("", "Make pch dir " + dir ); + PathManager.mkdir(dir); if (mPCH!="gcc") { @@ -233,20 +242,26 @@ class Compiler } else { - BuildTool.log("Make pch dir " + dir + header ); - DirManager.make(dir + header); + //LogManager.info("", "Creating PCH directory \"" + dir + header + "\""); + PathManager.mkdir(dir + header); args.push( "-o" ); args.push(pch_name); args.push( inGroup.mPrecompiledHeaderDir + "/" + inGroup.mPrecompiledHeader + ".h" ); } - BuildTool.println("Creating " + pch_name + "..."); - var result = BuildTool.runCommand( mExe, args, true, false ); + //LogManager.info("Creating " + pch_name + "..."); + + var split = mExe.split (" "); + var exe = split.shift (); + args = split.concat (args); + + var result = ProcessManager.runCommand("", exe, args, true, false, true); if (result!=0) { if (FileSystem.exists(pch_name)) FileSystem.deleteFile(pch_name); - throw "Error creating pch: " + result + " - build cancelled"; + LogManager.error("Could not create PCH"); + //throw "Error creating pch: " + result + " - build cancelled"; } } diff --git a/tools/run/File.hx b/tools/run/File.hx index 0d09c5b0c..2a909368c 100644 --- a/tools/run/File.hx +++ b/tools/run/File.hx @@ -50,14 +50,20 @@ class File var source_name = mDir+mName; if (!FileSystem.exists(source_name)) - throw "Could not find source '" + source_name + "'"; + { + LogManager.error("Could not find source file \"" + source_name + "\""); + //throw "Could not find source '" + source_name + "'"; + } var source_stamp = FileSystem.stat(source_name).mtime.getTime(); if (obj_stamp < source_stamp) return true; for(depend in mDepends) { if (!FileSystem.exists(depend)) - throw "Could not find dependency '" + depend + "' for '" + mName + "'"; + { + LogManager.error("Could not find dependency \"" + depend + "\" for \"" + mName + "\""); + //throw "Could not find dependency '" + depend + "' for '" + mName + "'"; + } if (FileSystem.stat(depend).mtime.getTime() > obj_stamp ) return true; } diff --git a/tools/run/FileGroup.hx b/tools/run/FileGroup.hx index 519dbf542..67e80cce7 100644 --- a/tools/run/FileGroup.hx +++ b/tools/run/FileGroup.hx @@ -64,7 +64,10 @@ class FileGroup public function checkDependsExist() { if (mMissingDepends.length>0) - throw "Could not find dependencies: " + mMissingDepends.join(","); + { + LogManager.error("Could not find dependencies: [ " + mMissingDepends.join (", ") + " ]"); + //throw "Could not find dependencies: " + mMissingDepends.join(","); + } } public function checkOptions(inObjDir:String) @@ -80,7 +83,7 @@ class FileGroup { var contents = sys.io.File.getContent(option); - var dest = inObjDir + "/" + haxe.io.Path.withoutDirectory(option); + var dest = inObjDir + "/" + Path.withoutDirectory(option); var skip = false; if (FileSystem.exists(dest)) @@ -91,7 +94,7 @@ class FileGroup } if (!skip) { - DirManager.make(inObjDir); + PathManager.mkdir(inObjDir); var stream = sys.io.File.write(dest,true); stream.writeString(contents); stream.close(); diff --git a/tools/run/HLSL.hx b/tools/run/HLSL.hx index 70ffceafd..223145d5b 100644 --- a/tools/run/HLSL.hx +++ b/tools/run/HLSL.hx @@ -20,20 +20,24 @@ class HLSL { if (!FileSystem.exists(Path.directory (target))) { - DirManager.make(Path.directory (target)); + PathManager.mkdir(Path.directory (target)); } - DirManager.makeFileDir(target); + //DirManager.makeFileDir(target); var srcStamp = FileSystem.stat(file).mtime.getTime(); if (!FileSystem.exists(target) || FileSystem.stat(target).mtime.getTime() < srcStamp) { var exe = "fxc.exe"; var args = [ "/nologo", "/T", profile, file, "/Vn", variable, "/Fh", target ]; - var result = BuildTool.runCommand(exe,args,BuildTool.verbose,false); + + LogManager.info("", exe + " " + args.join(" ")); + + var result = ProcessManager.runCommand("", exe, args); if (result!=0) { - throw "Error : Could not compile shader " + file + " - build cancelled"; + LogManager.error("Could not compile shader \"" + file + "\""); + //throw "Error : Could not compile shader " + file + " - build cancelled"; } } } diff --git a/tools/run/Linker.hx b/tools/run/Linker.hx index e05ef67ea..d83f860a9 100644 --- a/tools/run/Linker.hx +++ b/tools/run/Linker.hx @@ -38,8 +38,11 @@ class Linker for(obj in inObjs) { if (!FileSystem.exists(obj)) - throw "Could not find " + obj + " required by " + inName; - var obj_stamp = FileSystem.stat(obj).mtime.getTime(); + { + LogManager.error("Could not find \"" + obj + "\" required by \"" + inName + "\""); + //throw "Could not find " + obj + " required by " + inName; + } + var obj_stamp = FileSystem.stat(obj).mtime.getTime(); if (obj_stamp > stamp) return true; } @@ -50,10 +53,17 @@ class Linker { var ext = inTarget.mExt=="" ? mExt : inTarget.mExt; var file_name = mNamePrefix + inTarget.mOutput + ext; - if(!DirManager.make(inTarget.mOutputDir)) + + try { - throw "Unable to create output directory " + inTarget.mOutputDir; + PathManager.mkdir(inTarget.mOutputDir); } + catch (e:Dynamic) + { + LogManager.error("Unable to create output directory \"" + inTarget.mOutputDir + "\""); + //throw "Unable to create output directory " + inTarget.mOutputDir; + } + var out_name = inTarget.mOutputDir + file_name; var libs = inTarget.mLibs.concat(mLibs); @@ -72,7 +82,7 @@ class Linker var current = parts[0] + "-" + BuildTool.getMsvcVer() + parts[1]; if (FileSystem.exists(current)) { - BuildTool.log("Using current compiler library " + current); + LogManager.info("", "Using current compiler library " + current); libs[i]=current; } else @@ -80,7 +90,7 @@ class Linker var v18 = parts[0] + "-18" + parts[1]; if (FileSystem.exists(v18)) { - BuildTool.log("Using msvc18 compatible library " + v18); + LogManager.info("", "Using msvc18 compatible library " + v18); libs[i]=v18; if (!v18Added) { @@ -118,14 +128,14 @@ class Linker // creates stays out of the way if (mLibDir!="") { - DirManager.make(mLibDir); + PathManager.mkdir(mLibDir); args.push(out + mLibDir + "/" + file_name); } else { if (mRecreate && FileSystem.exists(out_name)) { - BuildTool.println(" clean " + out_name ); + LogManager.info(" clean " + out_name ); FileSystem.deleteFile(out_name); } args.push(out + out_name); @@ -144,13 +154,10 @@ class Linker if (isArchive.match(lib)) { var libName = Path.withoutDirectory(lib); - var libObjs = Setup.readStdout( mExe , ["t", lib] ); + var libObjs = Setup.readStdout(mExe, ["t", lib ]); var objDir = inCompiler.mObjDir + "/" + libName; - DirManager.make(objDir); - var here = Sys.getCwd(); - Sys.setCwd(objDir); - BuildTool.runCommand( mExe , ["x", lib], true, false ); - Sys.setCwd(here); + PathManager.mkdir(objDir); + ProcessManager.runCommand (objDir, mExe, ["x", lib], true, false, true); for(obj in libObjs) objs.push( objDir+"/"+obj ); } @@ -174,17 +181,27 @@ class Linker args = args.concat(objs); args = args.concat(libs); - - var result = BuildTool.runCommand( mExe, args, true, false ); + + var split = mExe.split (" "); + var exe = split.shift (); + args = split.concat (args); + + var result = ProcessManager.runCommand("", exe, args, true, false, true); if (result!=0) - throw "Error : " + result + " - build cancelled"; + { + Sys.exit(result); + //throw "Error : " + result + " - build cancelled"; + } if (mRanLib!="") { args = [out_name]; - var result = BuildTool.runCommand( mRanLib, args, true, false ); + var result = ProcessManager.runCommand("", mRanLib, args, true, false, true); if (result!=0) - throw "Error : " + result + " - build cancelled"; + { + Sys.exit(result); + //throw "Error : " + result + " - build cancelled"; + } } if (mLibDir!="") @@ -192,7 +209,7 @@ class Linker sys.io.File.copy( mLibDir+"/"+file_name, out_name ); FileSystem.deleteFile( mLibDir+"/"+file_name ); } - return out_name; + return out_name; } return ""; diff --git a/tools/run/LogManager.hx b/tools/run/LogManager.hx new file mode 100644 index 000000000..e2e2b86b1 --- /dev/null +++ b/tools/run/LogManager.hx @@ -0,0 +1,123 @@ +import haxe.io.Bytes; +import sys.io.Process; +#if neko +import neko.Lib; +#else +import cpp.Lib; +#end + +class LogManager +{ + public static var mute:Bool; + public static var verbose:Bool = false; + + private static var colorCodes:EReg = ~/\x1b\[[^m]+m/g; + private static var colorSupported:Null; + private static var sentWarnings = new Map(); + + public static function error(message:String, verboseMessage:String = "", e:Dynamic = null):Void + { + if (message != "" && !mute) + { + var output; + if (verbose && verboseMessage != "") + { + output = "\x1b[31;1mError:\x1b[0m\x1b[1m " + verboseMessage + "\x1b[0m\n"; + } + else + { + output = "\x1b[31;1mError:\x1b[0m \x1b[1m" + message + "\x1b[0m\n"; + } + Sys.stderr().write(Bytes.ofString(stripColor(output))); + } + + if (verbose && e != null) + { + Lib.rethrow(e); + } + + Sys.exit(1); + } + + public static function info(message:String, verboseMessage:String = ""):Void + { + if (!mute) + { + if (verbose && verboseMessage != "") + { + println(verboseMessage); + } + else if (message != "") + { + println(message); + } + } + } + + public static function print(message:String):Void + { + Sys.print(stripColor(message)); + } + + public static function println(message:String):Void + { + Sys.println(stripColor(message)); + } + + private static function stripColor(output:String):String + { + if (colorSupported == null) + { + if (!BuildTool.isWindows) + { + var result = -1; + try + { + var process = new Process ("tput", [ "colors" ]); + result = process.exitCode (); + process.close (); + } + catch (e:Dynamic) {}; + + colorSupported = (result == 0); + } + else + { + colorSupported = (Sys.getEnv("ANSICON") != null); + } + } + + if (colorSupported) + { + return output; + } + else + { + return colorCodes.replace(output, ""); + } + } + + public static function warn(message:String, verboseMessage:String = "", allowRepeat:Bool = false):Void + { + if (!mute) + { + var output = ""; + if (verbose && verboseMessage != "") + { + output = "\x1b[33;1mWarning:\x1b[0m \x1b[1m" + verboseMessage + "\x1b[0m"; + } + else if (message != "") + { + output = "\x1b[33;1mWarning:\x1b[0m \x1b[1m" + message + "\x1b[0m"; + } + + if (!allowRepeat && sentWarnings.exists (output)) + { + return; + } + + sentWarnings.set(output, true); + println(output); + } + } +} \ No newline at end of file diff --git a/tools/run/PathManager.hx b/tools/run/PathManager.hx new file mode 100644 index 000000000..150cff4bb --- /dev/null +++ b/tools/run/PathManager.hx @@ -0,0 +1,299 @@ +import sys.FileSystem; + +class PathManager +{ + private static var directoryCache = new Map(); + private static var haxelibPaths = new Map(); + + public static function combine(firstPath:String, secondPath:String):String + { + if (firstPath == null || firstPath == "") + { + return secondPath; + } + else if (secondPath != null && secondPath != "") + { + if (BuildTool.isWindows) + { + if (secondPath.indexOf (":") == 1) + { + return secondPath; + } + } + else + { + if (secondPath.substr (0, 1) == "/") + { + return secondPath; + } + } + + var firstSlash = (firstPath.substr(-1) == "/" || firstPath.substr(-1) == "\\"); + var secondSlash = (secondPath.substr(0, 1) == "/" || secondPath.substr(0, 1) == "\\"); + + if (firstSlash && secondSlash) + { + return firstPath + secondPath.substr(1); + } + else if (!firstSlash && !secondSlash) + { + return firstPath + "/" + secondPath; + } + else + { + return firstPath + secondPath; + } + } + else + { + return firstPath; + } + } + + public static function escape(path:String):String + { + if (!BuildTool.isWindows) + { + path = StringTools.replace(path, "\\ ", " "); + path = StringTools.replace(path, " ", "\\ "); + path = StringTools.replace(path, "\\'", "'"); + path = StringTools.replace(path, "'", "\\'"); + } + else + { + path = StringTools.replace(path, "^,", ","); + path = StringTools.replace(path, ",", "^,"); + } + return expand(path); + } + + public static function expand(path:String):String + { + if (path == null) + { + path = ""; + } + + if (!BuildTool.isWindows) + { + if (StringTools.startsWith(path, "~/")) + { + path = Sys.getEnv("HOME") + "/" + path.substr(2); + } + } + + return path; + } + + public static function getHaxelib (haxelib:String, version:String = "", validate:Bool = false, clearCache:Bool = false):String + { + var name = haxelib; + if (version != "") + { + name += ":" + version; + } + + if (clearCache) + { + haxelibPaths.remove(name); + } + + if (!haxelibPaths.exists(name)) + { + var cache = LogManager.verbose; + LogManager.verbose = false; + var output = ""; + + try + { + output = ProcessManager.runProcess(Sys.getEnv ("HAXEPATH"), "haxelib", [ "path", name ], true, true, true); + } + catch (e:Dynamic) {} + + LogManager.verbose = cache; + + var lines = output.split("\n"); + var result = ""; + + for (i in 1...lines.length) + { + if (StringTools.trim(lines[i]) == "-D " + haxelib) + { + result = StringTools.trim(lines[i - 1]); + } + } + + if (validate) + { + if (result == "") + { + if (output.indexOf("does not have") > -1) + { + var directoryName = ""; + if (BuildTool.isWindows) + { + directoryName = "Windows"; + } + else if (BuildTool.isMac) + { + directoryName = BuildTool.is64 ? "Mac64" : "Mac"; + } + else + { + directoryName = BuildTool.is64 ? "Linux64" : "Linux"; + } + + LogManager.error ("haxelib \"" + haxelib + "\" does not have an \"ndll/" + directoryName + "\" directory"); + } + else + { + if (version != "") + { + LogManager.error("Could not find haxelib \"" + haxelib + "\" version \"" + version + "\", does it need to be installed?"); + } + else + { + LogManager.error("Could not find haxelib \"" + haxelib + "\", does it need to be installed?"); + } + } + } + } + + haxelibPaths.set(name,result); + } + + return haxelibPaths.get(name); + } + + public static function mkdir(directory:String):Void + { + directory = StringTools.replace(directory, "\\", "/"); + var total = ""; + + if (directory.substr(0, 1) == "/") + { + total = "/"; + } + + var parts = directory.split("/"); + var oldPath = ""; + + if (parts.length > 0 && parts[0].indexOf(":") > -1) + { + oldPath = Sys.getCwd(); + Sys.setCwd(parts[0] + "\\"); + parts.shift(); + } + + for (part in parts) + { + if (part != "." && part != "") + { + if (total != "" && total != "/") + { + total += "/"; + } + + total += part; + + if (!directoryCache.exists (total)) + { + directoryCache.set(total, true); + if (!FileSystem.exists(total)) + { + LogManager.info("", " - \x1b[1mCreating directory:\x1b[0m " + total); + FileSystem.createDirectory(total); + } + } + } + } + + if (oldPath != "") + { + Sys.setCwd(oldPath); + } + } + + public static function removeDirectory(directory:String):Void + { + if (FileSystem.exists(directory)) + { + var files; + try + { + files = FileSystem.readDirectory(directory); + } + catch (e:Dynamic) + { + return; + } + + for (file in FileSystem.readDirectory(directory)) + { + var path = directory + "/" + file; + try + { + if (FileSystem.isDirectory(path)) + { + removeDirectory(path); + } + else + { + FileSystem.deleteFile(path); + } + } + catch (e:Dynamic) {} + } + + LogManager.info("", " - \x1b[1mRemoving directory:\x1b[0m " + directory); + + try + { + FileSystem.deleteDirectory(directory); + } + catch (e:Dynamic) {} + } + } + + static public function removeFile(file:String) + { + if (FileSystem.exists(file)) + { + LogManager.info("", " - \x1b[1mRemoving file:\x1b[0m " + file); + FileSystem.deleteFile(file); + } + } + + static public function removeFilesWithExtension(inExt:String) + { + var contents = FileSystem.readDirectory("."); + for(item in contents) + { + if (item.length > inExt.length && item.substr(item.length-inExt.length)==inExt) + removeFile(item); + } + } + + public static function resetDirectoryCache():Void + { + directoryCache = new Map(); + } + + public static function standardize(path:String, trailingSlash:Bool = false):String + { + path = StringTools.replace (path, "\\", "/"); + path = StringTools.replace (path, "//", "/"); + path = StringTools.replace (path, "//", "/"); + + if (!trailingSlash && StringTools.endsWith(path, "/")) + { + path = path.substr(0, path.length - 1); + } + else if (trailingSlash && !StringTools.endsWith(path, "/")) + { + path += "/"; + } + + return path; + } +} \ No newline at end of file diff --git a/tools/run/ProcessManager.hx b/tools/run/ProcessManager.hx new file mode 100644 index 000000000..d0162abfd --- /dev/null +++ b/tools/run/ProcessManager.hx @@ -0,0 +1,244 @@ +import haxe.io.BytesOutput; +import haxe.io.Eof; +import haxe.io.Path; +import sys.io.Process; +import sys.FileSystem; + +class ProcessManager +{ + public static function runCommand(path:String, command:String, args:Array, safeExecute:Bool = true, ignoreErrors:Bool = false, print:Bool = false):Int + { + if (print) + { + var message = command; + for (arg in args) + { + if (arg.indexOf(" ") > -1) + { + message += " \"" + arg + "\""; + } + else + { + message += " " + arg; + } + } + LogManager.info(message); + } + + command = PathManager.escape(command); + + if (safeExecute) + { + try + { + if (path != null && path != "" && !FileSystem.exists(FileSystem.fullPath(path)) && !FileSystem.exists(FileSystem.fullPath(new Path(path).dir))) + { + LogManager.error ("The specified target path \"" + path + "\" does not exist"); + return 1; + } + return _runCommand(path, command, args); + } + catch (e:Dynamic) + { + if (!ignoreErrors) + { + LogManager.error("", e); + return 1; + } + return 0; + } + } + else + { + return _runCommand(path, command, args); + } + } + + public static function runProcess(path:String, command:String, args:Array, waitForOutput:Bool = true, safeExecute:Bool = true, ignoreErrors:Bool = false, print:Bool = false):String + { + if (print) + { + var message = command; + for (arg in args) + { + if (arg.indexOf(" ") > -1) + { + message += " \"" + arg + "\""; + } + else + { + message += " " + arg; + } + } + LogManager.info(message); + } + + command = PathManager.escape(command); + + if (safeExecute) + { + try + { + if (path != null && path != "" && !FileSystem.exists(FileSystem.fullPath(path)) && !FileSystem.exists(FileSystem.fullPath(new Path(path).dir))) + { + LogManager.error("The specified target path \"" + path + "\" does not exist"); + } + return _runProcess(path, command, args, waitForOutput, ignoreErrors); + } + catch (e:Dynamic) + { + if (!ignoreErrors) + { + LogManager.error("", e); + } + return null; + } + } + else + { + return _runProcess(path, command, args, waitForOutput, ignoreErrors); + } + } + + private static function _runCommand(path:String, command:String, args:Array):Int + { + var oldPath:String = ""; + + if (path != null && path != "") + { + LogManager.info("", " - \x1b[1mChanging directory:\x1b[0m " + path + ""); + + oldPath = Sys.getCwd(); + Sys.setCwd(path); + } + + var argString = ""; + + for (arg in args) + { + if (arg.indexOf(" ") > -1) + { + argString += " \"" + arg + "\""; + } + else + { + argString += " " + arg; + } + } + + LogManager.info("", " - \x1b[1mRunning command:\x1b[0m " + command + argString); + + var result = 0; + + if (args != null && args.length > 0) + { + result = Sys.command(command, args); + } + else + { + result = Sys.command(command); + } + + if (oldPath != "") + { + Sys.setCwd(oldPath); + } + + if (result != 0) + { + throw ("Error running: " + command + " " + args.join (" ") + " [" + path + "]"); + } + + return result; + } + + private static function _runProcess(path:String, command:String, args:Array, waitForOutput:Bool, ignoreErrors:Bool):String + { + var oldPath:String = ""; + + if (path != null && path != "") + { + LogManager.info("", " - \x1b[1mChanging directory:\x1b[0m " + path + ""); + + oldPath = Sys.getCwd(); + Sys.setCwd(path); + } + + var argString = ""; + + for (arg in args) + { + if (arg.indexOf(" ") > -1) + { + argString += " \"" + arg + "\""; + } + else + { + argString += " " + arg; + } + } + + LogManager.info("", " - \x1b[1mRunning process:\x1b[0m " + command + argString); + + var output = ""; + var result = 0; + + var process = new Process(command, args); + var buffer = new BytesOutput(); + + if (waitForOutput) + { + var waiting = true; + while (waiting) + { + try + { + var current = process.stdout.readAll(1024); + buffer.write(current); + if (current.length == 0) + { + waiting = false; + } + } + catch (e:Eof) + { + waiting = false; + } + } + + result = process.exitCode(); + process.close(); + + //if (result == 0) + //{ + output = buffer.getBytes().toString(); + if (output == "") + { + var error = process.stderr.readAll().toString(); + if (ignoreErrors) + { + output = error; + } + else + { + LogManager.error(error); + } + + return null; + + /*if (error != "") + { + LogManager.error(error); + }*/ + } + //} + } + + if (oldPath != "") + { + Sys.setCwd(oldPath); + } + + return output; + } +} \ No newline at end of file diff --git a/tools/run/Setup.hx b/tools/run/Setup.hx index 609267279..c12e26215 100644 --- a/tools/run/Setup.hx +++ b/tools/run/Setup.hx @@ -14,7 +14,8 @@ class Setup } catch (e:Dynamic) { - throw 'ANDROID_NDK_DIR "$inDir" does not point to a valid directory.'; + LogManager.error('ANDROID_NDK_DIR "$inDir" does not point to a valid directory'); + //throw 'ANDROID_NDK_DIR "$inDir" does not point to a valid directory.'; } var extract_version = ~/^android-ndk-r(\d+)([a-z]?)$/; @@ -33,16 +34,15 @@ class Setup result = inDir + "/" + file; } } + + LogManager.info("", "Found NDK " + result); - if (BuildTool.verbose) + if (result=="") { - var message = "Found NDK " + result; - BuildTool.println(message); + LogManager.error('ANDROID_NDK_DIR "$inDir" does not contain matching NDK downloads'); + //throw 'ANDROID_NDK_DIR "$inDir" does not contain matching ndk downloads.'; } - if (result=="") - throw 'ANDROID_NDK_DIR "$inDir" does not contain matching ndk downloads.'; - return result; } @@ -71,7 +71,8 @@ class Setup home = env.get("USERPROFILE"); else { - Sys.println("Warning: No 'HOME' variable set - .hxcpp_config.xml might be missing."); + LogManager.warn("No $HOME variable set, \".hxcpp_config.xml\" might be missing"); + //Sys.println("Warning: No 'HOME' variable set - .hxcpp_config.xml might be missing."); return; } @@ -80,17 +81,18 @@ class Setup if (BuildTool.HXCPP!="") { - var src = toPath(BuildTool.HXCPP + "build-tool/example.hxcpp_config.xml"); + var src = toPath(BuildTool.HXCPP + "/build-tool/example.hxcpp_config.xml"); if (!sys.FileSystem.exists(config)) { - try { - if (BuildTool.verbose) - BuildTool.println("Copy config: " + src + " -> " + config ); - + try + { + LogManager.info("", "Copying HXCPP config \"" + src + "\" to \"" + config + "\""); sys.io.File.copy(src,config); - } catch(e:Dynamic) + } + catch(e:Dynamic) { - Sys.println("Warning : could not create config: " + config ); + LogManager.warn("Could not create HXCPP config \"" + config + "\""); + //Sys.println("Warning : could not create config: " + config ); } } } @@ -139,133 +141,138 @@ class Setup public static function setup(inWhat:String,ioDefines: Map) { if (inWhat=="androidNdk") + { setupAndroidNdk(ioDefines); + } else if (inWhat=="msvc") + { setupMSVC(ioDefines, ioDefines.exists("HXCPP_M64")); + } else - throw 'Unknown setup feature $inWhat'; + { + LogManager.error('Unknown setup feature "$inWhat"'); + //throw 'Unknown setup feature $inWhat'; + } } static public function setupAndroidNdk(defines:Map) { - var root:String = null; + var root:String = null; - if (!defines.exists("ANDROID_NDK_ROOT")) - { - if (defines.exists("ANDROID_NDK_DIR")) - { - root = Setup.findAndroidNdkRoot( defines.get("ANDROID_NDK_DIR") ); - if (BuildTool.verbose) - BuildTool.println("Using found ndk root " + root); + if (!defines.exists("ANDROID_NDK_ROOT")) + { + if (defines.exists("ANDROID_NDK_DIR")) + { + root = Setup.findAndroidNdkRoot( defines.get("ANDROID_NDK_DIR") ); + LogManager.info("", "Using found NDK root \"" + root + "\""); - Sys.putEnv("ANDROID_NDK_ROOT", root); - defines.set("ANDROID_NDK_ROOT", root); - } - else - throw "ANDROID_NDK_ROOT or ANDROID_NDK_DIR should be set"; - } - else - { - root = defines.get("ANDROID_NDK_ROOT"); - if (BuildTool.verbose) - BuildTool.println("Using specified ndk root " + root); - } + Sys.putEnv("ANDROID_NDK_ROOT", root); + defines.set("ANDROID_NDK_ROOT", root); + } + else + { + LogManager.error("Could not find ANDROID_NDK_ROOT or ANDROID_NDK_DIR variable"); + //throw "ANDROID_NDK_ROOT or ANDROID_NDK_DIR should be set"; + } + } + else + { + root = defines.get("ANDROID_NDK_ROOT"); + LogManager.info("", "Using specified NDK root \"" + root + "\""); + } - // Find toolchain - if (!defines.exists("TOOLCHAIN_VERSION")) - { - try - { - var files = FileSystem.readDirectory(root+"/toolchains"); + // Find toolchain + if (!defines.exists("TOOLCHAIN_VERSION")) + { + try + { + var files = FileSystem.readDirectory(root+"/toolchains"); - // Prefer clang? - var extract_version = ~/^arm-linux-androideabi-(\d.*)/; - var bestVer=""; - for(file in files) - { - if (extract_version.match(file)) - { - var ver = extract_version.matched(1); - if ( ver>bestVer || bestVer=="") - { - bestVer = ver; - } - } - } - if (bestVer!="") - { - defines.set("TOOLCHAIN_VERSION",bestVer); - if (BuildTool.verbose) - BuildTool.println("Found TOOLCHAIN_VERSION " + bestVer); - } - } - catch(e:Dynamic) { } - } + // Prefer clang? + var extract_version = ~/^arm-linux-androideabi-(\d.*)/; + var bestVer=""; + for(file in files) + { + if (extract_version.match(file)) + { + var ver = extract_version.matched(1); + if ( ver>bestVer || bestVer=="") + { + bestVer = ver; + } + } + } + if (bestVer!="") + { + defines.set("TOOLCHAIN_VERSION",bestVer); + LogManager.info("", "Found TOOLCHAIN_VERSION " + bestVer); + } + } + catch(e:Dynamic) { } + } - // See what ANDROID_HOST to use ... - try - { - var prebuilt = root+"/toolchains/arm-linux-androideabi-" + defines.get("TOOLCHAIN_VERSION") + "/prebuilt"; - var files = FileSystem.readDirectory(prebuilt); - if (files.length==1) - { - defines.set("ANDROID_HOST", files[0]); - if (BuildTool.verbose) - { - BuildTool.println("Found ANDROID_HOST " + files[0]); - } - } - else if (BuildTool.verbose) - BuildTool.println("Could not work out ANDROID_HOST (" + files + ") - using default"); - } - catch(e:Dynamic) { } + // See what ANDROID_HOST to use ... + try + { + var prebuilt = root+"/toolchains/arm-linux-androideabi-" + defines.get("TOOLCHAIN_VERSION") + "/prebuilt"; + var files = FileSystem.readDirectory(prebuilt); + if (files.length==1) + { + defines.set("ANDROID_HOST", files[0]); + LogManager.info("", "Found ANDROID_HOST " + files[0]); + } + else + { + LogManager.info("", "Could not work out ANDROID_HOST (" + files + ") - using default"); + } + } + catch(e:Dynamic) { } - var found = false; - for(i in 6...20) - if (defines.exists("NDKV" + i)) - { - found = true; - if (BuildTool.verbose) - BuildTool.println("Using specified android NDK " + i); - break; - } - if (!found) - { - var version = Setup.getNdkVersion( defines.get("ANDROID_NDK_ROOT") ); - if (BuildTool.verbose) - BuildTool.println("Deduced android NDK " + version); - defines.set("NDKV" + version, "1" ); - } + var found = false; + for(i in 6...20) + if (defines.exists("NDKV" + i)) + { + found = true; + LogManager.info("", "Using specified android NDK " + i); + break; + } + if (!found) + { + var version = Setup.getNdkVersion( defines.get("ANDROID_NDK_ROOT") ); + LogManager.info("", "Deduced android NDK " + version); + defines.set("NDKV" + version, "1" ); + } - if (defines.exists("PLATFORM")) - { - BuildTool.log("Using specified android PLATFORM " + defines.get("PLATFORM") ); - } - else - { - var base = defines.get("ANDROID_NDK_ROOT") + "/platforms"; - var best = 0; - try - { - for(file in FileSystem.readDirectory(base)) - { - if (file.substr(0,8)=="android-") - { - var platform = Std.parseInt(file.substr(8)); - if (platform>best) - best = platform; - } - } - } catch(e:Dynamic) - { - } + if (defines.exists("PLATFORM")) + { + LogManager.info("", "Using specified android PLATFORM " + defines.get("PLATFORM")); + } + else + { + var base = defines.get("ANDROID_NDK_ROOT") + "/platforms"; + var best = 0; + try + { + for(file in FileSystem.readDirectory(base)) + { + if (file.substr(0,8)=="android-") + { + var platform = Std.parseInt(file.substr(8)); + if (platform>best) + best = platform; + } + } + } catch(e:Dynamic) {} - if (best==0) - throw "Could not find platform in " + base; + if (best==0) + { + LogManager.error("Could not find NDK platform in \"" + base + "\""); + //throw "Could not find platform in " + base; + } - BuildTool.log("Using biggest platform " + best); - defines.set("PLATFORM", "android-" + best ); - } + LogManager.info("", "Using newest NDK platform: " + best); + defines.set("PLATFORM", "android-" + best); + } } public static function setupBlackBerryNativeSDK(ioDefines:Hash) @@ -355,17 +362,21 @@ class Setup for(env in Sys.environment().keys()) { if (env.substr(0,2)=="VS") - Sys.println("Found VS variable " + env); + { + LogManager.info("Found VS variable: " + env); + //Sys.println("Found VS variable " + env); + } } - throw "Could not find specified MSCV version " + ival; + LogManager.error("Could not find specified MSCV version: " + ival); + //throw "Could not find specified MSCV version " + ival; } ioDefines.set("HXCPP_MSVC", where ); Sys.putEnv("HXCPP_MSVC", where); - BuildTool.log('Using MSVC Ver $ival in $where ($varName)'); + LogManager.info("", 'Using MSVC Ver $ival in $where ($varName)'); } else { - BuildTool.log('Using specified MSVC Ver $val'); + LogManager.info("", 'Using specified MSVC Ver $val'); ioDefines.set("HXCPP_MSVC", val ); Sys.putEnv("HXCPP_MSVC", val); } @@ -382,7 +393,7 @@ class Setup xpCompat = true; } - var vc_setup_proc = new Process("cmd.exe", ["/C", BuildTool.HXCPP + "build-tool\\msvc" + extra + "-setup.bat" ]); + var vc_setup_proc = new Process("cmd.exe", ["/C", BuildTool.HXCPP + "\\build-tool\\msvc" + extra + "-setup.bat" ]); var vars_found = false; var error_string = ""; var output = new Array(); @@ -422,13 +433,23 @@ class Setup if (!vars_found || error_string!="") { for(o in output) - BuildTool.println(o); + { + LogManager.info(o); + //BuildTool.println(o); + } if (error_string!="") - throw(error_string); + { + LogManager.error (error_string); + //throw(error_string); + } else - BuildTool.println("Missing HXCPP_VARS"); - - throw("Could not automatically setup MSVC"); + { + LogManager.info("Missing HXCPP_VARS"); + //BuildTool.println("Missing HXCPP_VARS"); + } + + LogManager.error("Could not automatically setup MSVC"); + //throw("Could not automatically setup MSVC"); } } @@ -443,8 +464,7 @@ class Setup if (reg.match(str)) { var cl_version = Std.parseInt(reg.matched(1)); - if (BuildTool.verbose) - BuildTool.println("Using msvc cl version " + cl_version); + LogManager.info("", "Using msvc cl version " + cl_version); ioDefines.set("MSVC_VER", cl_version+""); if (cl_version>=17) ioDefines.set("MSVC17+","1"); diff --git a/tools/run/Stripper.hx b/tools/run/Stripper.hx index 341fd19e0..7ec1248f7 100644 --- a/tools/run/Stripper.hx +++ b/tools/run/Stripper.hx @@ -14,9 +14,16 @@ class Stripper var args = new Array(); args = args.concat(mFlags); args.push(inTarget); + + var split = mExe.split(" "); + var exe = split.shift(); + args = split.concat(args); - var result = BuildTool.runCommand( mExe, args, true,false ); + var result = ProcessManager.runCommand("", exe, args, true, false, true); if (result!=0) - throw "Error : " + result + " - build cancelled"; + { + Sys.exit(result); + //throw "Error : " + result + " - build cancelled"; + } } } \ No newline at end of file diff --git a/tools/run/Target.hx b/tools/run/Target.hx index fd216facc..1368aff59 100644 --- a/tools/run/Target.hx +++ b/tools/run/Target.hx @@ -47,16 +47,19 @@ class Target public function checkError() { - if (mErrors.length>0) - throw mErrors.join("/"); + if (mErrors.length>0) + { + LogManager.error(mErrors.join(", ")); + //throw mErrors.join("/"); + } } public function clean() { for(dir in mDirs) { - BuildTool.println("Remove " + dir + "..."); - DirManager.deleteRecurse(dir); + LogManager.info("Remove " + dir + "..."); + PathManager.removeDirectory(dir); } } From 2ecbcba66aee49b54e639d3f26b377769ef0dc5f Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Mon, 24 Mar 2014 23:55:11 -0700 Subject: [PATCH 4/6] Tool fixes --- .gitignore | 2 + run.n | Bin 118973 -> 120323 bytes tools/run/BuildTool.hx | 17 ++-- tools/run/Compiler.hx | 4 +- tools/run/HLSL.hx | 2 +- tools/run/Linker.hx | 6 +- tools/run/LogManager.hx | 2 +- tools/run/PathManager.hx | 12 +-- tools/run/ProcessManager.hx | 194 ++++++++++++++++++++++++++++++------ tools/run/Stripper.hx | 2 +- 10 files changed, 190 insertions(+), 51 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..c6e49efc9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +obj/ +bin/ diff --git a/run.n b/run.n index e636a743b9f12b3e0ea66735ba4cf13d2222b2ff..cea3b1916b539541259516ceea56f96e1ce36e12 100644 GIT binary patch delta 44012 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 delta 43194 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 R#-Mm-5(d*{-yBca@IS~=Hq!tA diff --git a/tools/run/BuildTool.hx b/tools/run/BuildTool.hx index 9b7563a1c..a369f8fb6 100644 --- a/tools/run/BuildTool.hx +++ b/tools/run/BuildTool.hx @@ -6,7 +6,6 @@ import sys.FileSystem; import neko.vm.Thread; import neko.vm.Mutex; import neko.vm.Tls; -import neko.vm.Tls; #else import cpp.vm.Thread; import cpp.vm.Mutex; @@ -39,7 +38,8 @@ class BuildTool public static var compileCache:String; public static var targetKey:String; public static var instance:BuildTool; - static var printMutex:Mutex; + public static var helperThread = new Tls(); + public static var printMutex:Mutex; static var mVarMatch = new EReg("\\${(.*?)}",""); public function new(inMakefile:String,inDefines:Hash,inTargets:Array, @@ -162,7 +162,8 @@ class BuildTool if (target.mBuildDir!="") { restoreDir = Sys.getCwd(); - LogManager.info("", "Enter \"" + target.mBuildDir + "\""); + Sys.println(target.mBuildDir); + LogManager.info("", "\x1b[1mChanging directory:\x1b[0m " + target.mBuildDir); Sys.setCwd(target.mBuildDir); } @@ -307,7 +308,7 @@ class BuildTool if (target.mBuildDir!="") { restoreDir = Sys.getCwd(); - LogManager.info("", "Enter \"" + target.mBuildDir + "\""); + LogManager.info("", "\x1b[1mChanging directory:\x1b[0m " + target.mBuildDir); Sys.setCwd(target.mBuildDir); } @@ -568,10 +569,10 @@ class BuildTool } else if (isLinux) { - result = ProcessManager.runProcess("", "nproc", [], true, true, true); + result = ProcessManager.runProcess("", "nproc", []); if (result == null) { - var cpuinfo = ProcessManager.runProcess("", "cat", [ "/proc/cpuinfo" ], true, true, true); + var cpuinfo = ProcessManager.runProcess("", "cat", [ "/proc/cpuinfo" ]); if (cpuinfo != null) { var split = cpuinfo.split("processor"); @@ -582,7 +583,7 @@ class BuildTool else if (isMac) { var cores = ~/Total Number of Cores: (\d+)/; - var output = ProcessManager.runProcess("", "/usr/sbin/system_profiler", [ "-detailLevel", "full", "SPHardwareDataType" ]); + var output = ProcessManager.runProcess("", "/usr/sbin/system_profiler", [ "-detailLevel", "full", "SPHardwareDataType" ], true, false); if (cores.match(output)) { result = cores.matched(1); @@ -905,7 +906,7 @@ class BuildTool if (defines.exists("apple") && !defines.exists("DEVELOPER_DIR")) { - var developer_dir = ProcessManager.runProcess("", "xcode-select", ["--print-path"]); + var developer_dir = ProcessManager.runProcess("", "xcode-select", ["--print-path"], true, false); if (developer_dir == null || developer_dir == "" || developer_dir.indexOf ("Run xcode-select") > -1) developer_dir = "/Applications/Xcode.app/Contents/Developer"; if (developer_dir == "/Developer") diff --git a/tools/run/Compiler.hx b/tools/run/Compiler.hx index e68b85488..b8bd23a18 100644 --- a/tools/run/Compiler.hx +++ b/tools/run/Compiler.hx @@ -151,7 +151,7 @@ class Compiler if (inTid >= 0) { - ProcessManager.runProcess("", exe, args); + ProcessManager.runProcessThreaded("", exe, args); } else { @@ -255,7 +255,7 @@ class Compiler var exe = split.shift (); args = split.concat (args); - var result = ProcessManager.runCommand("", exe, args, true, false, true); + var result = ProcessManager.runCommand("", exe, args); if (result!=0) { if (FileSystem.exists(pch_name)) diff --git a/tools/run/HLSL.hx b/tools/run/HLSL.hx index 223145d5b..1dbffef61 100644 --- a/tools/run/HLSL.hx +++ b/tools/run/HLSL.hx @@ -33,7 +33,7 @@ class HLSL LogManager.info("", exe + " " + args.join(" ")); - var result = ProcessManager.runCommand("", exe, args); + var result = ProcessManager.runCommand("", exe, args, false); if (result!=0) { LogManager.error("Could not compile shader \"" + file + "\""); diff --git a/tools/run/Linker.hx b/tools/run/Linker.hx index d83f860a9..0d9b66bfc 100644 --- a/tools/run/Linker.hx +++ b/tools/run/Linker.hx @@ -157,7 +157,7 @@ class Linker var libObjs = Setup.readStdout(mExe, ["t", lib ]); var objDir = inCompiler.mObjDir + "/" + libName; PathManager.mkdir(objDir); - ProcessManager.runCommand (objDir, mExe, ["x", lib], true, false, true); + ProcessManager.runCommand (objDir, mExe, ["x", lib]); for(obj in libObjs) objs.push( objDir+"/"+obj ); } @@ -186,7 +186,7 @@ class Linker var exe = split.shift (); args = split.concat (args); - var result = ProcessManager.runCommand("", exe, args, true, false, true); + var result = ProcessManager.runCommand("", exe, args); if (result!=0) { Sys.exit(result); @@ -196,7 +196,7 @@ class Linker if (mRanLib!="") { args = [out_name]; - var result = ProcessManager.runCommand("", mRanLib, args, true, false, true); + var result = ProcessManager.runCommand("", mRanLib, args); if (result!=0) { Sys.exit(result); diff --git a/tools/run/LogManager.hx b/tools/run/LogManager.hx index e2e2b86b1..c9b056eab 100644 --- a/tools/run/LogManager.hx +++ b/tools/run/LogManager.hx @@ -87,7 +87,7 @@ class LogManager } } - if (colorSupported) + if (true || colorSupported) { return output; } diff --git a/tools/run/PathManager.hx b/tools/run/PathManager.hx index 150cff4bb..049af9dbd 100644 --- a/tools/run/PathManager.hx +++ b/tools/run/PathManager.hx @@ -106,7 +106,7 @@ class PathManager try { - output = ProcessManager.runProcess(Sys.getEnv ("HAXEPATH"), "haxelib", [ "path", name ], true, true, true); + output = ProcessManager.runProcess(Sys.getEnv ("HAXEPATH"), "haxelib", [ "path", name ]); } catch (e:Dynamic) {} @@ -198,10 +198,10 @@ class PathManager if (!directoryCache.exists (total)) { - directoryCache.set(total, true); + //directoryCache.set(total, true); if (!FileSystem.exists(total)) { - LogManager.info("", " - \x1b[1mCreating directory:\x1b[0m " + total); + LogManager.info("", "\x1b[1mCreating directory:\x1b[0m " + total); FileSystem.createDirectory(total); } } @@ -245,7 +245,7 @@ class PathManager catch (e:Dynamic) {} } - LogManager.info("", " - \x1b[1mRemoving directory:\x1b[0m " + directory); + LogManager.info("", "\x1b[1mRemoving directory:\x1b[0m " + directory); try { @@ -259,7 +259,7 @@ class PathManager { if (FileSystem.exists(file)) { - LogManager.info("", " - \x1b[1mRemoving file:\x1b[0m " + file); + LogManager.info("", "\x1b[1mRemoving file:\x1b[0m " + file); FileSystem.deleteFile(file); } } @@ -280,7 +280,7 @@ class PathManager } public static function standardize(path:String, trailingSlash:Bool = false):String - { + { path = StringTools.replace (path, "\\", "/"); path = StringTools.replace (path, "//", "/"); path = StringTools.replace (path, "//", "/"); diff --git a/tools/run/ProcessManager.hx b/tools/run/ProcessManager.hx index d0162abfd..1013b6c1c 100644 --- a/tools/run/ProcessManager.hx +++ b/tools/run/ProcessManager.hx @@ -3,26 +3,41 @@ import haxe.io.Eof; import haxe.io.Path; import sys.io.Process; import sys.FileSystem; +#if neko +import neko.vm.Thread; +#else +import cpp.vm.Thread; +#end class ProcessManager -{ - public static function runCommand(path:String, command:String, args:Array, safeExecute:Bool = true, ignoreErrors:Bool = false, print:Bool = false):Int +{ + private static function printCommand(command:String, args:Array):Void { - if (print) + var message = "\x1b[34;1m" + command + "\x1b[0m"; + for (arg in args) { - var message = command; - for (arg in args) + if (StringTools.endsWith(arg, ".cpp") || StringTools.endsWith(arg, ".h")) { - if (arg.indexOf(" ") > -1) - { - message += " \"" + arg + "\""; - } - else - { - message += " " + arg; - } + arg = "\x1b[1m" + arg + "\x1b[0m"; + } + + if (arg.indexOf(" ") > -1) + { + message += " \"" + arg + "\""; + } + else + { + message += " " + arg; } - LogManager.info(message); + } + LogManager.info(message); + } + + public static function runCommand(path:String, command:String, args:Array, print:Bool = true, safeExecute:Bool = true, ignoreErrors:Bool = false):Int + { + if (print && !LogManager.verbose) + { + printCommand(command, args); } command = PathManager.escape(command); @@ -54,23 +69,45 @@ class ProcessManager } } - public static function runProcess(path:String, command:String, args:Array, waitForOutput:Bool = true, safeExecute:Bool = true, ignoreErrors:Bool = false, print:Bool = false):String + public static function runProcess(path:String, command:String, args:Array, waitForOutput:Bool = true, print:Bool = true, safeExecute:Bool = true, ignoreErrors:Bool = false):String { - if (print) + if (print && !LogManager.verbose) + { + printCommand(command, args); + } + + command = PathManager.escape(command); + + if (safeExecute) { - var message = command; - for (arg in args) + try { - if (arg.indexOf(" ") > -1) + if (path != null && path != "" && !FileSystem.exists(FileSystem.fullPath(path)) && !FileSystem.exists(FileSystem.fullPath(new Path(path).dir))) { - message += " \"" + arg + "\""; + LogManager.error("The specified target path \"" + path + "\" does not exist"); } - else + return _runProcess(path, command, args, waitForOutput, ignoreErrors); + } + catch (e:Dynamic) + { + if (!ignoreErrors) { - message += " " + arg; + LogManager.error("", e); } + return null; } - LogManager.info(message); + } + else + { + return _runProcess(path, command, args, waitForOutput, ignoreErrors); + } + } + + public static function runProcessThreaded(path:String, command:String, args:Array, print:Bool = true, safeExecute:Bool = true, ignoreErrors:Bool = false):Int + { + if (print && !LogManager.verbose) + { + printCommand(command, args); } command = PathManager.escape(command); @@ -83,7 +120,7 @@ class ProcessManager { LogManager.error("The specified target path \"" + path + "\" does not exist"); } - return _runProcess(path, command, args, waitForOutput, ignoreErrors); + return _runProcessThreaded(path, command, args, ignoreErrors); } catch (e:Dynamic) { @@ -96,7 +133,7 @@ class ProcessManager } else { - return _runProcess(path, command, args, waitForOutput, ignoreErrors); + return _runProcessThreaded(path, command, args, ignoreErrors); } } @@ -106,7 +143,7 @@ class ProcessManager if (path != null && path != "") { - LogManager.info("", " - \x1b[1mChanging directory:\x1b[0m " + path + ""); + LogManager.info("", "\x1b[1mChanging directory:\x1b[0m " + path + ""); oldPath = Sys.getCwd(); Sys.setCwd(path); @@ -126,7 +163,7 @@ class ProcessManager } } - LogManager.info("", " - \x1b[1mRunning command:\x1b[0m " + command + argString); + LogManager.info("", "\x1b[1mRunning command:\x1b[0m " + command + argString); var result = 0; @@ -158,7 +195,7 @@ class ProcessManager if (path != null && path != "") { - LogManager.info("", " - \x1b[1mChanging directory:\x1b[0m " + path + ""); + LogManager.info("", "\x1b[1mChanging directory:\x1b[0m " + path + ""); oldPath = Sys.getCwd(); Sys.setCwd(path); @@ -178,7 +215,7 @@ class ProcessManager } } - LogManager.info("", " - \x1b[1mRunning process:\x1b[0m " + command + argString); + LogManager.info("", "\x1b[1mRunning process:\x1b[0m " + command + argString); var output = ""; var result = 0; @@ -241,4 +278,103 @@ class ProcessManager return output; } + + private static function _runProcessThreaded(path:String, command:String, args:Array, ignoreErrors:Bool):Int + { + var oldPath:String = ""; + + if (path != null && path != "") + { + LogManager.info("", "\x1b[1mChanging directory:\x1b[0m " + path + ""); + + oldPath = Sys.getCwd(); + Sys.setCwd(path); + } + + var argString = ""; + + for (arg in args) + { + if (arg.indexOf(" ") > -1) + { + argString += " \"" + arg + "\""; + } + else + { + argString += " " + arg; + } + } + + LogManager.info("", "\x1b[1mRunning process:\x1b[0m " + command + argString); + + var output = new Array(); + var process = new Process(command, args); + var err = process.stderr; + var out = process.stdout; + var reader = BuildTool.helperThread.value; + + // Read stderr in separate thread to avoid blocking + if (reader==null) + { + var controller = Thread.current(); + BuildTool.helperThread.value = reader = Thread.create(function() + { + while(true) + { + var stream = Thread.readMessage(true); + var output:Array = null; + try + { + while(true) + { + var line = stream.readLine(); + if (output==null) + output = [ line ]; + else + output.push(line); + } + } + catch(e:Dynamic){ } + controller.sendMessage(output); + } + }); + } + + // Start-up the error reader + reader.sendMessage(err); + + try + { + while(true) + { + var line = out.readLine(); + output.push(line); + } + } + catch(e:Dynamic){ } + + var errOut:Array = Thread.readMessage(true); + + var code = process.exitCode(); + process.close(); + + if (code > 0 && !ignoreErrors) + { + LogManager.error(errOut.join ("\n")); + } + + if (errOut!=null && errOut.length>0) + output = output.concat(errOut); + + if (output.length>0) + { + if (BuildTool.printMutex!=null) + BuildTool.printMutex.acquire(); + LogManager.info(output.join("\n")); + if (BuildTool.printMutex!=null) + BuildTool.printMutex.release(); + } + + return code; + } } \ No newline at end of file diff --git a/tools/run/Stripper.hx b/tools/run/Stripper.hx index 7ec1248f7..28fdb7f71 100644 --- a/tools/run/Stripper.hx +++ b/tools/run/Stripper.hx @@ -19,7 +19,7 @@ class Stripper var exe = split.shift(); args = split.concat(args); - var result = ProcessManager.runCommand("", exe, args, true, false, true); + var result = ProcessManager.runCommand("", exe, args); if (result!=0) { Sys.exit(result); From 08ff7788e9c905b8d2aa35f3ccaf5ed7abf2428b Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 25 Mar 2014 00:08:37 -0700 Subject: [PATCH 5/6] Remove debug value --- tools/run/LogManager.hx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/run/LogManager.hx b/tools/run/LogManager.hx index c9b056eab..e2e2b86b1 100644 --- a/tools/run/LogManager.hx +++ b/tools/run/LogManager.hx @@ -87,7 +87,7 @@ class LogManager } } - if (true || colorSupported) + if (colorSupported) { return output; } From 4a405a42445622e7295d3e0ba84592d2078ba75d Mon Sep 17 00:00:00 2001 From: Joshua Granick Date: Tue, 25 Mar 2014 00:08:56 -0700 Subject: [PATCH 6/6] Update run script --- run.n | Bin 120323 -> 121506 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/run.n b/run.n index cea3b1916b539541259516ceea56f96e1ce36e12..3ca75bf9bef47180405efc439a3f6ce6748313ba 100644 GIT binary patch delta 40661 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

a)Uh$=M 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 gRg;kMzLc?*@dvWgcEq2HjwuEmAj3%CP4 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 KW$zJ9cJdaYl{As@Y!yYyz z?hzundh16CyL#&dB)lhkjI>O_aUf)w5=LuFW$#Wf|paI%NkF~zwBdn z_OvQ#;tP-@DL88I=1bHGKBJMef(mSrPrbk%3SLR{2}i1F$|TGA`#)2hKgYX8q@nx-c!qrts17<*dW!W2H_3zD@QR796JmFZc%~%Rm$f7BE|2eq61%I1t%BRVu;dc z>i2Hf*e@vJ@&Oi)mx{bm!8kC+cOCTH)INy&q$=jAgHY9e5CyJ1z*>ZF`-c`c58(Ct z?eaUS95;JJ(#Qs!xNW1e?I;<%*=(mg`2aN7tynhG^(F{);#i0^NU^6ucsEH%kOv-O zxe$|h&?81ZeTeyo@BIfmR85ZKETz>i;VTpS{t=z{BFhSYp#gcny!a4{mn&bwsGo6! z1<31PWX7b1T=bWbw2pH?O?CPxE=!=E!7*6&~Yw?75(ONwgkmDA6xSdHMTfc#HeU9}al3 zge~IzuD9;{K9L(AcBdn93{BfW)|bbGt27^!W?ssvWQk@J%b=L2*)=FH=!nz z9o|5$5ap?y_?TTMLvsF+v+$CK!vbfo*D33_b6WBpDnq`f>`Kv;*WE#0uO-LIZ@tU{ zI9w&^@{*>+3b{l0YYp^0;mOwIvlQFd^3-E2(O+2uiNfm?YTPJ$_$x+*BA388K5Inb z4T?zeS%m#&6>Y~NQ$-U*;Vl(qVqK{s3+|_==p5}=Q(Aa;!QP)*V2Rm4q1`e$zt3Y> za1tYQp^ZN*IhBz5Sq{1K7)$Y)CJG<8Sm@pmy+WrZpv_%eM4?cU4?el@kwWK$cjeB< zSyP{#SZ=x~o8+a(S(>jI7hx}|>_G~1z5hb*_#eKT_Y!T zWX(;=Jt<}MaNjJ#qLY`yKR_q5=LGYMR_sBei#Pr&HNI@S?YHh&2dfslN|_7ve8xt1 zvRveA8ggZ?gxe}P37NpM7NR_1%ej>hsnXSP%$w8K^3;!5qCDXw9i*LLp|bP;v~@Kx zO$1>yQ=mYUM1&U7YKt+b7den9i4m8?i;!OYj|VBnL~q86@c^Om074KB8W}E%A!3x9 z(Tl;75P??27E6mQB;XP8px_CJ;(If6=~8cR-#0TmyE`-8@B3b76JoD?#>23An82Y} zmVr2~b=L&&4_&JcST>AiZy5o3rKOctH^J)l&t}x`_4~f=@LPR$|ij#$FxEJ&h*7?jTikAj!D2Q{X z=?#&OaCFg&%v348l9On{+cz~GwDr5OaG+E4Y2_yp+uw4JZlBHVuF12ICD><{9NnZ4B!7^7dRFclK((|6uWzu$& zmXAM))#58k4qy%|hyp}hcnT>BfH2+FD7&Vxvsp_@>~%87uegi>@4BYSJFB1&$g(vl zTi`=q|2qC!lB@FU0GUEi^}Pyk1qSyXP=J|s1@yNXVB-D+is1&90O>!7&b#Z<(k3HW zeKrb{JKwxML{F#!_f>6A&uyu_%IoX3$2x&K}8ZxmLHq})bm=<}E zLs~C+LL2Q2aJugIa(UZ~iV`~`rBEUcPlMo@>{LmDX#4`AXB;Df(N<_0t<4R~Juy*H zMp0&#ZA71{jB(s7<9ls%G8~*`46@bA;+-d(R3~#Xz>3jr?Z~RWCr@H{5nR`J0a!N2 zaO>EA>6sB;#uu=pm&?mDcC3}xgkPIZ6T<;# zu~uSu!Nl)o(HXdy#B0QNb;nM8MaNom)U$5}mdRO+nPDJ0dn~=N1KZkl>6RqQwCPrY zNu);}Xg((erx8va>z)CYhg0Y%r-tmoq3w|_7EhsipRVqh1BSoFDi?|2Z*ASi-38bv Jj_R7%{{S{BK%f8s