import CopyFile.Overwrite; import haxe.io.Path; import haxe.Json; import sys.io.Process; import sys.FileSystem; #if haxe4 import sys.thread.Thread; import sys.thread.Mutex; import sys.thread.Tls; #elseif neko import neko.vm.Thread; import neko.vm.Mutex; import neko.vm.Tls; #else import cpp.vm.Thread; import cpp.vm.Mutex; import cpp.vm.Tls; #end import haxe.crypto.Md5; import Log.NORMAL; import Log.BOLD; import Log.ITALIC; import Log.YELLOW; import Log.WHITE; using StringTools; #if (haxe_ver>=4) typedef XmlAccess = haxe.xml.Access; #else typedef XmlAccess = haxe.xml.Fast; #end #if haxe3 typedef Hash = haxe.ds.StringMap; #end typedef FileGroups = Hash; typedef Targets = Hash; typedef Prelinkers = Hash; typedef Linkers = Hash; class BuildTool { public inline static var SupportedVersion = 430; var mDefines:Hash; var mCurrentIncludeFile:String; var mIncludePath:Array; var mCompiler:Compiler; var mStripper:Stripper; var mManifester:Manifester; var mPrelinkers:Prelinkers; var mLinkers:Linkers; var mCopyFiles:Array; var mFileGroups:FileGroups; var mTargets:Targets; var mFileStack:Array; var mMakefile:String; var mMagicLibs:Array<{name:String, replace:String}>; var mPragmaOnce:Map; var mNvccFlags:Array; var mNvccLinkFlags:Array; var mDirtyList:Array; var arm64:Bool; var m64:Bool; var m32:Bool; public static var os=""; public static var sAllowNumProcs = true; public static var sCompileThreadCount = 1; public static var sThreadPool:ThreadPool; public static var sReportedThreads = -1; public static var HXCPP = ""; public static var is64 = false; public static var isWindows = false; public static var isWindowsArm = false; public static var isLinux = false; public static var isRPi = false; public static var isMac = false; public static var targetKey:String; public static var instance:BuildTool; public static var helperThread = new Tls(); public static var destination:String; public static var outputs = new Array(); public static var groupMutex = new Mutex(); static var mVarMatch = new EReg("\\${(.*?)}",""); static var mNoDollarMatch = new EReg("{(.*?)}",""); public static var exitOnThreadError = false; public static var threadExitCode = 0; public static var startDir:String; public function new(inJob:String,inDefines:Hash,inTargets:Array, inIncludePath:Array, inDirtyList:Array ) { mDefines = inDefines; mFileGroups = new FileGroups(); mCompiler = null; mStripper = null; mTargets = new Targets(); mPrelinkers = new Prelinkers(); mLinkers = new Linkers(); mCurrentIncludeFile = ""; mFileStack = []; mCopyFiles = []; mIncludePath = inIncludePath; mPragmaOnce = new Map(); mMagicLibs = []; mNvccFlags = []; mNvccLinkFlags = []; mMakefile = ""; mDirtyList = inDirtyList; if (inJob=="cache") { } else { mMakefile = inJob; if (!PathManager.isAbsolute(mMakefile) && sys.FileSystem.exists(mMakefile)) mMakefile = sys.FileSystem.fullPath(mMakefile); mDefines.set("HXCPP_BUILD_DIR", Path.addTrailingSlash(Path.directory(mMakefile)) ); } instance = this; m64 = mDefines.exists("HXCPP_M64"); m32 = mDefines.exists("HXCPP_M32"); arm64 = mDefines.exists("HXCPP_ARM64"); if (m64==m32 && !arm64) { var arch = getArch(); // Default to the current OS version. windowsArm runs m32 code too m64 = arch=="m64"; m32 = arch=="m32"; arm64 = arch=="arm64"; mDefines.remove(m32 ? "HXCPP_M64" : "HXCPP_M32"); set64(mDefines,m64,arm64); } Profile.setEntry("parse xml"); include("toolchain/setup.xml"); if (mDefines.exists("toolchain")) { if (!mDefines.exists("BINDIR")) { mDefines.set("BINDIR", Path.withoutDirectory(Path.withoutExtension(mDefines.get("toolchain")))); } if ( (new EReg("window","i")).match(os) ) mDefines.set("windows_host","1"); } else setDefaultToolchain(mDefines); if (mDefines.exists("dll_import")) { var path = new Path(mDefines.get("dll_import")); if (!mDefines.exists("dll_import_include")) mDefines.set("dll_import_include", path.dir + "/include" ); if (!mDefines.exists("dll_import_link")) mDefines.set("dll_import_link", mDefines.get("dll_import") ); } setupAppleDirectories(mDefines); if (isMsvc()) { mDefines.set("isMsvc","1"); if (Std.parseInt(mDefines.get("MSVC_VER"))>=18) mDefines.set("MSVC18+","1"); } include("toolchain/finish-setup.xml", false); if (mMakefile!="") { pushFile(mMakefile,"makefile"); var make_contents = ""; try { make_contents = sys.io.File.getContent(mMakefile); } catch (e:Dynamic) { Log.error("Could not open build file \"" + mMakefile + "\""); //println("Could not open build file '" + mMakefile + "'"); //Sys.exit(1); } var xml_slow = Xml.parse(make_contents); var xml = new XmlAccess(xml_slow.firstElement()); parseXML(xml,"",false); popFile(); include("toolchain/" + mDefines.get("toolchain") + "-toolchain.xml", false); if (mDefines.exists("HXCPP_CONFIG")) include(mDefines.get("HXCPP_CONFIG"),"exes",true); } for(group in mFileGroups) group.filter(mDefines); if (Log.verbose) Log.println (""); // MSVC needs this before the toolchain file, Emscripten wants to set HXCPP_COMPILE_THREADS // If not already calculated in "setup" getThreadCount(); var cached = CompileCache.init(mDefines); Profile.setEntry("setup cache"); if (inJob=="cache") { if (!cached) { Log.error("HXCPP_COMPILE_CACHE is not set"); } switch(inTargets[0]) { case "days" : var days = inTargets[1]==null ? null : Std.parseInt(inTargets[1]); if (days==null) { Log.error("cache days - expected day count"); Tools.exit(1); } CompileCache.clear(days,0,true,null); case "resize" : var mb = inTargets[1]==null ? null : Std.parseInt(inTargets[1]); if (mb==null) { Log.error("cache resize - expected megabyte count"); Tools.exit(1); } CompileCache.clear(0,mb,true,inTargets[2]); case "clear" : CompileCache.clear(0,0,true,inTargets[1]); case "list" : CompileCache.list(false,inTargets[1]); case "details" : CompileCache.list(true,inTargets[1]); default: printUsage(); Tools.exit(1); } return; } if (cached) { var cacheSize = mDefines.exists("HXCPP_CACHE_MB") ? Std.parseInt( mDefines.get("HXCPP_CACHE_MB") ) : 1000; if (cacheSize!=null && cacheSize>0) CompileCache.clear(0,cacheSize,false,null); } if (Log.verbose) Log.println (""); if (inTargets.remove("clear")) { Profile.setEntry("clear"); for(target in mTargets.keys()) cleanTarget(target,false); } if (inTargets.remove("clean")) { Profile.setEntry("clean"); for(target in mTargets.keys()) cleanTarget(target,true); } if (destination!=null && inTargets.length!=1) { Log.warn("Exactly one target must be specified with 'destination'. Specified:" + inTargets ); destination = null; } Profile.setEntry("build"); for(target in inTargets) buildTarget(target,destination); var linkOutputs = mDefines.get("HXCPP_LINK_OUTPUTS"); if (linkOutputs!=null) sys.io.File.saveContent(linkOutputs,outputs.join("\n")+"\n"); if (Log.verbose) { for(out in outputs) Log.v(" generated " + out); } if (threadExitCode != 0) Tools.exit(threadExitCode); } public static function isDefault64() { } public function pushFile(inFilename:String, inWhy:String, inSection:String="") { Log.info("", " - \x1b[1mParsing " + inWhy + ":\x1b[0m " + inFilename + (inSection == "" ? "" : " \x1b[3m(section \"" + inSection + "\")\x1b[0m")); mFileStack.push(inFilename); } public function popFile() { mFileStack.pop(); } public static function addOutput(inWhat:String, inWhere:String) { outputs.push(inWhat + "=" + inWhere); } public static function getThreadCount() : Int { if (instance==null) return sCompileThreadCount; var defs = instance.mDefines; if (sAllowNumProcs) { var thread_var = defs.exists("HXCPP_COMPILE_THREADS") ? defs.get("HXCPP_COMPILE_THREADS") : Sys.getEnv("HXCPP_COMPILE_THREADS"); if (thread_var == null) { sCompileThreadCount = getNumberOfProcesses(); } else { sCompileThreadCount = (Std.parseInt(thread_var)<2) ? 1 : Std.parseInt(thread_var); } if (sCompileThreadCount!=sReportedThreads) { sReportedThreads = sCompileThreadCount; Log.v("\x1b[33;1mUsing compile threads: " + sCompileThreadCount + "\x1b[0m"); } } if (sCompileThreadCount>1 && sThreadPool==null) sThreadPool = new ThreadPool(sCompileThreadCount); return sCompileThreadCount; } public static function setThreadError(inCode:Int) { threadExitCode = inCode; if (exitOnThreadError) Tools.exit(inCode); } public function buildTarget(inTarget:String, inDestination:String) { //var dependDebug = function(s:String) Log.error(s); var dependDebug = null; // Sys.println("Build : " + inTarget ); if (!mTargets.exists(inTarget)) { Log.error ("Could not find build target \"" + inTarget + "\""); //throw "Could not find target '" + inTarget + "' to build."; } if (mCompiler==null) { Log.error("No compiler defined for the current build target"); //throw "No compiler defined"; } var target:Target = mTargets.get(inTarget); target.checkError(); for(sub in target.mSubTargets) buildTarget(sub,null); var threadPool = BuildTool.sThreadPool; PathManager.resetDirectoryCache(); var restoreDir = ""; if (target.mBuildDir!="") { restoreDir = Sys.getCwd(); Log.info("", " - \x1b[1mChanging directory:\x1b[0m " + target.mBuildDir); Sys.setCwd(target.mBuildDir); } targetKey = inTarget + target.getKey(); var objs = new Array(); mCompiler.objToAbsolute(); if (target.mFileGroups.length > 0) PathManager.mkdir(mCompiler.mObjDir); var baseDir = Sys.getCwd(); for(group in target.mFileGroups) { var useCache = CompileCache.hasCache && group.mUseCache; if (!useCache && group.mUseCache) Log.v("Ignoring compiler cache because HXCPP_COMPILE_CACHE is not valid."); var groupObjs = new Array(); if (group.mDir!="." && group.mSetImportDir) Sys.setCwd( PathManager.combine(baseDir, group.mDir ) ); group.checkOptions(mCompiler.mObjDir); group.checkDependsExist(); if (!mCompiler.initPrecompile(mDefines.get("USE_PRECOMPILED_HEADERS") )) group.dontPrecompile(); group.preBuild(); var to_be_compiled = new Array(); var cached = useCache && mCompiler.createCompilerVersion(group); var inList = new Array(); var groupIsOutOfDate = mDirtyList.indexOf(group.mId)>=0 || mDirtyList.indexOf("all")>=0; if (useCache) { Profile.push("compute hash"); if (useCache && group.hasFiles() && threadPool!=null) { Log.initMultiThreaded(); var names:Array = Lambda.array(Lambda.map(group.mFiles, function(file:File) {return file.mName; })); threadPool.setArrayCount( names.length ); threadPool.runJob( function(tid) { var localCache = new Map(); while(threadExitCode==0) { var id = sThreadPool.getNextIndex(); if (id<0) break; group.mFiles.get(names[id]).computeDependHash(localCache); } } ); } else { for(file in group.mFiles) file.computeDependHash(null); } Profile.pop(); } for(file in group.mFiles) { var obj_name = mCompiler.getCachedObjName(file); groupObjs.push(obj_name); var outOfDate = groupIsOutOfDate || file.isOutOfDate(obj_name, dependDebug); if (outOfDate) { if (dependDebug!=null) dependDebug(mCompiler.getCacheString(file)); to_be_compiled.push(file); } inList.push(outOfDate); } var someCompiled = to_be_compiled.length > 0; var pchStamp:Null = null; if (group.mPrecompiledHeader!="") { Profile.push("pch"); var obj = mCompiler.precompile(group,cached || to_be_compiled.length==0); if (obj!=null) { pchStamp = FileSystem.stat(obj).mtime.getTime(); groupObjs.push(obj); /* for(i in 0...group.mFiles.length) { var obj_name = groupObjs[i]; if (!inList[i]) { if (FileSystem.stat(obj_name).mtime.getTime() < pchStamp) { groupObjs.push(obj_name); trace(' Add $obj_name'); } else trace(' Ok $obj_name'); } else { trace(' Listed $obj_name ' + group.mFiles[i].mName); } } */ } Profile.pop(); } if (group.mConfig!="") { var lines = ["#ifndef HXCPP_CONFIG_INCLUDED","#define HXCPP_CONFIG_INCLUDED"]; var flags = group.mCompilerFlags.concat(mCompiler.getCompilerDefines("haxe")); var define = ~/^-D([^=]*)=?(.*)/; for(flag in flags) { if (define.match(flag)) { var name = define.matched(1); var val = define.matched(2); lines.push(""); lines.push( '#if !defined($name) && !defined(NO_$name)' ); lines.push( '#define $name $val' ); lines.push( '#endif' ); } } lines.push(""); lines.push("#include "); lines.push(""); lines.push("#endif"); lines.push(""); var filename = mDefines.exists("HXCPP_OUTPUT_CONFIG_NAME") ? mDefines.get("HXCPP_OUTPUT_CONFIG_NAME") : PathManager.combine( target.mOutputDir, group.mConfig ); if (!PathManager.isAbsolute(filename)) filename = PathManager.combine( Sys.getCwd(), filename); var content = lines.join("\n"); if (!FileSystem.exists(filename) || sys.io.File.getContent(filename)!=content) sys.io.File.saveContent(filename, content); addOutput("config",filename); } var nvcc = group.mNvcc; var first = true; var groupHeader = (!Log.quiet && !Log.verbose) ? function() { if (first) { groupMutex.acquire(); if (first) { first = false; Log.lock(); Log.println(""); Log.info("\x1b[33;1mCompiling group: " + group.mId + "\x1b[0m"); var message = "\x1b[1m" + (nvcc ? getNvcc() : mCompiler.mExe) + "\x1b[0m"; var flags = group.mCompilerFlags; if (!nvcc) flags = flags.concat(mCompiler.getFlagStrings()); else flags = flags.concat( BuildTool.getNvccFlags() ); for (compilerFlag in flags) { if (StringTools.startsWith(compilerFlag, "-D")) { var index = compilerFlag.indexOf("("); if (index > -1) { message += " \x1b[1m" + compilerFlag.substr(0, index) + "\x1b[0m\x1b[2m" + compilerFlag.substr(index) + "\x1b[0m"; } else { message += " \x1b[1m" + compilerFlag + "\x1b[0m"; } } else { message += " \x1b[0m" + compilerFlag + "\x1b[0m"; } } message += " \x1b[2m...\x1b[0m \x1b[2mtags=" + group.mTags.split(",") + "\x1b[0m"; Log.info(message); Log.unlock(); } groupMutex.release(); } } : null; Profile.push("compile"); if (threadPool==null) { for(file in to_be_compiled) mCompiler.compile(file,-1,groupHeader,pchStamp); } else { Log.initMultiThreaded(); var mutex = threadPool.mutex; var compiler = mCompiler; threadPool.setArrayCount(to_be_compiled.length); threadPool.runJob( function(threadId:Int) { while(threadExitCode==0) { var index = threadPool.getNextIndex(); if (index<0) break; var file = to_be_compiled[index]; compiler.compile(file,threadId,groupHeader,pchStamp); } }); } Profile.pop(); if (CompileCache.hasCache && group.mAsLibrary && mLinkers.exists("static_link")) { Profile.push("link libs"); var linker = mLinkers.get("static_link"); var targetDir = mCompiler.mObjDir; if (useCache) { targetDir = CompileCache.compileCache + "/" + group.getCacheProject() + "/lib"; PathManager.mkdir(targetDir); } var libName = targetDir + "/" + mCompiler.getTargetPrefix() + "_" + group.getCacheProject(); var libTarget = new Target(libName, "linker", "static_link" ); linker.link(libTarget,groupObjs, mCompiler, [] ); target.mAutoLibs.push(linker.mLastOutName); // Linux the libraries must be added again if the references were not resolved the firs time if (group.mAddTwice) target.mLibs.push(linker.mLastOutName); Profile.pop(); } else if (nvcc) { var objDir = mCompiler.mObjDir; if (group.isCached()) objDir = CompileCache.compileCache; var extraObj = linkNvccFiles(objDir, someCompiled, groupObjs, group.mId, mCompiler.mExt); groupObjs.push(extraObj); objs = objs.concat(groupObjs); } else { objs = objs.concat(groupObjs); } if (group.mDir!="." && group.mSetImportDir) Sys.setCwd( baseDir ); } switch(target.mTool) { case "linker": Profile.push("linker"); if (mPrelinkers.exists(target.mToolID)) { var result = mPrelinkers.get(target.mToolID).prelink(target,objs, mCompiler); if (result != "") objs.push(result); //throw "Missing linker :\"" + target.mToolID + "\""; } if (!mLinkers.exists(target.mToolID)) { Log.error ("Could not find linker for \"" + target.mToolID + "\""); //throw "Missing linker :\"" + target.mToolID + "\""; } var extraDeps = []; var manifest = mDefines.get("manifestFile"); if (manifest!=null) extraDeps.push(manifest); var linker = mLinkers.get(target.mToolID); var output = linker.link(target,objs, mCompiler, extraDeps); if (output!="") { if (mStripper!=null) { if (target.mToolID=="exe" || target.mToolID=="dll") { if ( mDefines.exists("HXCPP_DEBUG_LINK_AND_STRIP") ) { var unstripped = linker.getUnstrippedFilename(mCompiler.mObjDir,target); //var unstripped = mCompiler.mObjDir + "/" + linker.getSimpleFilename(target); Log.v("Save unstripped to " + unstripped); var chmod = isWindows ? false : target.mToolID=="exe"; CopyFile.copyFile(output, unstripped, false, Overwrite.ALWAYS, chmod); } mStripper.strip(output); } } if (manifest!=null && (target.mToolID=="exe" || target.mToolID=="dll") ) { if (mManifester==null) { Log.v('Could not find manifest tool for "$manifest" - ignoring'); } else { //if (!PathManager.isAbsolute(manifest)) //manifest = PathManager.combine(startDir,manifest); Log.v('Adding manifest "$manifest"'); mManifester.add(output, manifest,target.mToolID=="exe"); } } } var outFile = linker.mLastOutName; if (outFile!="" && !PathManager.isAbsolute(outFile) && sys.FileSystem.exists(mMakefile)) { var baseFile = PathManager.standardize(mMakefile); var parts = baseFile.split("/"); parts[ parts.length-1 ] = outFile; outFile = parts.join("/"); } if (outFile!="") addOutput(target.mToolID, outFile); if (output!="" && inDestination!=null) { inDestination = substitute(inDestination,false); if (inDestination!="") { if (!PathManager.isAbsolute(inDestination) && sys.FileSystem.exists(mMakefile)) { var baseFile = PathManager.standardize(mMakefile); var parts = baseFile.split("/"); parts[ parts.length-1 ] = inDestination; inDestination = parts.join("/"); } inDestination = PathManager.clean(inDestination); var fileParts = inDestination.split("/"); fileParts.pop(); PathManager.mkdir(fileParts.join("/")); var chmod = isWindows ? false : target.mToolID=="exe"; CopyFile.copyFile(output, inDestination, false, Overwrite.ALWAYS, chmod); } } Profile.pop(); } if (mCopyFiles.length>0) { Profile.push("copy files"); for(copyFile in mCopyFiles) if (copyFile.toolId==null || copyFile.toolId==target.mToolID) copyFile.copy(target.mOutputDir); Profile.pop(); } if (restoreDir!="") Sys.setCwd(restoreDir); } function linkNvccFiles(objDir:String, hasChanged:Bool, nvObjs:Array, inGroupName:String, objExt:String) { // nvcc -arch=sm_30 -dlink test1.o test2.o -o link.o // Sadly, nvcc has no 'fromFile' options, so we must do it from objDir var objDirLen = objDir.length; var last = objDir.substr(objDirLen-1); if (last!="/" && last!="\\") objDirLen++; var outFile = "nvcc_" + inGroupName + mCompiler.mExt; var fullFile = objDir + "/" + outFile; if (hasChanged || !sys.FileSystem.exists(fullFile) ) { var maxObjs = 25; var shortObjs = nvObjs.map( function(f) return f.substr(objDirLen) ); if (shortObjs.length>maxObjs) { var partObjs = new Array(); var p0 = 0; var n =shortObjs.length; var groupIdx = 0; while(p0>1) : maxObjs; var files = shortObjs.slice(p0,p0+use); var flags = getNvccLinkFlags().concat(files).concat(["-o",subName]); var dbgFlags = getNvccLinkFlags().concat(["[.", "x"+subName.length,".]"]).concat(["-o",subName]); Log.v("Linking nvcc in " + objDir + ":" + getNvcc() + dbgFlags.join(" ") ); ProcessManager.runCommand(objDir ,getNvcc(), flags ); partObjs.push(subName); p0 += use; } shortObjs = partObjs; } var flags = getNvccLinkFlags().concat(shortObjs).concat(["-o",outFile]); var dbgFlags = getNvccLinkFlags().concat(["[.", "x"+shortObjs.length,".]"]).concat(["-o",outFile]); Log.v("Linking nvcc in " + objDir + ":" + getNvcc() + dbgFlags.join(" ") ); ProcessManager.runCommand(objDir ,getNvcc(), flags ); } return fullFile; } public function cleanTarget(inTarget:String,allObj:Bool) { // Sys.println("Build : " + inTarget ); if (!mTargets.exists(inTarget)) { Log.error("Could not find build target \"" + inTarget + "\""); //throw "Could not find target '" + inTarget + "' to build."; } if (mCompiler==null) { Log.error("No compiler defined"); //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(); Log.info("", " - \x1b[1mChanging directory:\x1b[0m " + target.mBuildDir); Sys.setCwd(target.mBuildDir); } PathManager.removeDirectory(mCompiler.mObjDir); PathManager.removeFile("all_objs"); PathManager.removeFilesWithExtension(".pdb"); if (allObj) PathManager.removeDirectory("obj"); if (restoreDir!="") Sys.setCwd(restoreDir); } public function createCompiler(inXML:XmlAccess,inBase:Compiler) : Compiler { var c = inBase; var id = inXML.has.id ? substitute(inXML.att.id) : null; var exe = inXML.has.exe ? substitute(inXML.att.exe) : null; if (inBase==null || inXML.has.replace) { c = new Compiler(id,exe); } else { if (id!=null) c.mID = id; if (exe!=null) c.mExe = exe; } c.mAddGCCIdentity = mDefines.exists("USE_GCC_FILETYPES"); for(el in inXML.elements) { if (valid(el,"")) switch(el.name) { case "flag" : c.addFlag(substitute(el.att.value), el.has.tag?substitute(el.att.tag):""); 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 "rcflag" : c.mRcFlags.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 "rcexe" : c.mRcExe = substitute((el.att.name)); case "rcext" : c.mRcExt = substitute((el.att.value)); 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!="") { pushFile(full_name,"compiler"); var make_contents = sys.io.File.getContent(full_name); var xml_slow = Xml.parse(make_contents); createCompiler(new XmlAccess(xml_slow.firstElement()),c); popFile(); } else if (!el.has.noerror) { Log.error("Could not find include file \"" + name + "\""); //throw "Could not find include file " + name; } default: Log.error("Unknown compiler option \"" + el.name + "\""); //throw "Unknown compiler option: '" + el.name + "'"; } } return c; } public function loadNvccXml() { var incName = findIncludeFile("nvcc-setup.xml"); if (incName=="") incName = findIncludeFile('$HXCPP/toolchain/nvcc-setup.xml'); if (incName=="") Log.error("Could not setup nvcc - missing nvcc-setup.xml"); else if (!mPragmaOnce.get(incName)) { pushFile(incName, "Nvcc"); var make_contents = sys.io.File.getContent(incName); mPragmaOnce.set(incName,true); var xml = Xml.parse(make_contents); parseXML(new XmlAccess(xml.firstElement()),"", false); popFile(); } } public static function setupNvcc() { instance.loadNvccXml(); } public function createFileGroup(inXML:XmlAccess,inFiles:FileGroup,inName:String, inForceRelative:Bool, inTags:String):FileGroup { var dir = inXML.has.dir ? substitute(inXML.att.dir) : "."; if (inForceRelative) dir = PathManager.combine( Path.directory(mCurrentIncludeFile), dir ); var group:FileGroup = inFiles==null ? new FileGroup(dir,inName, inForceRelative) : inXML.has.replace ? inFiles.replace(dir, inForceRelative) : inFiles; if (inTags!=null) group.mTags = inTags; for(el in inXML.elements) { if (valid(el,"")) switch(el.name) { case "file" : var name = substitute(el.att.name); var file:File = group.find(name); if (file==null) { file = new File(name,group); group.addFile( file ); } if (el.has.tag) { var extra = substitute(el.att.tag); file.setTags(group.mTags==null || group.mTags=="" ? extra : group.mTags+","+extra); } if (el.has.tags) file.setTags( substitute(el.att.tags) ); if (el.has.filterout) file.mFilterOut = substitute(el.att.filterout); if (el.has.embedName) file.mEmbedName = substitute(el.att.embedName); if (el.has.scramble) file.mScramble = substitute(el.att.scramble); for(f in el.elements) if (valid(f,"") && f.name=="depend") file.mDepends.push( substitute(f.att.name) ); case "section" : createFileGroup(el,group,inName,inForceRelative,null); case "cache" : group.mUseCache = parseBool( substitute(el.att.value) ); if (el.has.project) group.mCacheProject = substitute(el.att.project); if (el.has.asLibrary) group.mAsLibrary = true; if (el.has.respectTimestamp) group.mRespectTimestamp = true; case "tag" : group.addTag( substitute(el.att.value) ); case "addTwice" : group.mAddTwice = true; case "depend" : if (el.has.name) { var dateOnly = el.has.dateOnly && parseBool( substitute(el.att.dateOnly) ); group.addDepend( substitute(el.att.name), dateOnly ); } else if (el.has.files) { var name = substitute(el.att.files); if (!mFileGroups.exists(name)) Log.error( "Could not find filegroup for depend node:" + name ); group.addDependFiles(mFileGroups.get(name)); } else Log.error("depend node must have 'name' or 'files' attribute"); 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 "config" : group.mConfig = substitute(el.att.name); case "compilerflag" : if (el.has.name) group.addCompilerFlag( substitute(el.att.name) ); group.addCompilerFlag( substitute(el.att.value) ); case "nvcc" : setupNvcc(); group.mNvcc = true; if (group.mTags=="haxe,static") group.mTags=="nvcc"; case "objprefix" : group.mObjPrefix = 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 "include" : var subbed_name = substitute(el.att.name); var full_name = findIncludeFile(subbed_name); if (full_name!="") { if (!mPragmaOnce.get(full_name)) { pushFile(full_name, "FileGroup"); var make_contents = sys.io.File.getContent(full_name); var xml_slow = Xml.parse(make_contents); createFileGroup(new XmlAccess(xml_slow.firstElement()), group, inName, false,null); popFile(); } } else { Log.error("Could not find include file \"" + subbed_name + "\""); } } } return group; } public function createLinker(inXML:XmlAccess,inBase:Linker):Linker { var exe:String = inXML.has.exe ? substitute(inXML.att.exe) : null; if (inBase!=null && !inXML.has.replace && inBase.mExe==null) inBase.mExe = exe; var l = (inBase!=null && !inXML.has.replace) ? inBase : new Linker(exe); for(el in inXML.elements) { 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" : if (el.has.hxbase) l.mLibs.push( substitute(el.att.hxbase) + mDefines.get("LIBEXTRA") + mDefines.get("LIBEXT") ); else if (el.has.base) l.mLibs.push( substitute(el.att.base) + mDefines.get("LIBEXT") ); else l.mLibs.push( substitute(el.att.name) ); case "prefix" : l.mNamePrefix = substitute(el.att.value); case "ranlib" : l.mRanLib = (substitute(el.att.name)); case "libpathflag" : l.mAddLibPath = (substitute(el.att.value)); case "recreate" : l.mRecreate = (substitute(el.att.value)) != ""; case "expandAr" : l.mExpandArchives = substitute(el.att.value) != ""; case "fromfile" : if (el.has.value) l.mFromFile = substitute(el.att.value); if (el.has.needsQuotes) l.mFromFileNeedsQuotes = parseBool(substitute(el.att.needsQuotes)); case "exe" : l.mExe = (substitute(el.att.name)); case "section" : createLinker(el,l); } } return l; } public function createPrelinker(inXML:XmlAccess,inBase:Prelinker):Prelinker { var l = (inBase!=null && !inXML.has.replace) ? inBase : new Prelinker(substitute(inXML.att.exe)); for(el in inXML.elements) { 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 "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" : createPrelinker(el,l); } } return l; } public function createManifester(inXML:XmlAccess,inBase:Manifester):Manifester { var s = (inBase!=null && !inXML.has.replace) ? inBase : new Manifester(substitute(inXML.att.exe)); for(el in inXML.elements) { if (valid(el,"")) switch(el.name) { case "flag" : s.mFlags.push(substitute(el.att.value)); case "outPre" : s.mOutPre = substitute(el.att.value); case "outPost" : s.mOutPost = substitute(el.att.value); case "exe" : s.mExe = substitute((el.att.name)); } } return s; } public function createStripper(inXML:XmlAccess,inBase:Stripper):Stripper { var s = (inBase!=null && !inXML.has.replace) ? inBase : new Stripper(substitute(inXML.att.exe)); 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)); } } return s; } public function createTarget(inXML:XmlAccess,?inTarget:Target, inForceRelative) : Target { var target:Target = inTarget; var output = inXML.has.output ? substitute(inXML.att.output) : ""; var tool = inXML.has.tool ? substitute(inXML.att.tool) : ""; var toolid = inXML.has.toolid ? substitute(inXML.att.toolid) : ""; if (target==null) { target = new Target(output,tool,toolid); if (inForceRelative) target.mBuildDir = Path.directory(mCurrentIncludeFile); } else { if (output!="") target.mOutput = output; if (tool!="") target.mTool = tool; if (toolid!="") target.mToolID = toolid; } for(el in inXML.elements) { if (valid(el,"")) switch(el.name) { case "target" : target.mSubTargets.push( substitute(el.att.id) ); case "merge" : var name = substitute(el.att.id); if (!mTargets.exists(name)) Log.error("Could not find target " + name + " to merge."); target.merge( mTargets.get(name) ); case "lib" : if (el.has.hxbase) target.mLibs.push( substitute(el.att.hxbase) + mDefines.get("LIBEXTRA") + mDefines.get("LIBEXT") ); else if (el.has.base) target.mLibs.push( substitute(el.att.base) + mDefines.get("LIBEXT") ); else { var lib = substitute(el.att.name); var found = false; for(magicLib in mMagicLibs) { if (lib.endsWith(magicLib.name)) { var replace = lib.substr(0, lib.length-magicLib.name.length) + magicLib.replace; Log.v('Using $replace instead of $lib'); found = true; include(replace, "", false, true ); break; } } if (!found) target.mLibs.push(lib); } 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.setExt( (substitute(el.att.value)) ); case "builddir" : target.mBuildDir = substitute(el.att.name); case "libpath" : target.mLibPaths.push( substitute(el.att.name) ); case "fullouput" : target.mFullOutputName = substitute(el.att.name); case "fullunstripped" : target.mFullUnstrippedName = 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), el.has.asLibrary ); case "section" : createTarget(el,target,false); } } return target; } public function defined(inString:String):Bool { if (inString=="this_dir") return true; return mDefines.exists(inString); } public function parseBool(inValue:String):Bool { return inValue=="1" || inValue=="t" || inValue=="true"; } function findLocalIncludeFile(inBase:String):String { if (inBase == null || inBase=="") return ""; var c0 = inBase.substr(0,1); if (c0!="/" && c0!="\\") { var c1 = inBase.substr(1,1); if (c1!=":") { if (mCurrentIncludeFile!="") { var relative = Path.directory(mCurrentIncludeFile); var name = PathManager.combine(relative, inBase); if (FileSystem.exists(name)) return name; } for(p in mIncludePath) { var name = PathManager.combine(p, inBase); if (FileSystem.exists(name)) { return name; } } return ""; } } if (FileSystem.exists(inBase)) return inBase; return ""; } function findIncludeFile(inBase:String):String { var result = findLocalIncludeFile(inBase); if (result!="" && !Path.isAbsolute(result)) result = Path.normalize( PathManager.combine( mCurrentIncludeFile=="" ? Sys.getCwd() : Path.directory(mCurrentIncludeFile), result ) ); return result; } private static function getArch():String { if (isWindows) { if (isWindowsArm) return "arm64"; var architecture = Sys.getEnv("PROCESSOR_ARCHITECTURE"); var wow64Architecture = Sys.getEnv("PROCESSOR_ARCHITEW6432"); if (architecture.indexOf("64") > -1 || wow64Architecture != null && wow64Architecture.indexOf("64") > -1) { return "m64"; } else { return "m32"; } } 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("aarch64") > -1) || (output.indexOf("arm64") > -1) ) { return "arm64"; } else if (output.indexOf("64") > -1) { return "m64"; } else { return "m32"; } } } static public function getMsvcVer() { return instance.mDefines.get("MSVC_VER"); } static public function keepTemp() { return instance.mDefines.exists("HXCPP_KEEP_TEMP"); } // Setting HXCPP_COMPILE_THREADS to 2x number or cores can help with hyperthreading public static function getNumberOfProcesses():Int { var cache = Log.verbose; Log.verbose = false; var result = null; if (isWindows) { var env = Sys.getEnv("NUMBER_OF_PROCESSORS"); if (env != null) { result = env; } } else if (isLinux) { result = ProcessManager.runProcessLine("", "nproc", [], true, false, true, true); if (result == null) { var cpuinfo = ProcessManager.runProcess("", "cat", [ "/proc/cpuinfo" ], true, false, true, true); if (cpuinfo != null) { var split = cpuinfo.split("processor"); result = Std.string(split.length - 1); } } } else if (isMac) { var cores = ~/Total Number of Cores: (\d+)/; var output = ProcessManager.runProcess("", "/usr/sbin/system_profiler", [ "-detailLevel", "full", "SPHardwareDataType" ], true, false, true, true); if (output != null && cores.match(output)) { result = cores.matched(1); } } Log.verbose = cache; if (result == null || Std.parseInt(result) < 1) { return 1; } else { return Std.parseInt(result); } } private static function getVersion():String { try { var json = Json.parse (sys.io.File.getContent (PathManager.getHaxelib ("hxcpp") + "/haxelib.json")); return json.version; } catch (e:Dynamic) { return "0.0.0"; } } public static function isMsvc() { return instance.mDefines.get("toolchain")=="msvc"; } public static function isMingw() { return instance.mDefines.get("toolchain")=="mingw"; } public static function getNvcc() { return instance.mDefines.get("NVCC"); } public static function getNvccLinkFlags() : Array { return instance.mNvccLinkFlags; } public static function getNvccFlags() : Array { return instance.mNvccFlags; } public static function copy(from:String, to:String) { Log.v('copy $from $to'); try { if (FileSystem.isDirectory(to)) to += "/" + Path.withoutDirectory(from); var bytes = sys.io.File.getBytes(from); sys.io.File.saveBytes(to,bytes); } catch(e:Dynamic) { Log.error('Could not copy file $from $to'); } } static public function main() { try { runMain(); } catch(e:Dynamic) { Log.error('Uncaught exception on main thread: $e\n${haxe.CallStack.toString(haxe.CallStack.exceptionStack())}'); Tools.exit(1); } Tools.exit(0); } // Process args and environment. static function runMain() { var targets = new Array(); var defines = new Hash(); var include_path = new Array(); var makefile:String=""; var optionsTxt = "Options.txt"; Profile.start(); include_path.push("."); var args = Sys.args(); var env = Sys.environment(); for(e in env.keys()) defines.set(e, Sys.getEnv(e) ); // Check for calling from haxelib ... if (args.length>0) { var last:String = (new Path(args[args.length-1])).toString(); var isRootDir = last=="/"; if (!isRootDir) { var slash = last.substr(-1); if (slash=="/"|| slash=="\\") last = last.substr(0,last.length-1); } if (isRootDir || (FileSystem.exists(last) && FileSystem.isDirectory(last))) { // When called from haxelib, the last arg is the original directory, and // the current direcory is the library directory. HXCPP = PathManager.standardize(Sys.getCwd()); defines.set("HXCPP",HXCPP); args.pop(); Sys.setCwd(last); } } if (defines.exists("HXCPP_NO_COLOUR") || defines.exists("HXCPP_NO_COLOR")) Log.colorSupported = false; Log.verbose = defines.exists("HXCPP_VERBOSE"); exitOnThreadError = defines.exists("HXCPP_EXIT_ON_ERROR"); os = Sys.systemName(); startDir = Sys.getCwd(); isWindows = (new EReg("window","i")).match(os); if (isWindows) { var proc = Sys.getEnv("PROCESSOR_IDENTIFIER"); isWindowsArm = proc!=null && (new EReg("\\barm","i")).match(proc); if (isWindowsArm) defines.set("windows_arm_host", "1"); } isMac = (new EReg("mac","i")).match(os); if (isMac) defines.set("mac_host", "1"); isLinux = (new EReg("linux","i")).match(os); if (isLinux) defines.set("linux_host", "1"); if (args.length>0 && args[0].endsWith(".cppia")) { var binDir = isWindows ? "Windows" : isMac ? "Mac64" : isLinux ? "Linux64" : null; if (binDir==null) Log.error("Cppia is not supported on this host."); var arch = getArch(); var binDir = isWindows ? (isWindowsArm ? "WindowsArm64" : "Windows64" ) : isMac ? "Mac64" : isLinux ? ("Linux64") : null; var exe = '$HXCPP/bin/$binDir/Cppia' + (isWindows ? ".exe" : ""); if (!isWindows) { var phase = "find"; try { var stat = FileSystem.stat(exe); if (stat==null) throw "Could not find exe:" + exe; var mode = stat.mode; var exeFlags = (1<<0) | (1<<3) | (1<<6); if ( (mode&exeFlags) != exeFlags ) { var phase = "add exe permissions to"; if (Sys.command( "chmod", ["755", exe])!=0) Log.error('Please use root access to add execute permissions to $exe'); } } catch(e:Dynamic) { Log.error('Could not $phase Cppia host $exe ($e)'); } } #if (haxe_ver < 3.3) // avoid issue of path with spaces // https://github.com/HaxeFoundation/haxe/issues/3603 if (isWindows) exe = '"$exe"'; #end Tools.exit( Sys.command( exe, args ) ); } else if (args.length>0 && args[0].endsWith(".js")) { Setup.initHXCPPConfig(defines); Setup.setupEmscripten(defines); var node = defines.get("EMSCRIPTEN_NODE_JS"); Log.v( node==null ? "EMSCRIPTEN_NODE_JS undefined, using 'node'" : 'Using $node from EMSCRIPTEN_NODE_JS'); if (node=="" || node==null) node = "node"; Log.v( node + " " + args.join(" ") ); Tools.exit( Sys.command( node, args ) ); } else if (args.length==1 && args[0]=="defines") { var dir = '$HXCPP/tools/hxcpp'; try { var defineMatch = ~/m*defines\.\w+\("(\w+)"/i; var allDefines = new Map(); for(file in FileSystem.readDirectory(dir)) if (file.endsWith(".hx")) for(line in sys.io.File.getContent(file).split("\n")) if (defineMatch.match(line)) allDefines.set(defineMatch.matched(1),true); for(key in allDefines.keys()) Sys.println(key); } catch(e:Dynamic) { Log.error('Could not read $dir : $e'); } return; } isRPi = isLinux && Setup.isRaspberryPi(); is64 = getArch()!="m32"; var dirtyList = new Array(); var a = 0; while(a < args.length) { var arg = args[a]; if (arg.substr(0,2)=="-D" || (~/^[a-zA-Z0-9_][a-zA-Z0-9_-]*=/).match(arg) ) { var define = arg.substr(0,2)=="-D" ? arg.substr(2) : arg; var equals = define.indexOf("="); if (equals>0) { var value = define.substr(equals+1); define = define.substr(0,equals); if (define=="destination") { destination = value; } else defines.set(define,value); } else defines.set(define,""); if (define=="verbose") Log.verbose = true; } else if (arg=="-debug") defines.set("debug","1"); else if (arg=="-no-options") optionsTxt = ""; else if (arg=="-options") { a++; optionsTxt = args[a]; if (optionsTxt==null) optionsTxt = ""; } else if (arg=="-dirty") { a++; dirtyList.push(args[a]); } else if (arg=="-v" || arg=="-verbose") Log.verbose = true; else if (arg=="-nocolor") Log.colorSupported = false; else if (arg.substr(0,2)=="-I") include_path.push(PathManager.standardize(arg.substr(2))); else if (makefile.length==0) makefile = arg; else targets.push(arg); a++; } if (defines.exists("HXCPP_TIMES")) Profile.enable(); if (defines.exists("HXCPP_NO_COLOUR") || defines.exists("HXCPP_NO_COLOR")) Log.colorSupported = false; Log.verbose = Log.verbose || defines.exists("HXCPP_VERBOSE"); Log.quiet = defines.exists("HXCPP_QUIET") && !Log.verbose; Log.mute = defines.exists("HXCPP_SILENT") && !Log.quiet && !Log.verbose; if ( optionsTxt!="" && makefile!="") { var path = PathManager.combine(haxe.io.Path.directory(makefile), optionsTxt); if (FileSystem.exists(path)) try { var contents = sys.io.File.getContent(path); if (contents.substr(0,1)!=" ") // Is it New-style? for(def in contents.split("\r").join("").split("\n")) { var equals = def.indexOf("="); if (equals>0) { var name = def.substr(0,equals); var value = def.substr(equals+1); if (name=="hxcpp") { // Ignore } else if (name=="destination") destination = value; else defines.set(name,value); } } } catch(e:Dynamic) { Log.error('Could not parse options file $path ($e)'); } } Profile.setEntry("setup"); Setup.initHXCPPConfig(defines); if (HXCPP=="" && env.exists("HXCPP")) { HXCPP = PathManager.standardize(env.get("HXCPP")); defines.set("HXCPP",HXCPP); } if (HXCPP=="") { if (!defines.exists("HXCPP")) { Log.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); } //Log.info("", "HXCPP : " + HXCPP); include_path.push("."); if (env.exists("HOME")) include_path.push(env.get("HOME")); if (env.exists("USERPROFILE")) include_path.push(env.get("USERPROFILE")); include_path.push(HXCPP); //trace(include_path); //var msvc = false; // Create alias... if (defines.exists("ios")) { if (defines.exists("simulator")) defines.set("iphonesim", "iphonesim"); else if (!defines.exists ("iphonesim")) defines.set("iphoneos", "iphoneos"); defines.set("iphone", "iphone"); } if (defines.exists("tvos")) { if (defines.exists("simulator")) defines.set("appletvsim", "appletvsim"); else if (!defines.exists ("appletvsim")) defines.set("appletvos", "appletvos"); defines.set("appletv", "appletv"); } if (makefile=="" || Log.verbose) { printBanner(); } if (makefile=="") { printUsage(); } else { Log.v('${BOLD}${YELLOW}Using makefile: $makefile${NORMAL}'); Log.v('${BOLD}${YELLOW}Reading HXCPP config: ' + defines.get("HXCPP_CONFIG") + NORMAL); if (defines.exists("toolchain")) Log.v('${BOLD}{$YELLOW}Using target toolchain: ' + defines.get("toolchain") + NORMAL); else Log.v('${BOLD}${YELLOW}No specified toolchain${NORMAL}'); if (Log.verbose) Log.println(""); if (targets.length==0) targets.push("default"); new BuildTool(makefile,defines,targets,include_path,dirtyList); } } static function printUsage() { Log.println('${YELLOW}Usage:${NORMAL}'); Log.println(' ${BOLD}haxelib run hxcpp${NORMAL} file.xml ${ITALIC}${WHITE}[options]${NORMAL}'); Log.println(' Build project from "file.xml". options:'); Log.println(' ${BOLD}-D${NORMAL}${ITALIC}value${NORMAL} -- Specify a define to use when processing other commands'); Log.println(' ${BOLD}-verbose${NORMAL} -- Print additional information (when available)'); Log.println(' ${BOLD}-dirty [groudId|all]${NORMAL} -- always rebuild files in given group'); Log.println(' ${BOLD}haxelib run hxcpp${NORMAL} ${ITALIC}${WHITE}file.cppia${NORMAL}'); Log.println(' Run cppia script using default Cppia host'); Log.println(' ${BOLD}haxelib run hxcpp${NORMAL} ${ITALIC}${WHITE}file.js${NORMAL}'); Log.println(' Run emscripten compiled scipt "file.js"'); Log.println(' ${BOLD}haxelib run hxcpp${NORMAL} ${ITALIC}${WHITE}cache [command] [project]${NORMAL}'); Log.println(' Perform command on cache, either on specific project or all. commands:'); Log.println(' ${BOLD}clear${NORMAL} -- remove all files from cache'); Log.println(' ${BOLD}days${NORMAL} #days -- remove files older than "days"'); Log.println(' ${BOLD}resize${NORMAL} #megabytes -- Only keep #megabytes MB'); Log.println(' ${BOLD}list${NORMAL} -- list cache usage'); Log.println(' ${BOLD}details${NORMAL} -- list cache usage, per file'); Log.println(''); } static function printBanner() { Log.println("\x1b[33;1m __ "); Log.println("/\\ \\ "); Log.println("\\ \\ \\___ __ _ ___ _____ _____ "); Log.println(" \\ \\ _ `\\ /\\ \\/'\\ /'___\\/\\ '__`\\/\\ '__`\\ "); Log.println(" \\ \\ \\ \\ \\\\/> ) { if ( (new EReg("window","i")).match(os) ) defines.set("windows_host","1"); if (defines.exists("iphoneos")) { defines.set("toolchain","iphoneos"); defines.set("iphone","iphone"); defines.set("apple","apple"); defines.set("BINDIR","iPhone"); } else if (defines.exists("iphonesim")) { defines.set("toolchain","iphonesim"); defines.set("iphone","iphone"); defines.set("apple","apple"); defines.set("BINDIR","iPhone"); } else if (defines.exists("appletvos")) { defines.set("toolchain","appletvos"); defines.set("appletv","appletv"); defines.set("apple","apple"); defines.set("BINDIR","AppleTV"); } else if (defines.exists("appletvsim")) { defines.set("toolchain","appletvsim"); defines.set("appletv","appletv"); defines.set("apple","apple"); defines.set("BINDIR","AppleTV"); } else if (defines.exists("watchos")) { defines.set("toolchain","watchos"); defines.set("apple","apple"); defines.set("applewatch","applewatch"); defines.set("BINDIR","watchos"); } else if (defines.exists("watchsimulator")) { defines.set("toolchain","watchsimulator"); defines.set("applewatch","applewatch"); defines.set("apple","apple"); defines.set("BINDIR","watchsimulator"); } else if (defines.exists("android")) { defines.set("toolchain","android"); defines.set("android","android"); defines.set("BINDIR","Android"); if (!defines.exists("ANDROID_HOST")) { if ( (new EReg("mac","i")).match(os) ) defines.set("ANDROID_HOST","darwin-x86_64"); else if ( (new EReg("window","i")).match(os) ) { defines.set("windows_host","1"); defines.set("ANDROID_HOST","windows"); } else if ( (new EReg("linux","i")).match(os) ) defines.set("ANDROID_HOST","linux-x86_64"); else { Log.error ("Unknown android host \"" + os + "\""); //throw "Unknown android host:" + os; } } } else if (defines.exists("webos")) { defines.set("toolchain","webos"); defines.set("webos","webos"); defines.set("BINDIR","webOS"); } else if (defines.exists("tizen")) { defines.set("toolchain","tizen"); defines.set("tizen","tizen"); defines.set("BINDIR","Tizen"); } else if (defines.exists("blackberry")) { defines.set("toolchain", "blackberry"); defines.set("blackberry","blackberry"); defines.set("BINDIR","BlackBerry"); } else if (defines.exists("emcc") || defines.exists("emscripten")) { defines.set("toolchain","emscripten"); defines.set("emcc","emcc"); defines.set("emscripten","emscripten"); defines.set("BINDIR","Emscripten"); } else if (defines.exists("gph")) { defines.set("toolchain","gph"); defines.set("gph","gph"); defines.set("BINDIR","GPH"); } else if (defines.exists ("gcw0")) { defines.set ("toolchain", "gcw0"); defines.set ("gcw0", "gcw0"); defines.set ("BINDIR", "GCW0"); } else if (defines.exists("cygwin") || defines.exists("HXCPP_CYGWIN")) { set64(defines,m64); defines.set("toolchain","cygwin"); defines.set("cygwin","cygwin"); defines.set("linux","linux"); defines.set("BINDIR",m64 ? "Cygwin64":"Cygwin"); } else if ( (new EReg("window","i")).match(os) ) { defines.set("windows_host","1"); // Cross-compile? if (defines.exists("rpi")) { defines.set("toolchain","linux"); defines.set("xcompile","1"); defines.set("linux","linux"); defines.set("rpi","1"); defines.set("hardfp","1"); defines.set("BINDIR", "RPi"); } else { set64(defines,m64,arm64); defines.set("windows","windows"); defines.set("BINDIR",arm64 ? "WindowsArm64" : m64 ? "Windows64":"Windows"); // Choose between MSVC and MINGW var useMsvc = true; if (defines.exists("mingw") || defines.exists("HXCPP_MINGW") || defines.exists("minimingw")) useMsvc = false; else if ( defines.exists("winrt") || defines.exists("HXCPP_MSVC_VER")) useMsvc = true; else { for(i in 8...24) { if (Sys.getEnv("VS" + i + "0COMNTOOLS")!=null) { useMsvc = true; break; } } Log.v("Using Windows compiler: " + (useMsvc ? "MSVC" : "MinGW") ); } if (useMsvc) { defines.set("toolchain","msvc"); if ( defines.exists("winrt") ) defines.set("BINDIR",m64 ? "WinRT64":"WinRT"); } else { defines.set("toolchain","mingw"); defines.set("mingw","mingw"); } } } else if ( isRPi ) { defines.set("toolchain","linux"); defines.set("linux","linux"); defines.set("rpi","1"); defines.set("hardfp","1"); defines.set("BINDIR", "RPi"); } else if ( (new EReg("linux","i")).match(os) ) { set64(defines,m64,arm64); // Cross-compile? if(defines.exists("windows")) { defines.set("toolchain","mingw"); defines.set("xcompile","1"); defines.set("BINDIR", arm64 ? "WindowsArm64" : m64 ? "Windows64":"Windows"); } else { defines.set("toolchain","linux"); defines.set("linux","linux"); if (defines.exists("HXCPP_LINUX_ARMV7")) { defines.set("noM32","1"); defines.set("noM64","1"); defines.set("HXCPP_ARMV7","1"); m64 = false; } else if (arm64 || defines.exists("HXCPP_LINUX_ARM64")) { defines.set("noM32","1"); defines.set("noM64","1"); defines.set("HXCPP_ARM64","1"); m64 = true; } defines.set("BINDIR", m64 ? "Linux64":"Linux"); } } else if ( (new EReg("mac","i")).match(os) ) { set64(defines,m64, arm64); // Cross-compile? if (defines.exists("linux")) { defines.set("mac_host","1"); defines.set("linux","linux"); defines.set("toolchain","linux"); defines.set("xcompile","1"); defines.set("BINDIR", m64 ? "Linux64":"Linux"); } else { defines.set("toolchain","mac"); defines.set("macos","macos"); defines.set("apple","apple"); defines.set("BINDIR", arm64 ? "MacArm64" : m64 ? "Mac64":"Mac"); } } } function setupAppleDirectories(defines:Hash) { if (defines.exists("HXCPP_CLEAN_ONLY")) return; if (defines.exists("apple") && !defines.exists("DEVELOPER_DIR")) { var developer_dir = ProcessManager.runProcessLine("", "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") defines.set("LEGACY_XCODE_LOCATION","1"); defines.set("DEVELOPER_DIR",developer_dir); } if (defines.exists("iphone") && !defines.exists("IPHONE_VER")) { var dev_path = defines.get("DEVELOPER_DIR") + "/Platforms/iPhoneOS.platform/Developer/SDKs/"; if (FileSystem.exists(dev_path)) { var best="0.0"; var files = FileSystem.readDirectory(dev_path); var extract_version = ~/^iPhoneOS(.*).sdk$/; for(file in files) { if (extract_version.match(file)) { var ver = extract_version.matched(1); if (Std.parseFloat (ver)>Std.parseFloat (best)) best = ver; } } if (best!="0.0") defines.set("IPHONE_VER",best); } } if (defines.exists("appletv") && !defines.exists("TVOS_VER")) { var dev_path = defines.get("DEVELOPER_DIR") + "/Platforms/AppleTVOS.platform/Developer/SDKs/"; if (FileSystem.exists(dev_path)) { var best="0.0"; var files = FileSystem.readDirectory(dev_path); var extract_version = ~/^AppleTVOS(.*).sdk$/; for(file in files) { if (extract_version.match(file)) { var ver = extract_version.matched(1); if (Std.parseFloat (ver)>Std.parseFloat (best)) best = ver; } } if (best!="0.0") defines.set("TVOS_VER",best); } } if (defines.exists("applewatch") && !defines.exists("WATCHOS_VER")) { var dev_path = defines.get("DEVELOPER_DIR") + "/Platforms/WatchOS.platform/Developer/SDKs/"; if (FileSystem.exists(dev_path)) { var best="0.0"; var files = FileSystem.readDirectory(dev_path); var extract_version = ~/^WatchOS(.*).sdk$/; for(file in files) { if (extract_version.match(file)) { var ver = extract_version.matched(1); if (Std.parseFloat (ver)>Std.parseFloat (best)) best = ver; } } if (best!="0.0") defines.set("WATCHOS_VER",best); } } if (defines.exists("macos") && !defines.exists("MACOSX_VER")) { var dev_path = defines.get("DEVELOPER_DIR") + "/Platforms/MacOSX.platform/Developer/SDKs/"; if (FileSystem.exists(dev_path)) { var best="0.0"; var files = FileSystem.readDirectory(dev_path); var extract_version = ~/^MacOSX(.*).sdk$/; for(file in files) { if (extract_version.match(file)) { var ver = extract_version.matched(1); var split_best = best.split("."); var split_ver = ver.split("."); if (Std.parseFloat(split_ver[0]) > Std.parseFloat(split_best[0]) || Std.parseFloat(split_ver[1]) > Std.parseFloat(split_best[1])) best = ver; } } if (best!="0.0") defines.set("MACOSX_VER",best); else Log.v("Could not find MACOSX_VER!"); } } if (!FileSystem.exists(defines.get("DEVELOPER_DIR") + "/Platforms/MacOSX.platform/Developer/SDKs/")) { defines.set("LEGACY_MACOSX_SDK","1"); } } function parseXML(inXML:XmlAccess,inSection:String, forceRelative:Bool) { for(el in inXML.elements) { if (valid(el,inSection)) { switch(el.name) { case "set" : var name = substitute(el.att.name); var value = substitute(el.att.value); mDefines.set(name,value); case "unset" : var name = substitute(el.att.name); mDefines.remove(name); case "setup" : var name = substitute(el.att.name); Setup.setup(name,mDefines); case "echo" : Log.info(substitute(el.att.value)); case "setenv" : var name = substitute(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); Log.error(error); case "path" : var path = substitute(el.att.name); Log.info("", " - \x1b[1mAdding path:\x1b[0m " + path); 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 "manifest" : mManifester = createManifester(el,mManifester); case "prelinker" : var name = substitute(el.att.id); if (mPrelinkers.exists(name)) createPrelinker(el,mPrelinkers.get(name)); else mPrelinkers.set(name, createPrelinker(el,null) ); case "linker" : var name = substitute(el.att.id); if (mLinkers.exists(name)) createLinker(el,mLinkers.get(name)); else mLinkers.set(name, createLinker(el,null) ); case "files" : var name = substitute(el.att.id); var tags = el.has.tags ? substitute(el.att.tags) : null; if (mFileGroups.exists(name) ) createFileGroup(el, mFileGroups.get(name), name, false, tags); else mFileGroups.set(name,createFileGroup(el,null,name, forceRelative,tags)); case "include", "import" : var name = substitute(el.att.name); var section = el.has.section ? substitute(el.att.section) : ""; include(name, section, el.has.noerror, el.name=="import" ); 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), forceRelative); else mTargets.set( name, createTarget(el,null, forceRelative) ); case "mkdir" : var name = substitute(el.att.name); try { PathManager.mkdir(name); } catch(e:Dynamic) { Log.error("Could not create directory " + name ); } case "copy" : var from = substitute(el.att.from); from = PathManager.combine( Path.directory(mCurrentIncludeFile), from ); var to = substitute(el.att.to); to = PathManager.combine( Path.directory(mCurrentIncludeFile), to ); copy(from,to); case "copyFile" : mCopyFiles.push( new CopyFile(substitute(el.att.name), substitute(el.att.from), el.has.allowMissing ? subBool(el.att.allowMissing) : false, el.has.overwrite ? substitute(el.att.overwrite) : Overwrite.ALWAYS, el.has.toolId ? substitute(el.att.toolId) : null ) ); case "section" : parseXML(el,"",forceRelative); case "pleaseUpdateHxcppTool" : checkToolVersion( substitute(el.att.version) ); case "magiclib" : mMagicLibs.push( {name: substitute(el.att.name), replace:substitute(el.att.replace) } ); case "nvccflag" : if (el.has.name) mNvccFlags.push( substitute(el.att.name) ); mNvccFlags.push( substitute(el.att.value) ); case "nvcclinkflag" : if (el.has.name) mNvccLinkFlags.push( substitute(el.att.name) ); mNvccLinkFlags.push( substitute(el.att.value) ); case "pragma" : if (el.has.once) mPragmaOnce.set(mCurrentIncludeFile, parseBool(substitute(el.att.once))); } } } } public function checkToolVersion(inVersion:String) { var ver = Std.parseInt(inVersion); if (ver>3) Log.error("Your version of hxcpp.n is out-of-date. Please update."); } public function resolvePath(inPath:String) { return PathManager.combine( mCurrentIncludeFile=="" ? Sys.getCwd() : Path.directory(mCurrentIncludeFile), inPath); } public function include(inName:String, inSection:String="", inAllowMissing:Bool = false, forceRelative=false) { var full_name = findIncludeFile(inName); if (full_name!="") { if (mPragmaOnce.get(full_name)) return; pushFile(full_name, "include", inSection); // TODO - use mFileStack? var oldInclude = mCurrentIncludeFile; mCurrentIncludeFile = full_name; var make_contents = sys.io.File.getContent(full_name); var xml_slow = Xml.parse(make_contents); Profile.push( haxe.io.Path.withoutDirectory(inName) ); parseXML(new XmlAccess(xml_slow.firstElement()),inSection, forceRelative); Profile.pop(); mCurrentIncludeFile = oldInclude; popFile(); } else if (!inAllowMissing) { Log.error("Could not find include file \"" + inName + "\""); //throw "Could not find include file " + name; } } static function set64(outDefines:Hash, in64:Bool,isArm64=false) { if (isArm64) { outDefines.set("HXCPP_ARM64","1"); outDefines.set("HXCPP_M64","1"); outDefines.remove("HXCPP_32"); } else if (in64) { outDefines.set("HXCPP_M64","1"); outDefines.remove("HXCPP_32"); outDefines.remove("HXCPP_ARM64"); } else { outDefines.set("HXCPP_M32","1"); outDefines.remove("HXCPP_M64"); outDefines.remove("HXCPP_ARM64"); } } public function dospath(path:String) : String { if (mDefines.exists("windows_host")) { path = path.split("\\").join("/"); var filename = ""; var parts = path.split("/"); if (!FileSystem.isDirectory(path)) filename = parts.pop(); var oldDir = Sys.getCwd(); var output = ""; var err = ""; Sys.setCwd(parts.join("\\")); try { var bat = '$HXCPP/toolchain/dospath.bat'.split("/").join("\\"); var process = new Process("cmd",["/c",bat]); output = process.stdout.readAll().toString(); output = output.split("\r")[0].split("\n")[0]; err = process.stderr.readAll().toString(); process.close(); } catch (e:Dynamic) { Log.error(e); } Sys.setCwd(oldDir); if (output=="") Log.error("Could not find dos path for " + path + " " + err); return output + "\\" + filename; } return path; } public function substitute(str:String,needDollar=true):String { var match = needDollar ? mVarMatch : mNoDollarMatch; while( match.match(str) ) { var sub = match.matched(1); if (sub.startsWith("haxelib:")) { sub = PathManager.getHaxelib(sub.substr(8)); sub = PathManager.standardize(sub); } else if (sub.startsWith("removeQuotes:")) { sub = mDefines.get(sub.substr(13)); var len = sub.length; if (len>1 && sub.substr(0,1)=="\"" && sub.substr(len-1)=="\"") sub = sub.substr(1,len-2); } else if (sub.startsWith("dospath:") ) { sub = dospath( mDefines.get(sub.substr(8)) ); } else if (sub.startsWith("dir:") ) { sub = dospath( mDefines.get(sub.substr(4)) ); if (!FileSystem.isDirectory(sub)) { sub = haxe.io.Path.directory(sub); } } else if (sub=="this_dir") { sub = Path.normalize(mCurrentIncludeFile=="" ? Sys.getCwd() : Path.directory(mCurrentIncludeFile)); } else sub = mDefines.get(sub); if (sub==null) sub=""; str = match.matchedLeft() + sub + match.matchedRight(); } return str; } public function subBool(str:String):Bool { var result = substitute(str); return result=="t" || result=="true" || result=="1"; } public function valid(inEl:XmlAccess,inSection:String):Bool { 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) { 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.unlessApi) { var value = substitute(inEl.att.unlessApi); try { var val = Std.parseInt(value); if (val<=SupportedVersion) return false; } catch(e:Dynamic) { } } 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; } }