Update Files

This commit is contained in:
2025-01-22 16:18:30 +01:00
parent ed4603cf95
commit a36294b518
16718 changed files with 2960346 additions and 0 deletions

View File

@ -0,0 +1,158 @@
parameters:
name: ''
vmImage: ''
arch: '' # hxcpp's target arch (HXCPP_Mxx), can be '32' or '64'
platform: '' # can be linux64, mac, windows, or windows64
listPlatform32: ['linux32', 'windows']
listPlatform64: ['linux64', 'mac', 'windows64']
jobs:
- job: ${{ parameters.name }}
pool:
vmImage: ${{ parameters.vmImage }}
variables:
${{ if startsWith(parameters.vmImage, 'ubuntu-') }}:
libExt: .dso
sep: '/'
${{ if contains(parameters.vmImage, 'mac') }}:
libExt: .dylib
sep: '/'
${{ if contains(parameters.vmImage, 'win') }}:
libExt: .dll
sep: '\'
steps:
- ${{ if startsWith(parameters.vmImage, 'ubuntu-') }}:
- script: |
set -ex
sudo rm -R /var/lib/mysql/
# mariadb
curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup > mariadb_repo_setup
curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup.sha256 > mariadb_repo_setup.sha256
sha256sum --check mariadb_repo_setup.sha256
sudo bash mariadb_repo_setup
sudo apt-get update -qqy
sudo apt-get remove -qqy mysql-common
sudo apt-get autoremove -qqy
sudo apt-get install -qqy mariadb-server
# remaining packages
sudo apt-get install -qqy gcc-multilib g++-multilib
displayName: Install dependencies
- script: |
set -ex
sudo systemctl start mysql
sudo mysql -u root -e "create database hxcpp; grant all privileges on hxcpp.* to hxcpp@localhost identified by 'hxcpp'; flush privileges;"
displayName: Configure MariaDB
- template: install-neko-snapshot.yaml
parameters:
platform: ${{ parameters.platform }}
- template: install-haxe-snapshot.yaml
parameters:
platform: ${{ parameters.platform }}
- script: |
set -ex
mkdir -p ~/haxelib
haxelib setup ~/haxelib
haxelib install utest
haxelib dev hxcpp $(Build.SourcesDirectory)
haxelib list
displayName: Install Haxe libraries
- script: haxe compile.hxml
workingDirectory: tools/run
displayName: Build run.n
- script: haxe compile.hxml
workingDirectory: tools/hxcpp
displayName: Build hxcpp
- script: haxe compile-cppia.hxml
workingDirectory: project
displayName: Build cppia
# cffi
- script: haxelib run hxcpp build.xml -debug -DHXCPP_M${{parameters.arch}}
workingDirectory: test/cffi/project
displayName: Build cffi project
- bash: |
set -ex
haxe compile.hxml -debug -D HXCPP_M${{parameters.arch}}
haxe compile-utf8.hxml -debug -D HXCPP_M${{parameters.arch}}
haxe compile-neko.hxml -debug -D HXCPP_M${{parameters.arch}}
workingDirectory: test/cffi
displayName: cffi test - Compile
- script: bin$(sep)cpp$(sep)TestMain-debug
workingDirectory: test/cffi
displayName: cffi test - Run
- script: bin$(sep)cpp-utf8$(sep)TestMain-debug
workingDirectory: test/cffi
displayName: cffi-utf8 test - Run
- ${{ if or(and(containsValue(parameters.listPlatform32, parameters.platform), eq(parameters.arch, '32')), and(containsValue(parameters.listPlatform64, parameters.platform), eq(parameters.arch, '64'))) }}:
- bash: cp test/cffi/project/ndll/*/prime$(libExt) test/cffi/bin/neko/prime.ndll
displayName: Copy prime.ndll
- script: neko TestMain.n
workingDirectory: test/cffi/bin/neko
displayName: cffi-neko test - Run
# haxe
- script: haxe compile.hxml -debug -D HXCPP_M${{parameters.arch}}
workingDirectory: test/haxe
displayName: haxe test - Compile
- script: bin$(sep)TestMain-debug
workingDirectory: test/haxe
displayName: haxe test - Run
# telemetry, should work in debug and non-debug modes
- script: haxe compile.hxml -debug -D HXCPP_M${{parameters.arch}}
workingDirectory: test/telemetry
displayName: telemetry test (debug) - Compile
- script: bin$(sep)TestMain-debug
workingDirectory: test/telemetry
displayName: telemetry test (debug) - Run
- script: haxe compile.hxml -D HXCPP_M${{parameters.arch}}
workingDirectory: test/telemetry
displayName: telemetry test - Compile
- script: bin$(sep)TestMain
workingDirectory: test/telemetry
displayName: telemetry test - Run
# std
- script: haxe compile${{parameters.arch}}.hxml
workingDirectory: test/std
displayName: std test - Compile
- script: cpp${{parameters.arch}}$(sep)Test
workingDirectory: test/std
displayName: std test - Run
# debugger
- script: haxe compile.hxml -D HXCPP_M${{parameters.arch}}
workingDirectory: test/debugger
displayName: debugger test - Compile
- script: bin$(sep)App-debug
workingDirectory: test/debugger
displayName: debugger test - Run
# native
- script: haxe compile.hxml -D HXCPP_M${{parameters.arch}}
workingDirectory: test/native
displayName: native test - Compile
- script: bin$(sep)Native
workingDirectory: test/native
displayName: native test - Run
# haxe unit test
- bash: |
set -ex
HAXE_VERSION=`haxe -version`
HAXE_HASH=`[[ "$HAXE_VERSION" =~ ^.+\+(.+) ]] && echo ${BASH_REMATCH[1]}`
git clone -q https://github.com/HaxeFoundation/haxe.git
pushd haxe
git reset --hard "$HAXE_HASH"
git clean -fdx
popd
displayName: haxe unit test - Clone haxe repo
- script: haxelib install compile-cpp.hxml --always
workingDirectory: haxe/tests/unit
displayName: haxe unit test - Install haxelibs
- script: haxe compile-cpp.hxml -D HXCPP_M${{parameters.arch}} -D no_http
workingDirectory: haxe/tests/unit
displayName: haxe unit test - Compile
- script: bin$(sep)cpp$(sep)TestMain-debug
workingDirectory: haxe/tests/unit
displayName: haxe unit test - Run

View File

@ -0,0 +1,31 @@
parameters:
platform: '' # can be linux64, mac, windows, or windows64
steps:
- ${{ if startsWith(parameters.platform, 'windows') }}:
- powershell: |
Invoke-WebRequest https://build.haxe.org/builds/haxe/${{parameters.platform}}/haxe_latest.zip -OutFile $(Agent.TempDirectory)/haxe_latest.zip
Expand-Archive $(Agent.TempDirectory)/haxe_latest.zip -DestinationPath $(Agent.TempDirectory)
Remove-Item $(Agent.TempDirectory)/haxe_latest.zip
$HAXEPATH = Get-Item $(Agent.TempDirectory)/haxe_*
$HAXE_STD_PATH = "$HAXEPATH\std"
Write-Host "##vso[task.prependpath]$HAXEPATH"
Write-Host "##vso[task.setvariable variable=HAXE_STD_PATH]$HAXE_STD_PATH"
displayName: Install Haxe using snapshot from S3
- ${{ if not(startsWith(parameters.platform, 'windows')) }}:
- bash: |
set -ex
DOWNLOADDIR=$(Agent.TempDirectory)
curl -sSL https://build.haxe.org/builds/haxe/${{parameters.platform}}/haxe_latest.tar.gz -o $(Agent.TempDirectory)/haxe_latest.tar.gz
tar -xf $(Agent.TempDirectory)/haxe_latest.tar.gz -C $(Agent.TempDirectory)
rm $(Agent.TempDirectory)/haxe_latest.tar.gz
HAXEPATH=`echo $(Agent.TempDirectory)/haxe_*`
sudo mkdir -p /usr/local/bin
sudo mkdir -p /usr/local/share/haxe
sudo ln -s $HAXEPATH/{haxe,haxelib} /usr/local/bin/
sudo ln -s $HAXEPATH/std /usr/local/share/haxe/std
set +x
echo "##vso[task.setvariable variable=HAXE_STD_PATH]/usr/local/share/haxe/std"
displayName: Install Haxe using snapshot from S3
- script: haxe -version
displayName: Print Haxe version

View File

@ -0,0 +1,33 @@
parameters:
platform: '' # can be linux64, mac, windows, or windows64
steps:
- ${{ if startsWith(parameters.platform, 'windows') }}:
- powershell: |
Invoke-WebRequest https://build.haxe.org/builds/neko/${{parameters.platform}}/neko_latest.zip -OutFile $(Agent.TempDirectory)/neko_latest.zip
Expand-Archive $(Agent.TempDirectory)/neko_latest.zip -DestinationPath $(Agent.TempDirectory)
$NEKOPATH = Get-ChildItem $(Agent.TempDirectory)/neko-*-win
Write-Host "##vso[task.prependpath]$NEKOPATH"
Write-Host "##vso[task.setvariable variable=NEKOPATH]$NEKOPATH"
displayName: Install Neko using snapshot from S3
- ${{ if not(startsWith(parameters.platform, 'windows')) }}:
- bash: |
set -ex
DOWNLOADDIR=$(Agent.TempDirectory)
curl -sSL https://build.haxe.org/builds/neko/${{parameters.platform}}/neko_latest.tar.gz -o $(Agent.TempDirectory)/neko_latest.tar.gz
tar -xf $(Agent.TempDirectory)/neko_latest.tar.gz -C $(Agent.TempDirectory)
NEKOPATH=`echo $(Agent.TempDirectory)/neko-*-*`
sudo mkdir -p /usr/local/bin
sudo mkdir -p /usr/local/lib/neko
sudo ln -s $NEKOPATH/{neko,nekoc,nekoml,nekotools} /usr/local/bin/
sudo ln -s $NEKOPATH/libneko.* /usr/local/lib/
sudo ln -s $NEKOPATH/*.ndll /usr/local/lib/neko/
set +x
echo "##vso[task.prependpath]$NEKOPATH"
echo "##vso[task.setvariable variable=NEKOPATH]$NEKOPATH"
displayName: Install Neko using snapshot from S3
- ${{ if eq(parameters.platform, 'linux64') }}:
- bash: sudo ldconfig
displayName: ldconfig
- script: neko -version 2>&1
displayName: Print Neko version

View File

@ -0,0 +1,39 @@
class Build extends hxcpp.Builder
{
// Create a build in 'bin' directory, with the "stdlibc++" flags for compatibility
// This flasg should not make a difference because hxcpp does not use stdlibc++
override public function wantLegacyIosBuild() { return true; }
override public function wantWindows64() { return true; }
// Override to ensure this version if hxcpp is used, even if haxelib says otherwise
override public function runBuild(target:String, isStatic:Bool, arch:String, inFlags:Array<String>)
{
var args = ["run.n", "Build.xml"].concat(inFlags);
var here = Sys.getCwd().split("\\").join("/");
var parts = here.split("/");
if (parts.length>0 && parts[parts.length-1]=="")
parts.pop();
if (parts.length>0)
parts.pop();
var hxcppDir = parts.join("/");
// This is how haxelib calls a 'run.n' script...
Sys.setCwd(hxcppDir);
args.push(here);
Sys.println("neko " + args.join(" "));
if (Sys.command("neko",args)!=0)
{
Sys.println("#### Error building neko " + inFlags.join(" "));
Sys.exit(-1);
}
Sys.setCwd(here);
}
public static function main()
{
new Build( Sys.args() );
}
}

View File

@ -0,0 +1,5 @@
-neko ../../project/build.n
-main Build
-D neko_v1
-lib hxcpp
-debug

View File

@ -0,0 +1,32 @@
#!/bin/bash
set -ev
git clone --recursive https://github.com/HaxeFoundation/haxe.git ~/haxe --depth 1
sudo add-apt-repository ppa:avsm/ppa -y
sudo add-apt-repository ppa:haxe/snapshots -y
sudo apt-get update
sudo apt-get install -y \
neko \
ocaml-nox \
camlp4-extra \
opam \
libpcre3-dev \
zlib1g-dev \
awscli
export OPAMYES=1
opam init
eval `opam config env`
opam pin add haxe ~/haxe --no-action
opam install haxe --deps-only
# Build haxe
pushd ~/haxe
make ADD_REVISION=1 && sudo make install INSTALL_DIR=/usr/local
popd
haxe -version
# setup haxelib
mkdir ~/haxelib && haxelib setup ~/haxelib
haxelib dev hxcpp $TRAVIS_BUILD_DIR
haxelib install record-macros

View File

@ -0,0 +1,28 @@
#!/bin/bash
set -ev
git clone --recursive https://github.com/HaxeFoundation/haxe.git ~/haxe --depth 1
brew update
brew tap Homebrew/bundle
brew bundle --file=~/haxe/tests/Brewfile --no-upgrade
brew install neko --HEAD;
export OPAMYES=1
opam init
eval `opam config env`
opam update
opam pin add haxe ~/haxe --no-action
opam install haxe --deps-only
# Build haxe
pushd ~/haxe
make ADD_REVISION=1 && sudo make install INSTALL_DIR=/usr/local
popd
haxe -version
# setup haxelib
mkdir ~/haxelib && haxelib setup ~/haxelib
haxelib dev hxcpp $TRAVIS_BUILD_DIR
haxelib install record-macros

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,304 @@
import sys.FileSystem;
class CompileCache
{
public static var hasCache = false;
public static var compileCache:String;
public static function init(inDefines:Map<String, String>) : Bool
{
compileCache = "";
hasCache = false;
if (inDefines.exists("HXCPP_COMPILE_CACHE"))
{
compileCache = inDefines.get("HXCPP_COMPILE_CACHE");
compileCache = compileCache.split("\\").join("/");
// Don't get upset by trailing slash
while(compileCache.length>1)
{
var l = compileCache.length;
var last = compileCache.substr(l-1);
if (last=="/")
compileCache = compileCache.substr(0,l-1);
else
break;
}
if (!FileSystem.exists(compileCache))
{
try{
PathManager.mkdir(compileCache);
}
catch(e:Dynamic)
{
Log.error("Could not create compiler cache directory \"" + compileCache + "\"");
}
}
if (FileSystem.exists(compileCache) && FileSystem.isDirectory(compileCache))
{
hasCache = true;
}
else
{
Log.error("Could not find compiler cache \"" + compileCache + "\"");
//throw "Could not find compiler cache: " + compileCache;
}
}
if (hasCache)
{
Log.info("", "\x1b[33;1mUsing compiler cache: " + compileCache + "\x1b[0m");
}
return hasCache;
}
/*
public static function getPchCacheName(inProject:String,hash:String,header:String, inExt:String)
{
var dir = compileCache + "/" + inProject + "/pch" + hash.substr(0,8);
try
{
if (!FileSystem.exists(dir))
PathManager.mkdir(dir);
} catch(e:Dynamic) { }
return dir + "/" + header + inExt;
}
*/
public static function getPchDir(inProject:String,hash:String)
{
var dir = compileCache + "/" + inProject + "/pch" + hash.substr(0,8);
try
{
if (!FileSystem.exists(dir))
PathManager.mkdir(dir);
} catch(e:Dynamic) { }
return dir;
}
public static function getCacheName(inProject:String,hash:String,inExt:String)
{
var dir = compileCache + "/" + inProject + "/" + hash.substr(0,2);
try
{
if (!FileSystem.exists(dir))
PathManager.mkdir(dir);
} catch(e:Dynamic) { }
return dir + "/" + hash.substr(2) + inExt;
}
public static function clear(inDays:Int,inMB:Int,inLogInfo:Bool,inProject:String)
{
try
{
var projects = FileSystem.readDirectory(compileCache);
var deleted = 0;
var total = 0;
var t0 = haxe.Timer.stamp();
var tooOld = Date.now().getTime() - inDays * 24 * 3600 * 1000.0;
var sizeKB:Float = 0;
var fileInfo = [];
for(project in projects)
{
if (inProject!=null && inProject!=project)
continue;
var projectHasDirs = false;
var projDir = compileCache + "/" + project;
if(!FileSystem.isDirectory(projDir))
continue;
var dirs = FileSystem.readDirectory(projDir);
for(dir in dirs)
{
var path = projDir + "/" + dir;
if(!FileSystem.isDirectory(path)) {
FileSystem.deleteFile(path);
continue;
}
if (dir.length!=2 && dir!="lib" && dir.substr(0,3)!="pch" )
{
Log.warn('bad cache name "$dir" found - try manually clearing');
continue;
}
var dirFiles = FileSystem.readDirectory(path);
var allDeleted = true;
for(file in dirFiles)
{
total++;
var filename = path + "/" + file;
var doDelete = true;
if (inDays>0)
{
var info = FileSystem.stat(filename);
var atime = info.atime;
var time = atime==null ? info.mtime.getTime() :
Math.max(info.atime.getTime(),info.mtime.getTime() );
if (time>=tooOld)
doDelete = false;
}
else if (inMB>0)
{
var info = FileSystem.stat(filename);
var atime = info.atime;
var time = atime==null ? info.mtime.getTime() :
Math.max(info.atime.getTime(),info.mtime.getTime() );
fileInfo.push( {filename:filename, time:time, size:info.size } );
sizeKB += info.size/1024;
doDelete = false;
}
if (doDelete)
{
try
{
FileSystem.deleteFile(filename);
deleted++;
}
catch(e:Dynamic)
{
Log.warn('Could not delete $filename');
}
}
else
allDeleted = false;
}
if (allDeleted)
{
try
{
FileSystem.deleteDirectory(path);
}
catch(e:Dynamic)
{
Log.warn('Could not delete directory $path');
}
}
else
projectHasDirs = true;
}
if (!projectHasDirs)
{
try
{
FileSystem.deleteDirectory(projDir);
}
catch(e:Dynamic)
{
Log.warn('Could not delete directory $projDir');
}
}
}
if (inMB*1024<sizeKB)
{
// newest first
fileInfo.sort( function(a,b) return a.time > b.time ? -1 : 1 );
var keepKB:Float = inMB*1024;
for(info in fileInfo)
{
if (keepKB>0)
{
sizeKB -= info.size/1024;
keepKB -= info.size/1024;
}
else
{
try
{
FileSystem.deleteFile(info.filename);
deleted++;
}
catch(e:Dynamic)
{
Log.warn('Could not delete ${info.filename}');
}
}
}
}
var t = haxe.Timer.stamp()-t0;
var projString = inProject==null ? "" : ' from project $inProject';
var message = inMB > 0 ?
'Cache: removed $deleted/$total files$projString, leaving ' + Std.int(sizeKB/1024) + 'MB, in $t seconds' :
'Cache: removed $deleted/$total files$projString in $t seconds';
if (inLogInfo)
Log.info(message);
else
Log.v(message);
}
catch(error:Dynamic)
{
Log.warn("Error cleaning cache: " + error);
}
}
public static function list(inDetails:Bool,inProject:String)
{
try
{
Sys.println('Cache Directory: $compileCache');
var t0 = haxe.Timer.stamp();
var files = new Array<String>();
var projects = FileSystem.readDirectory(compileCache);
var size = 0.0;
var count = 0;
for(project in projects)
{
if (inProject!=null && inProject!=project)
continue;
var projSize = size;
var projCount = count;
var projDir = compileCache + "/" + project;
if(!FileSystem.isDirectory(projDir))
continue;
var dirs = FileSystem.readDirectory(projDir);
for(dir in dirs)
{
var path = projDir + "/" + dir;
if(!FileSystem.isDirectory(path))
continue;
var dirFiles = FileSystem.readDirectory(path);
for(file in dirFiles)
{
var filename = path + "/" + file;
var info = FileSystem.stat(filename);
if (inDetails)
{
var atime = info.atime;
if (atime==null || atime.getTime()<info.mtime.getTime())
atime = info.mtime;
Sys.println('$filename : ${info.size} bytes, $atime');
}
count++;
size += info.size;
}
//files = files.concat(dirFiles);
}
projSize = Std.int( (size - projSize)/1024 );
projCount = count - projCount;
Sys.println('Project $project\t: ${projSize}k in $projCount files');
}
var k = Std.int(size/1024);
var t = haxe.Timer.stamp()-t0;
var projString = inProject==null ? "" : ' in project $inProject';
Sys.println('Found: ${k}k in $count files$projString in $t seconds');
}
catch(error:Dynamic)
{
Log.warn("Error accessing cache: " + error);
}
}
}

View File

@ -0,0 +1,642 @@
import haxe.crypto.Md5;
import haxe.io.Path;
import sys.FileSystem;
private class FlagInfo
{
var flag:String;
var tag:String;
public function new(inFlag:String, inTag:String)
{
flag = inFlag;
tag = inTag;
}
public function add(args:Array<String>, inFilter:Array<String>)
{
var allowSpace = inFilter.indexOf("nvcc")<0;
if ((tag==""&&allowSpace) || inFilter.indexOf(tag)>=0)
args.push(flag);
}
public function toString():String
{
if (tag=="")
return flag;
else
return '$flag($tag)';
}
}
class Compiler
{
private var mFlags:Array<FlagInfo>;
public var mCFlags:Array<String>;
public var mNvccFlags:Array<String>;
public var mMMFlags:Array<String>;
public var mCPPFlags:Array<String>;
public var mOBJCFlags:Array<String>;
public var mPCHFlags:Array<String>;
public var mAddGCCIdentity:Bool;
public var mExe:String;
public var mOutFlag:String;
public var mObjDir:String;
public var mRelObjDir: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 mRcExe:String;
public var mRcExt:String;
public var mRcFlags:Array<String>;
public var mGetCompilerVersion:String;
public var mCompilerVersion:String;
public var mCompilerVersionString:String;
public var mCached:Bool;
public var mID:String;
//testing...
public var useCacheInPlace = true;
//public var useCacheInPlace = false;
public function new(inID,inExe:String)
{
mFlags = [];
mCFlags = [];
mNvccFlags = [];
mCPPFlags = [];
mOBJCFlags = [];
mMMFlags = [];
mPCHFlags = [];
mAddGCCIdentity = false;
mCompilerVersion = null;
mRcExt = ".res";
mObjDir = "obj";
mOutFlag = "-o";
mExe = inExe;
mID = inID;
mExt = ".o";
mPCHExt = ".pch";
mPCHCreate = "-Yc";
mPCHUse = "-Yu";
mPCHFilename = "/Fp";
mCached = false;
mRcFlags = [];
}
public function getFlagStrings()
{
var result = new Array<String>();
for(f in mFlags)
result.push( f.toString() );
return result;
}
public function addFlag(inFlag:String, inTag:String)
{
mFlags.push( new FlagInfo(inFlag, inTag) );
}
public function objToAbsolute()
{
if (mRelObjDir==null)
mRelObjDir = mObjDir;
mObjDir = Path.normalize( PathManager.combine( Sys.getCwd(), mRelObjDir ) );
}
public function getTargetPrefix()
{
var dir = mRelObjDir!=null ? mRelObjDir : mObjDir;
dir = dir.split("\\").join("/");
var parts = dir.split("/");
// Trailing slash?
var prefix = parts.pop();
if (prefix=="")
prefix = parts.pop();
if (prefix==null)
prefix = "";
prefix = prefix.split("-").join("_");
return prefix;
}
function addIdentity(ext:String,ioArgs:Array<String>)
{
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);
}
}
}
function addOptimTags(tagFilter:Array<String>)
{
var optimFlags = (tagFilter.indexOf("debug") >= 0 ? 1 : 0) +
(tagFilter.indexOf("release") >= 0 ? 1 : 0) +
(tagFilter.indexOf("optim-std") >= 0 ? 1 : 0) +
(tagFilter.indexOf("optim-none") >= 0 ? 1 : 0) +
(tagFilter.indexOf("optim-size") >= 0 ? 1 : 0);
if (optimFlags==0)
tagFilter.push("optim-std");
else if (optimFlags>1)
Log.error("More than one optimization tag has been set:" + tagFilter);
}
public function getCompilerDefines(inTags:String)
{
var args = new Array<String>();
var tagFilter = inTags.split(",");
addOptimTags(tagFilter);
for(flag in mFlags)
flag.add(args,tagFilter);
return args;
}
function getArgs(inFile:File)
{
var nvcc = inFile.isNvcc();
var isRc = mRcExe!=null && inFile.isResource();
var args = nvcc ? inFile.mGroup.mCompilerFlags.concat( BuildTool.getNvccFlags() ) :
inFile.mCompilerFlags.concat(inFile.mGroup.mCompilerFlags);
var tagFilter = inFile.getTags().split(",");
addOptimTags(tagFilter);
if (!isRc)
for(flag in mFlags)
flag.add(args,tagFilter);
var ext = mExt.toLowerCase();
var ext = new Path(inFile.mName).ext;
if (ext!=null)
ext = ext.toLowerCase();
else
Log.error("Unkown extension for " + inFile.mName);
addIdentity(ext,args);
var allowPch = false;
if (nvcc)
args = args.concat(mNvccFlags);
else if (isRc)
args = args.concat(mRcFlags);
else 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++" || ext=="cc")
{
allowPch = true;
args = args.concat(mCPPFlags);
}
if (isRc || inFile.getTags()!=inFile.mGroup.getTags())
allowPch = false;
if (inFile.mGroup.isPrecompiled() && allowPch)
{
var pchDir = getPchDir(inFile.mGroup);
if (mPCHUse!="")
{
args.push(mPCHUse + inFile.mGroup.mPrecompiledHeader + ".h");
args.push(mPCHFilename + pchDir + "/" + inFile.mGroup.getPchName() + mPCHExt);
}
else
args.unshift("-I"+pchDir);
}
return args;
}
public function createEmbedFile(srcName:String, destName:String, embedName:String, scramble:String)
{
try
{
var content = sys.io.File.getContent(srcName);
var output = new Array<String>();
if (scramble==null)
{
output.push( 'const char *$embedName = ' );
content = content.split("\r").join("");
content = content.split("\\").join( String.fromCharCode(1) );
content = content.split('"').join('\\"');
content = content.split(String.fromCharCode(1)).join("\\\\" );
var lines = content.split("\n");
for(line in lines)
output.push( '"$line\\n"' );
output.push(";\n");
}
else
{
var bytes = haxe.io.Bytes.ofString(content);
var byteLen = bytes.length;
var key = haxe.io.Bytes.ofString(scramble);
var keyLen = key.length;
var state = 0;
var line = "";
output.push( 'int ${embedName}_len = $byteLen;' );
output.push( 'static const unsigned char data[] = {' );
for(i in 0...byteLen)
{
var ch = bytes.get(i);
state = (((state + key.get(i%keyLen)) ^ ch) & 0xff);
line += state + ",";
if ( (i%10)==9 )
{
output.push(line);
line = "";
}
}
if (line!="")
output.push(line);
output.push( '};' );
output.push( 'const unsigned char * $embedName = data;' );
}
sys.io.File.saveContent(destName, output.join("\n") );
}
catch(e:Dynamic)
{
Log.warn('Error creating $destName from $srcName: $e');
}
}
public function cleanTmp(file:String)
{
if (BuildTool.keepTemp())
return;
try
{
if (file!=null && FileSystem.exists(file))
FileSystem.deleteFile(file);
}
catch(e:Dynamic) { }
}
public function compile(inFile:File,inTid:Int,headerFunc:Void->Void,pchTimeStamp:Null<Float>)
{
var obj_name = getObjName(inFile);
var args = getArgs(inFile);
var nvcc = inFile.isNvcc();
var exe = nvcc ? BuildTool.getNvcc() : mExe;
var isRc = mRcExe!=null && inFile.isResource();
if (isRc)
exe = mRcExe;
var found = false;
var cacheName:String = null;
if (mCompilerVersion!=null && inFile.mGroup.isCached())
{
cacheName = getHashedName(inFile, args);
if (useCacheInPlace)
{
//Log.info(""," link cache for " + obj_name );
obj_name = cacheName;
}
if (FileSystem.exists(cacheName))
{
var newer = true;
if (pchTimeStamp!=null || inFile.mGroup.mRespectTimestamp)
{
var time = FileSystem.stat(cacheName).mtime.getTime();
if (pchTimeStamp!=null)
newer = time>=pchTimeStamp;
if (inFile.mGroup.mRespectTimestamp)
newer = newer && time>= FileSystem.stat(inFile.mDir + "/" + inFile.mName).mtime.getTime();
}
if (newer)
{
//Log.info(""," copy cache for " + obj_name );
if (!useCacheInPlace)
sys.io.File.copy(cacheName, obj_name);
found = true;
}
}
}
if (!found)
{
if (headerFunc!=null)
headerFunc();
var tmpFile:String = null;
var delayedFilename:String = null;
if (inFile.mEmbedName!=null)
{
var srcDir = Path.directory( inFile.mDir + "/" + inFile.mName);
tmpFile = new Path( srcDir + "/" + inFile.mEmbedName + ".cpp").toString();
Log.v("Creating temp file " + tmpFile);
createEmbedFile( inFile.mDir + "/" + inFile.mName, tmpFile, inFile.mEmbedName, inFile.mScramble );
args.push( tmpFile );
}
else
{
if (isRc)
delayedFilename = (new Path( inFile.mDir + inFile.mName)).toString();
else
args.push( (new Path( inFile.mDir + inFile.mName)).toString() );
}
var out = nvcc ? "-o " : mOutFlag;
if (out.substr(-1)==" ")
{
args.push(out.substr(0,out.length-1));
out = "";
}
args.push(out + obj_name);
if (delayedFilename!=null)
args.push(delayedFilename);
var tagInfo = inFile.mTags==null ? "" : " " + inFile.mTags.split(",");
var fileName = inFile.mName;
var split = fileName.split ("/");
if (split.length > 1)
{
fileName = " \x1b[2m-\x1b[0m \x1b[33m" + split.slice(0, split.length - 1).join("/") + "/\x1b[33;1m" + split[split.length - 1] + "\x1b[0m";
}
else
{
fileName = " \x1b[2m-\x1b[0m \x1b[33;1m" + fileName + "\x1b[0m";
}
fileName += " \x1b[3m" + tagInfo + "\x1b[0m";
if (inTid >= 0)
{
if (BuildTool.threadExitCode == 0)
{
if (!Log.verbose)
{
Log.info(fileName);
}
var err = ProcessManager.runProcessThreaded(exe, args, null);
cleanTmp(tmpFile);
if (err!=0)
{
if (FileSystem.exists(obj_name))
FileSystem.deleteFile(obj_name);
BuildTool.setThreadError(err);
}
}
}
else
{
if (!Log.verbose)
{
Log.info(fileName);
}
var result = ProcessManager.runProcessThreaded(exe, args, null);
cleanTmp(tmpFile);
if (result!=0)
{
if (FileSystem.exists(obj_name))
FileSystem.deleteFile(obj_name);
Tools.exit (result);
//throw "Error : " + result + " - build cancelled";
}
}
if (cacheName!=null && !useCacheInPlace)
{
Log.info("", " caching " + cacheName);
sys.io.File.copy(obj_name, cacheName);
}
}
return obj_name;
}
public function createCompilerVersion(inGroup:FileGroup)
{
if ( mCompilerVersion==null)
{
var versionString = "";
var command = "";
if (mGetCompilerVersion==null)
{
command = mExe + " --version";
versionString = ProcessManager.readStdout(mExe,["--version"]).join(" ");
}
else
{
command = mGetCompilerVersion;
versionString = ProcessManager.readStderr(mGetCompilerVersion,[]).join(" ");
}
if (versionString=="" || versionString==null)
Log.error("Could not deduce compiler version with " + command);
Log.info("", "Compiler version: " + versionString);
mCompilerVersionString = versionString;
mCompilerVersion = Md5.encode(versionString);
mCached = true;
}
return mCached;
}
function getObjName(inFile:File)
{
var isRc = mRcExe!=null && inFile.isResource();
var path = new Path(inFile.mName);
var dirId = Md5.encode(BuildTool.targetKey + path.dir + inFile.mGroup.mId).substr(0,8) + "_";
return PathManager.combine(mObjDir, inFile.mGroup.mObjPrefix + dirId + path.file + (isRc ? mRcExt : mExt) );
}
function getHashedName(inFile:File, args:Array<String>)
{
var sourceName = inFile.mDir + inFile.mName;
var contents = sys.io.File.getContent(sourceName);
if (contents!="")
{
var md5 = Md5.encode(contents + args.join(" ") +
inFile.mGroup.mDependHash + mCompilerVersion + inFile.mDependHash );
return CompileCache.getCacheName(inFile.getCacheProject(),md5,mExt);
}
else
throw "Unkown source contents " + sourceName;
return "";
}
public function getCacheString(inFile:File)
{
var args = getArgs(inFile);
return ("<contents>" + args.join(" ") + " " + inFile.mGroup.getDependString() + " " + mCompilerVersionString + " " + inFile.getDependString() );
}
public function getCachedObjName(inFile:File)
{
if (mCompilerVersion!=null && useCacheInPlace && inFile.mGroup.isCached())
{
//trace(inFile.mName + " " + inFile.getTags().split(",") + " " + getFlagStrings() + " " + getArgs(inFile));
return getHashedName(inFile, getArgs(inFile));
}
else
return getObjName(inFile);
}
public function needsPchObj()
{
return mPCH!="gcc";
}
/*
public function getPchObjName(group:FileGroup)
{
var pchDir = getPchDir(group);
if (pchDir != "")
return pchDir + "/" + group.getPchName() + mExt;
throw "Missing precompiled directory name";
}
*/
public function getPchCompileFlags(inGroup:FileGroup)
{
var args = inGroup.mCompilerFlags.copy();
var tags = inGroup.mTags.split(",");
addOptimTags(tags);
for(flag in mFlags)
flag.add(args,tags);
return args.concat( mCPPFlags );
}
public function getPchDir(inGroup:FileGroup)
{
if (!inGroup.isCached())
return inGroup.getPchDir(mObjDir);
var args = getPchCompileFlags(inGroup);
var md5 = Md5.encode(args.join(" ") + inGroup.mPrecompiledHeader +
inGroup.mDependHash + mCompilerVersion );
return CompileCache.getPchDir(inGroup.getCacheProject(),md5);
}
public function precompile(inGroup:FileGroup, inReuseIfPossible:Bool)
{
// header will be like "hxcpp" or "wx/wx"
var header = inGroup.mPrecompiledHeader;
// file will be like "hxcpp" or "wx"
var file = inGroup.getPchName();
var args = getPchCompileFlags(inGroup);
// Local output dir
var dir = getPchDir(inGroup);
// Like objs/hxcpp.pch or objs/wx.gch
var pch_name = dir + "/" + file + mPCHExt;
if (inGroup.isCached() || inReuseIfPossible)
{
// No obj needed for gcc
var obj = mPCH=="gcc" ? null : PathManager.combine(dir, file + mExt);
if (FileSystem.exists(pch_name) && (obj==null || FileSystem.exists(obj)) )
return obj;
}
args = args.concat( mPCHFlags );
//Log.info("", "Make pch dir " + dir );
PathManager.mkdir(dir);
if (mPCH!="gcc")
{
args.push( mPCHCreate + header + ".h" );
var symbol = "link" + Md5.encode( PathManager.combine(dir, file + mExt) );
args.push( "-Yl" + symbol );
// 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 + PathManager.combine(dir, file + mExt));
}
else
{
Log.info("", 'Creating PCH directory "$dir"');
PathManager.mkdir(dir);
args.push( "-o" );
args.push(pch_name);
args.push( inGroup.mPrecompiledHeaderDir + "/" + inGroup.mPrecompiledHeader + ".h" );
}
Log.info("Creating " + pch_name + "...", " - Precompile " + pch_name );
var result = ProcessManager.runCommand("", mExe, args);
if (result!=0)
{
var goes = 10;
for(attempt in 0...goes)
{
try {
if (FileSystem.exists(pch_name))
FileSystem.deleteFile(pch_name);
break;
}
catch(error:Dynamic)
{
Log.warn('Error cleaning PCH file $pch_name: $error');
if (attempt<goes-1)
Sys.sleep(0.25);
}
}
Log.error("Could not create PCH");
//throw "Error creating pch: " + result + " - build cancelled";
}
if (mPCH!="gcc")
return PathManager.combine(dir, file + mExt);
return null;
}
public function setPCH(inPCH:String)
{
mPCH = inPCH;
if (mPCH=="gcc")
{
mPCHExt = ".h.gch";
mPCHUse = "";
mPCHFilename = "";
}
}
public function initPrecompile(inDefault:String)
{
if (mPCH==null)
setPCH(inDefault);
return mPCH!=null;
}
}

View File

@ -0,0 +1,97 @@
import sys.FileSystem;
class CopyFile
{
public var name:String;
public var from:String;
public var toolId:String;
public var allowMissing:Bool;
public var overwrite:Overwrite;
public function new(inName:String, inFrom:String, inAlowMissing:Bool, inOverwrite:Overwrite, ?inToolId:String)
{
name = inName;
from = inFrom;
toolId = inToolId;
allowMissing = inAlowMissing;
overwrite = inOverwrite;
}
public function copy(inTo:String)
{
var fromFile = from + "/" + name;
var toFile = inTo + name;
copyFile(fromFile, toFile, allowMissing, overwrite);
}
public static function copyFile(fromFile:String, toFile:String, allowMissing = false, overwrite:Overwrite = Overwrite.ALWAYS, addExePermission=false)
{
if (!FileSystem.exists(fromFile))
{
if (allowMissing)
{
Log.v('Missing "$fromFile" - ignore');
return;
}
Log.error("Error - source file does not exist " + fromFile);
}
try
{
Log.v('Copy "$fromFile" to "$toFile"');
var applyCopy = true;
switch(overwrite)
{
case Overwrite.IF_NEWER:
if(FileSystem.exists(toFile)
&& (FileSystem.stat(fromFile).mtime.getTime() - FileSystem.stat(toFile).mtime.getTime()) <= 0)
{
Log.v('The "$fromFile" is older or it hasn\'t changes. Skip copy');
applyCopy = false;
}
case Overwrite.NEVER:
if(FileSystem.exists(toFile))
{
Log.v('The "$toFile" file exists. Skip copy');
applyCopy = false;
}
case Overwrite.ALWAYS:
default:
Log.v('The Overwrite option "$overwrite" is not supported. ' +
'Possible values: {${Overwrite.ALWAYS}, ${Overwrite.IF_NEWER}, ${Overwrite.NEVER}}. ' +
'Applying "${Overwrite.ALWAYS}" by default');
}
if(applyCopy)
{
sys.io.File.copy( fromFile, toFile );
if (addExePermission)
{
Log.v("chmod 755 " + toFile );
Sys.command("chmod", ["755", toFile]);
}
}
}
catch(e:Dynamic)
{
if (allowMissing)
{
Log.v('Could not copy to "$toFile" - ignore');
return;
}
Log.error('Error $e - could not copy to "$toFile"');
}
}
}
@:enum
abstract Overwrite(String) from String to String
{
var ALWAYS = "always";
var IF_NEWER = "ifNewer";
var NEVER = "never";
}

View File

@ -0,0 +1,159 @@
import sys.FileSystem;
using StringTools;
#if haxe4
import sys.thread.Mutex;
#elseif cpp
import cpp.vm.Mutex;
#else
import neko.vm.Mutex;
#end
class File
{
static var mFileHashes = new Map<String,String>();
public var mName:String;
public var mDir:String;
public var mDependHash:String;
public var mDepends:Array<String>;
public var mCompilerFlags:Array<String>;
public var mGroup:FileGroup;
public var mTags:String;
public var mFilterOut:String;
public var mEmbedName:String;
public var mScramble:String;
static public var mDependMutex = new Mutex();
public function new(inName:String, inGroup:FileGroup)
{
mName = inName;
mDir = "";
if (inGroup.mDir != "" && !PathManager.isAbsolute(mName))
mDir = inGroup.mDir;
if (mDir!="") mDir += "/";
// Do not take copy - use reference so it can be updated
mGroup = inGroup;
mDepends = [];
mCompilerFlags = [];
mEmbedName = null;
mScramble = null;
mTags = null;
}
inline public function getCacheProject() return mGroup.getCacheProject();
public function isNvcc() return mGroup.mNvcc;
public function isResource() return mName.endsWith(".rc");
public function keep(inDefines:Map<String,String>)
{
return mFilterOut==null || !inDefines.exists(mFilterOut);
}
public function getTags()
{
return mTags==null ? mGroup.mTags : mTags;
}
public function setTags(inTags:String)
{
return mTags=inTags;
}
public function computeDependHash(localCache:Map<String,String>)
{
mDependHash = "";
for(depend in mDepends)
mDependHash += getFileHash(depend,localCache);
mDependHash = haxe.crypto.Md5.encode(mDependHash);
}
public function getDependString()
{
return "FILES(" + mDepends.join(",") + ")";
}
public static function getFileHash(inName:String,localCache:Map<String,String>)
{
if (localCache==null)
{
var result = mFileHashes.get(inName);
if (result==null)
{
var content = sys.io.File.getContent(inName);
result = haxe.crypto.Md5.encode(content);
mFileHashes.set(inName,result);
}
return result;
}
else
{
var result = localCache.get(inName);
if (result!=null)
return result;
mDependMutex.acquire();
result = mFileHashes.get(inName);
mDependMutex.release();
if (result==null)
{
var content = sys.io.File.getContent(inName);
result = haxe.crypto.Md5.encode(content);
mDependMutex.acquire();
mFileHashes.set(inName,result);
mDependMutex.release();
}
localCache.set(inName,result);
return result;
}
}
public function isOutOfDate(inObj:String, ?dependDebug:String->Void)
{
if (!FileSystem.exists(inObj))
{
return true;
}
var obj_stamp = FileSystem.stat(inObj).mtime.getTime();
if (mGroup.isOutOfDate(obj_stamp))
{
if (dependDebug!=null)
dependDebug(mName + " - whole group is out of date " + mGroup.getNewestFile() + " " + obj_stamp + " < " + mGroup.mNewest);
return true;
}
var source_name = mDir+mName;
if (!FileSystem.exists(source_name))
{
Log.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)
{
if (dependDebug!=null)
dependDebug(mName + ' - stamped $obj_stamp < $source_stamp');
return true;
}
for(depend in mDepends)
{
if (!FileSystem.exists(depend))
{
Log.error("Could not find dependency \"" + depend + "\" for \"" + mName + "\"");
//throw "Could not find dependency '" + depend + "' for '" + mName + "'";
}
var dependTime = FileSystem.stat(depend).mtime.getTime();
if (dependTime > obj_stamp )
{
if (dependDebug!=null)
dependDebug(mName + ' - depend $obj_stamp < $dependTime');
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,292 @@
import haxe.io.Path;
import sys.FileSystem;
class FileGroup
{
public var mNewest:Float;
public var mNewestFile:String;
public var mCompilerFlags:Array<String>;
public var mMissingDepends:Array<String>;
public var mOptions:Array<String>;
public var mPrecompiledHeader:String;
public var mPrecompiledHeaderDir:String;
public var mFiles:Map<String, File>;
public var mHLSLs:Array<HLSL>;
public var mDir:String;
public var mId:String;
public var mConfig:String;
public var mCacheDepends:Array<String>;
public var mDependHash:String;
public var mAsLibrary:Bool;
public var mAddTwice:Bool;
public var mSetImportDir:Bool;
public var mUseCache:Bool;
public var mRespectTimestamp:Bool;
public var mCacheProject:String;
public var mTags:String;
public var mNvcc:Bool;
public var mObjPrefix:String;
public function new(inDir:String,inId:String,inSetImportDir = false)
{
mId = inId;
replace(inDir, inSetImportDir);
}
public function toString() return 'FileGroup($mId)';
public function replace(inDir:String,inSetImportDir)
{
mNewest = 0;
mFiles = new Map<String, File>();
mCompilerFlags = [];
mPrecompiledHeader = "";
mCacheDepends = [];
mMissingDepends = [];
mOptions = [];
mHLSLs = [];
mDir = inDir;
mConfig = "";
mAsLibrary = false;
mAddTwice = false;
mSetImportDir = inSetImportDir;
mUseCache = false;
mRespectTimestamp = false;
mCacheProject = "";
mNvcc = false;
mTags = "haxe,static";
mObjPrefix = "";
return this;
}
public function find(name:String)
{
return mFiles.get(name);
}
public function addFile(file:File)
{
mFiles.set(file.mName, file);
}
public function hasFiles():Bool {
return Lambda.exists(mFiles, function(file:File) { return true; } );
}
public function filter(defines:Map<String,String>)
{
var newFiles = new Map<String, File>();
for(file in mFiles)
if (file.keep(defines))
newFiles.set(file.mName, file);
mFiles = newFiles;
}
public function getTags()
{
return mTags;
}
public function addTag(inTag:String)
{
if (inTag!=null && inTag!="")
{
var have = mTags.split(",");
if (have.indexOf(inTag)<0)
{
have.push(inTag);
mTags = have.join(",");
}
}
}
public function isPrecompiled() return mPrecompiledHeader!="";
public function dontPrecompile()
{
mPrecompiledHeader = "";
}
public function addCompilerFlag(inFlag:String)
{
mCompilerFlags.push(inFlag);
}
public function getCacheProject()
{
if (mCacheProject=="")
mCacheProject = mId;
return mCacheProject;
}
public function addDepend(inFile:String, inDateOnly:Bool)
{
if (mSetImportDir && !Path.isAbsolute(inFile) )
inFile = PathManager.combine(mDir, inFile);
if (!FileSystem.exists(inFile))
{
mMissingDepends.push(inFile);
return;
}
var stamp = FileSystem.stat(inFile).mtime.getTime();
if (stamp>mNewest)
{
mNewest = stamp;
mNewestFile = inFile;
}
if (!inDateOnly)
mCacheDepends.push(inFile);
}
public function getNewestFile()
{
return '$mId($mNewestFile)';
}
public function addDependFiles(inGroup:FileGroup)
{
if (inGroup.mNewest>mNewest)
{
mNewestFile = inGroup.getNewestFile();
mNewest = inGroup.mNewest;
}
for(depend in inGroup.mCacheDepends)
mCacheDepends.push(depend);
for(missing in inGroup.mMissingDepends)
mMissingDepends.push(missing);
}
public function addHLSL(inFile:String,inProfile:String,inVariable:String,inTarget:String)
{
addDepend(inFile, true );
mHLSLs.push( new HLSL(inFile,inProfile,inVariable,inTarget) );
}
public function addOptions(inFile:String)
{
mOptions.push(inFile);
}
public function checkDependsExist()
{
if (mMissingDepends.length>0)
{
Log.error("Could not find dependencies for " + mId + " : [ " + mMissingDepends.join (", ") + " ]");
//throw "Could not find dependencies: " + mMissingDepends.join(",");
}
}
public function filterOptions(contents:String)
{
// Old-style
if (contents.substr(0,1)==" ")
return contents;
var result = new Array<String>();
for(def in contents.split("\n"))
{
var name = def.split("=")[0];//.toLowerCase();
if (name.indexOf("hxcpp_link")>=0)
{
// Only effects linking, not compiling
}
else if (name=="hxcpp_verbose" || name=="hxcpp_silent" || name=="hxcpp_quiet" || name=="hxcpp_times" || name=="hxcpp_neko_buildtool" || name=="hxcpp_link_no_tool_depends" )
{
// Does not affect build
}
else if (name.indexOf("hxcpp")>=0 || name=="scriptable" || name.indexOf("dll")>=0 || name=="no_console" ||
name.substr(0,8)=="android-" || name.substr(0,4)=="ndkv" || name=="toolchain" || name=="platform" ||
name=="toolchain_version" || name=="android_ndk_root" )
result.push(def);
}
return result.join("\n");
}
public function checkOptions(inObjDir:String)
{
var changed = false;
for(option in mOptions)
{
if (!FileSystem.exists(option))
{
mMissingDepends.push(option);
}
else
{
var contents = filterOptions(sys.io.File.getContent(option));
var dest = inObjDir + "/" + Path.withoutDirectory(option);
var skip = false;
if (FileSystem.exists(dest))
{
var dest_content = filterOptions(sys.io.File.getContent(dest));
if (dest_content==contents)
skip = true;
}
if (!skip)
{
PathManager.mkdir(inObjDir);
var stream = sys.io.File.write(dest,true);
stream.writeString(contents);
stream.close();
changed = true;
}
addDepend(dest,true);
}
}
return changed;
}
public function getPchDir(inObjDir:String)
{
var result = inObjDir + "/__pch/" + mId ;
PathManager.mkdir(result);
return result;
}
public function getPchName()
{
return Path.withoutDirectory(mPrecompiledHeader);
}
public function isOutOfDate(inStamp:Float)
{
return inStamp<mNewest;
}
public function isCached() return CompileCache.hasCache && mUseCache;
public function preBuild()
{
for(hlsl in mHLSLs)
hlsl.build();
if (CompileCache.hasCache && mUseCache)
{
mDependHash = "";
for(depend in mCacheDepends)
mDependHash += File.getFileHash(depend,null);
mDependHash = haxe.crypto.Md5.encode(mDependHash);
}
}
public function getDependString()
{
return "Group(" + mCacheDepends.join(",") + ")";
}
public function setPrecompiled(inFile:String, inDir:String)
{
mPrecompiledHeader = inFile;
mPrecompiledHeaderDir = inDir;
}
}

View File

@ -0,0 +1,42 @@
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)))
{
PathManager.mkdir(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 = ProcessManager.runCommand("", exe, args);
if (result!=0)
{
Log.error("Could not compile shader \"" + file + "\"");
//throw "Error : Could not compile shader " + file + " - build cancelled";
}
}
}
}

View File

@ -0,0 +1,324 @@
import haxe.io.Path;
import sys.FileSystem;
import haxe.crypto.Md5;
using StringTools;
class Linker
{
public var mExe:String;
public var mFlags:Array<String>;
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 mFromFileNeedsQuotes:Bool;
public var mLibs:Array<String>;
public var mExpandArchives:Bool;
public var mRecreate:Bool;
public var mLastOutName:String;
public var mAddLibPath:String;
public function new(inExe:String)
{
mFlags = [];
mOutFlag = "-o";
mAddLibPath = "-L";
mExe = inExe;
mNamePrefix = "";
mLibDir = "";
mRanLib = "";
mExpandArchives = false;
// Default to on...
mFromFile = "@";
mFromFileNeedsQuotes = true;
mLibs = [];
mRecreate = false;
}
function isOutOfDate(inName:String, inObjs:Array<String>)
{
if (!FileSystem.exists(inName))
return true;
var stamp = FileSystem.stat(inName).mtime.getTime();
for(obj in inObjs)
{
if (!FileSystem.exists(obj))
{
Log.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;
}
return false;
}
function getSimpleFilename(inTarget:Target)
{
var ext = inTarget.getExt(mExt);
// Remove arch from ext ...
var idx = ext.indexOf('.');
if (idx>0)
ext = ext.substr(idx);
return mNamePrefix + inTarget.mOutput + ext;
}
public function getUnstrippedFilename(inObjDir, inTarget:Target)
{
if (inTarget.mFullUnstrippedName!=null)
{
PathManager.mkdir( inTarget.mFullUnstrippedName, true );
return inTarget.mFullUnstrippedName;
}
return inObjDir + "/" + getSimpleFilename(inTarget);
}
public function link(inTarget:Target,inObjs:Array<String>,inCompiler:Compiler,extraDeps:Array<String> )
{
var ext = inTarget.getExt(mExt);
var file_name = mNamePrefix + inTarget.mOutput + ext;
var tmpDir = inCompiler.mObjDir;
try
{
PathManager.mkdir(inTarget.mOutputDir);
}
catch (e:Dynamic)
{
Log.error("Unable to create output directory \"" + inTarget.mOutputDir + "\"");
//throw "Unable to create output directory " + inTarget.mOutputDir;
}
var out_name = Path.normalize(PathManager.combine( inTarget.mBuildDir, inTarget.mOutputDir + file_name));
var hashFile = out_name + ".hash";
if (inTarget.mFullOutputName!=null)
{
PathManager.mkdir( inTarget.mFullOutputName, true );
out_name = inTarget.mFullOutputName;
}
mLastOutName = out_name;
var lastLib = "";
var libs = new Array<String>();
for(l in inTarget.mAutoLibs)
if (l!=lastLib)
{
libs.push(l);
lastLib = l;
}
for(l in inTarget.mLibs)
if (l!=lastLib)
{
libs.push(l);
lastLib = l;
}
for(l in mLibs)
if (l!=lastLib)
{
libs.push(l);
lastLib = l;
}
var v18Added = false;
var isOutOfDateLibs = false;
var md5 = Md5.encode(inObjs.join(";"));
if (!FileSystem.exists(hashFile) || sys.io.File.getContent(hashFile)!=md5)
isOutOfDateLibs = true;
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))
{
Log.info("", " - \x1b[1mUsing current compiler library:\x1b[0m " + current);
libs[i]=current;
}
else
{
var v18 = parts[0] + "-18" + parts[1];
if (FileSystem.exists(v18))
{
Log.info("", " - \x1b[1mUsing MSVC18 compatible library:\x1b[0m " + v18);
libs[i]=v18;
if (!v18Added)
{
v18Added=true;
libs.push( BuildTool.HXCPP + "/lib/Windows/libmsvccompat-18.lib");
}
}
else
{
Log.error("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 (BuildTool.isMingw())
{
var libMatch = ~/^([a-zA-Z0-9_]+).lib$/;
if (libMatch.match(libs[i]))
libs[i] = "-l" + libMatch.matched(1);
}
}
if (isOutOfDateLibs || isOutOfDate(out_name,inObjs) || isOutOfDate(out_name,inTarget.mDepends) || isOutOfDate(out_name,extraDeps) )
{
var args = new Array<String>();
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!="")
{
PathManager.mkdir(mLibDir);
args.push(out + mLibDir + "/" + file_name);
}
else
{
if (mRecreate && FileSystem.exists(out_name))
{
Log.info("\x1b[1mClean: \x1b[0m" + 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<String>();
for(lib in libs)
{
if (isArchive.match(lib))
{
var libName = Path.withoutDirectory(lib);
var libObjs = ProcessManager.readStdout(mExe, ["t", lib ]);
var objDir = tmpDir + "/" + libName + ".unpack";
PathManager.mkdir(objDir);
ProcessManager.runCommand (objDir, mExe, ["x", lib], true, true, false, " - Unpack : " + lib);
for(obj in libObjs)
objs.push( objDir+"/"+obj );
}
else
libArgs.push(lib);
}
libs = libArgs;
}
var here = Path.normalize(Sys.getCwd()) + "/";
var hereLen = here.length;
for(oid in 0...objs.length)
{
var obj = Path.normalize( objs[oid] );
if (obj.startsWith(here))
objs[oid] = obj.substr(hereLen);
}
// Place list of obj files in a file called "all_objs"
if (mFromFile!="")
{
PathManager.mkdir(tmpDir);
var fname = tmpDir + "/all_objs";
var local = Path.normalize(fname);
if (local.startsWith(here))
fname = local.substr(hereLen);
var fout = sys.io.File.write(fname,false);
if (mFromFileNeedsQuotes)
{
for(obj in objs)
fout.writeString('"' + obj + '"\n');
}
else
{
for(obj in objs)
fout.writeString(obj + '\n');
}
fout.close();
var parts = mFromFile.split(" ");
var last = parts.pop();
args = args.concat(parts);
args.push(last + fname );
}
else
args = args.concat(objs);
for(libpath in inTarget.mLibPaths)
{
var path = Path.normalize(libpath);
if (path.startsWith(here))
path = path.substr(hereLen);
args.push( mAddLibPath + path );
}
args = args.concat(libs);
var result = ProcessManager.runCommand("", mExe, args, true, true, false,
"\x1b[1mLink: \x1b[0m" + out_name);
if (result!=0)
{
Tools.exit(result);
//throw "Error : " + result + " - build cancelled";
}
if (mRanLib!="")
{
args = [out_name];
var result = ProcessManager.runCommand("", mRanLib, args, true, true, false, "\x1b[1mRanlib:\x1b[0m " + out_name);
if (result!=0)
{
Tools.exit(result);
//throw "Error : " + result + " - build cancelled";
}
}
if (mLibDir!="")
{
sys.io.File.copy( mLibDir+"/"+file_name, out_name );
FileSystem.deleteFile( mLibDir+"/"+file_name );
}
sys.io.File.saveContent(hashFile,md5);
return out_name;
}
return "";
}
}

View File

@ -0,0 +1,189 @@
import haxe.io.Bytes;
import sys.io.Process;
#if haxe4
import sys.thread.Mutex;
#elseif neko
import neko.vm.Mutex;
#else
import cpp.vm.Mutex;
#end
#if neko
import neko.Lib;
#else
import cpp.Lib;
#end
class Log
{
public static var mute:Bool= false;
public static var quiet:Bool = false;
public static var verbose:Bool = false;
public static var colorSupported:Null<Bool> = null;
private static var sentWarnings = new Map<String,Bool>();
public static var printMutex:Mutex;
public static inline var RED = "\x1b[31m";
public static inline var YELLOW = "\x1b[33m";
public static inline var WHITE = "\x1b[37m";
public static inline var NORMAL = "\x1b[0m";
public static inline var BOLD = "\x1b[1m";
public static inline var ITALIC = "\x1b[3m";
public static function initMultiThreaded()
{
if (printMutex==null)
printMutex = new Mutex();
}
public static function e(message:String):Void
{
error(message);
}
public static function error(message:String, verboseMessage:String = "", e:Dynamic = null, terminate:Bool = true):Void
{
var output;
if (verbose && verboseMessage != "")
{
output = "\x1b[31;1mError:\x1b[0m\x1b[1m " + verboseMessage + "\x1b[0m\n";
}
else
{
if (message=="")
output = "\x1b[31;1mError\x1b[0m\n";
else
output = "\x1b[31;1mError:\x1b[0m \x1b[1m" + message + "\x1b[0m\n";
}
if (printMutex!=null)
printMutex.acquire();
Sys.stderr().write(Bytes.ofString(stripColor(output)));
if (printMutex!=null)
printMutex.release();
if ((verbose || !terminate) && e != null)
Lib.rethrow(e);
if (terminate)
Tools.exit(1);
}
public static function info(message:String, verboseMessage:String = ""):Void
{
if (!mute)
{
if (printMutex!=null)
printMutex.acquire();
if (verbose && verboseMessage != "")
{
println(verboseMessage);
}
else if (message != "")
{
println(message);
}
if (printMutex!=null)
printMutex.release();
}
}
inline public static function v(verboseMessage:String):Void
{
Log.info("",verboseMessage);
}
public static function lock():Void
{
if (printMutex!=null)
printMutex.acquire();
}
public static function unlock():Void
{
if (printMutex!=null)
printMutex.release();
}
public static function print(message:String):Void
{
if (printMutex!=null)
printMutex.acquire();
Sys.print(stripColor(message));
if (printMutex!=null)
printMutex.release();
}
public static function println(message:String):Void
{
if (printMutex!=null)
printMutex.acquire();
Sys.println(stripColor(message));
if (printMutex!=null)
printMutex.release();
}
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("TERM") == "xterm" || Sys.getEnv("ANSICON") != null);
}
}
if (colorSupported)
{
return output;
}
else
{
var colorCodes:EReg = ~/\x1b\[[^m]+m/g;
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);
if (printMutex!=null)
printMutex.acquire();
println(output);
if (printMutex!=null)
printMutex.release();
}
}
}

View File

@ -0,0 +1,32 @@
class Manifester
{
public var mExe:String;
public var mFlags:Array<String>;
public var mOutPre:String;
public var mOutPost:String;
public function new(inExe:String)
{
mFlags = [];
mExe = inExe;
mOutPre = "";
mOutPost = "";
}
public function add(binName:String,manifestName:String, isExe:Bool)
{
var args = new Array<String>();
args = args.concat(mFlags);
//only windows for now
mOutPost = isExe ? ";1" : ";2";
var result = ProcessManager.runCommand("", mExe, args.concat([manifestName,mOutPre + binName + mOutPost]) );
if (result!=0)
{
Tools.exit(result);
//throw "Error : " + result + " - build cancelled";
}
}
}

View File

@ -0,0 +1,365 @@
import sys.FileSystem;
class PathManager
{
private static var directoryCache = new Map<String,Bool>();
private static var haxelibPaths = new Map<String,String>();
public static function combine(firstPath:String, secondPath:String):String
{
if (firstPath == null || firstPath == "")
{
return secondPath;
}
else if (secondPath != null && secondPath != "" && 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 = true, clearCache:Bool = false):String
{
var name = haxelib;
if (version != "")
{
name += ":" + version;
}
if (clearCache)
{
haxelibPaths.remove(name);
}
if (!haxelibPaths.exists(name))
{
var cache = Log.verbose;
Log.verbose = false;
var output = "";
try
{
output = ProcessManager.runProcess(Sys.getEnv ("HAXEPATH"), "haxelib", [ "path", name ], true, false);
}
catch (e:Dynamic) {}
Log.verbose = cache;
var lines = output.split("\n");
var result = "";
var re = new EReg("^-D " + haxelib + "(=.*)?$", ""); //matches "-D hxcpp=3.1.0" or "-D hxcpp", but not "-D hxcpp-extras"
for (i in 1...lines.length)
{
if (re.match(StringTools.trim(lines[i])))
{
result = StringTools.trim(lines[i - 1]);
}
}
if (result == "")
{
for (line in lines)
{
if (line != "" && line.substr(0, 1) != "-")
{
try
{
if (FileSystem.exists(line))
{
result = line;
}
}
catch (e:Dynamic) {}
}
}
}
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";
}
Log.error ("haxelib \"" + haxelib + "\" does not have an \"ndll/" + directoryName + "\" directory");
}
else
{
if (version != "")
{
Log.error("Could not find haxelib \"" + haxelib + "\" version \"" + version + "\", does it need to be installed?");
}
else
{
Log.error("Could not find haxelib \"" + haxelib + "\", does it need to be installed?");
}
}
}
}
if ( result!="" )
{
var rootPath = result;
var depth = 0;
while( FileSystem.exists(rootPath) && FileSystem.isDirectory(rootPath) && depth<10 )
{
if (FileSystem.exists(rootPath + "/haxelib.json"))
{
result = rootPath;
break;
}
depth++;
rootPath = haxe.io.Path.directory(rootPath);
}
}
haxelibPaths.set(name,result);
}
return haxelibPaths.get(name);
}
public static function isAbsolute(path:String):Bool
{
if (BuildTool.isWindows)
{
if (path != null && path.length > 2 && path.charAt(1) == ":" && (path.charAt(2) == "\\" || path.charAt(2) == "/"))
{
return true;
}
}
else
{
if (StringTools.startsWith(path, "/") || StringTools.startsWith(path, "\\"))
{
return true;
}
}
return false;
}
public static function mkdir(directory:String, skipFilePart=false):Void
{
directory = StringTools.replace(directory, "\\", "/");
var total = "";
if (directory.substr(0, 1) == "/")
{
total = "/";
}
var parts = directory.split("/");
if (skipFilePart && parts.length>0)
parts.pop();
if (parts.length > 0 && parts[0].indexOf(":") > -1)
{
total = 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))
{
Log.info("", " - \x1b[1mCreating directory:\x1b[0m " + total);
FileSystem.createDirectory(total);
}
}
}
}
}
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) {}
}
Log.info("", " - \x1b[1mRemoving directory:\x1b[0m " + directory);
try
{
FileSystem.deleteDirectory(directory);
}
catch (e:Dynamic) {}
}
}
static public function removeFile(file:String)
{
if (FileSystem.exists(file))
{
Log.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<String,Bool>();
}
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;
}
public static function clean(path:String)
{
var result = new Array<String>();
for(part in standardize(path).split("/"))
{
if (part!=".")
{
if (part=="..")
{
if (result.length==0)
Log.error("Bad relative path " + path);
result.pop();
}
else
result.push(part);
}
}
return result.join("/");
}
}

View File

@ -0,0 +1,122 @@
import haxe.io.Path;
import sys.FileSystem;
class Prelinker
{
public var mExe:String;
public var mFlags:Array<String>;
public var mOutFlag:String;
public var mFromFile:String;
public var mExpandArchives:Bool;
public function new(inExe:String)
{
mFlags = [];
mOutFlag = "-o";
mExe = inExe;
mExpandArchives = false;
// Default to on...
mFromFile = "@";
}
function isOutOfDate(inName:String, inObjs:Array<String>)
{
if (!FileSystem.exists(inName))
return true;
var stamp = FileSystem.stat(inName).mtime.getTime();
for(obj in inObjs)
{
if (!FileSystem.exists(obj))
{
Log.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;
}
return false;
}
public function prelink(inTarget:Target,inObjs:Array<String>,inCompiler:Compiler)
{
var file_name = "prelink.o";
try
{
PathManager.mkdir(inTarget.mOutputDir);
}
catch (e:Dynamic)
{
Log.error("Unable to create output directory \"" + inTarget.mOutputDir + "\"");
//throw "Unable to create output directory " + inTarget.mOutputDir;
}
var out_name = inCompiler.mObjDir + "/" + file_name;
if (isOutOfDate(out_name,inObjs) || isOutOfDate(out_name,inTarget.mDepends))
{
var args = new Array<String>();
var out = mOutFlag;
if (out.substr(-1)==" ")
{
args.push(out.substr(0,out.length-1));
out = "";
}
args.push(out + out_name);
//args = args.concat(mFlags).concat(inTarget.mFlags);
args = args.concat(mFlags);
var objs = inObjs.copy();
/*if (mExpandArchives)
{
var isArchive = ~/\.a$/;
var libArgs = new Array<String>();
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;
PathManager.mkdir(objDir);
ProcessManager.runCommand (objDir, mExe, ["x", lib]);
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 = ProcessManager.runCommand("", mExe, args);
if (result!=0)
{
Tools.exit(result);
//throw "Error : " + result + " - build cancelled";
}
return out_name;
}
return "";
}
}

View File

@ -0,0 +1,509 @@
import haxe.io.BytesOutput;
import haxe.io.Eof;
import haxe.io.Path;
import sys.io.Process;
import sys.FileSystem;
#if haxe4
import sys.thread.Thread;
#elseif neko
import neko.vm.Thread;
#else
import cpp.vm.Thread;
#end
class ProcessManager
{
static function dup(inArgs:Array<String>)
{
if (inArgs==null)
return [];
return inArgs.copy();
}
// Command may be a pseudo command, like "xcrun --sdk abc", or 'python "some script"'
// Here we split the first word into command and move the rest into args, being careful
// to preserve quoted words
static function combineCommand(command:String, args:Array<String>)
{
var parts = new Array<String>();
var c = command;
var quoted = ~/^\s*"([^"]+)"(.*)/;
var word = ~/^\s*(\S+)(.*)/;
while(c.length>0)
{
if (quoted.match(c))
{
parts.push( quoted.matched(1) );
c = quoted.matched(2);
}
else if (word.match(c))
{
parts.push( word.matched(1) );
c = word.matched(2);
}
else
break;
}
if (parts.length>1)
{
command = parts.shift();
while(parts.length>0)
args.unshift( parts.pop() );
}
return PathManager.escape(command);
}
private static function formatMessage(command:String, args:Array<String>, colorize:Bool = true):String
{
var message = "";
if (colorize)
{
message = "\x1b[33;1m" + command + "\x1b[0m";
}
else
{
message = command;
}
for (arg in args)
{
if (colorize)
{
var ext = Path.extension(arg);
if (ext == "cpp" || ext == "c" || ext == "h" || ext == "hpp" || ext == "m" || ext == "mm")
{
var split = arg.split ("/");
if (split.length > 1)
{
arg = "\x1b[33m" + split.slice(0, split.length - 1).join("/") + "/\x1b[33;1m" + split[split.length - 1] + "\x1b[0m";
}
else
{
arg = "\x1b[1m" + arg + "\x1b[0m";
}
}
else if (StringTools.startsWith(arg, "-D"))
{
arg = "\x1b[1m" + arg + "\x1b[0m";
}
else
{
arg = "\x1b[0m" + arg + "\x1b[0m";
}
}
if (arg.indexOf(" ") > -1)
{
message += " \"" + arg + "\"";
}
else
{
message += " " + arg;
}
}
return message;
}
public static function runCommand(path:String, command:String, args:Array<String>, print:Bool = true, safeExecute:Bool = true, ignoreErrors:Bool = false,?inText:String):Int
{
args = dup(args);
command = combineCommand(command,args);
if (print && !Log.verbose && !Log.quiet)
{
Log.info(inText==null ? "" : inText,formatMessage(command, args));
}
if (safeExecute)
{
try
{
if (path != null && path != "" && !FileSystem.exists(FileSystem.fullPath(path)) && !FileSystem.exists(FileSystem.fullPath(new Path(path).dir)))
{
Log.error("The specified target path \"" + path + "\" does not exist");
return 1;
}
return _runCommand(path, command, args, inText);
}
catch (e:Dynamic)
{
if (!ignoreErrors)
{
//var text = formatMessage(command, args);
//Log.error("Error while running command\n" + text , e);
if (Log.verbose)
{
Log.error ("", e);
}
return 1;
}
return 0;
}
}
else
{
return _runCommand(path, command, args, inText);
}
}
public static function readStderr(inCommand:String,inArgs:Array<String>)
{
inArgs = dup(inArgs);
inCommand = combineCommand(inCommand,inArgs);
var result = new Array<String>();
var proc = new Process(inCommand,inArgs);
try
{
while(true)
{
var out = proc.stderr.readLine();
result.push(out);
}
} catch(e:Dynamic){}
proc.close();
return result;
}
public static function readStdout(command:String,args:Array<String>)
{
args = dup(args);
command = combineCommand(command,args);
var result = new Array<String>();
var proc = new Process(command,args);
try
{
while(true)
{
var out = proc.stdout.readLine();
result.push(out);
}
} catch(e:Dynamic){}
proc.close();
return result;
}
public static function runProcess(path:String, command:String, args:Array<String>, waitForOutput:Bool = true, print:Bool = true, safeExecute:Bool = true, ignoreErrors:Bool = false, ?text:String):String
{
args = dup(args);
command = combineCommand(command,args);
if (print && !Log.verbose)
{
Log.info(formatMessage(command, args));
}
if (safeExecute)
{
try
{
if (path != null && path != "" && !FileSystem.exists(FileSystem.fullPath(path)) && !FileSystem.exists(FileSystem.fullPath(new Path(path).dir)))
{
Log.error("The specified target path \"" + path + "\" does not exist");
}
return _runProcess(path, command, args, waitForOutput, ignoreErrors, text);
}
catch (e:Dynamic)
{
if (!ignoreErrors)
{
//Log.error("Error while running command\n" + formatMessage(command,args), e);
if (Log.verbose)
{
Log.error ("", e);
}
}
return null;
}
}
else
{
return _runProcess(path, command, args, waitForOutput, ignoreErrors, text);
}
}
public static function runProcessLine(path:String, command:String, args:Array<String>, waitForOutput:Bool = true, print:Bool = true, safeExecute:Bool = true, ignoreErrors:Bool = false):String
{
var result = runProcess(path, command, args, waitForOutput, print, safeExecute, ignoreErrors);
if (result!=null)
return result.split("\n")[0];
return result;
}
private static function _runCommand(path:String, command:String, args:Array<String>, inText:String):Int
{
var oldPath:String = "";
if (path != null && path != "")
{
Log.info("", " - \x1b[1mChanging directory:\x1b[0m " + path + "");
oldPath = Sys.getCwd();
Sys.setCwd(path);
}
if (Log.quiet && inText!=null)
{
Log.info(inText);
}
else
{
var text = inText==null ? "Running command" : inText;
Log.info("", " - \x1b[1m" + text + ":\x1b[0m " + formatMessage(command, args));
}
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 while running command\n" + formatMessage(command, args) + (path != "" ? " [" + path + "]" : ""));
}
return result;
}
private static function _runProcess(path:String, command:String, args:Array<String>, waitForOutput:Bool, ignoreErrors:Bool, inText:String):String
{
var oldPath:String = "";
if (path != null && path != "")
{
Log.info("", " - \x1b[1m - Changing directory:\x1b[0m " + path + "");
oldPath = Sys.getCwd();
Sys.setCwd(path);
}
if ( !Log.quiet)
{
var text = inText==null ? "Running process" : inText;
Log.info("", " - \x1b[1m" + text + ":\x1b[0m " + formatMessage(command, args));
}
else
{
Log.info("",inText);
}
var output = "";
var result = 0;
var process:Process = null;
try
{
process = new Process(command, args);
}
catch(e:Dynamic)
{
if (ignoreErrors)
return null;
Log.error(e+"");
}
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
{
if (error==null || error=="")
error = "Error while running command\n" + formatMessage(command, args);
Log.error(error);
}
return null;
}
//}
}
if (oldPath != "")
{
Sys.setCwd(oldPath);
}
return output;
}
// This function will return 0 on success, or non-zero error code
public static function runProcessThreaded(command:String, args:Array<String>, inText:String = null):Int
{
args = dup(args);
command = combineCommand(command,args);
Log.lock();
// Other thread may have already thrown an error
if (BuildTool.threadExitCode!=0)
{
Log.unlock();
return BuildTool.threadExitCode;
}
if (inText != null)
Log.info(inText,"");
if (!Log.quiet)
Log.v(" - \x1b[1mRunning command:\x1b[0m " + formatMessage(command, args));
Log.unlock();
var output = new Array<String>();
var process:Process = null;
try
{
process = new Process(command, args);
}
catch(e:Dynamic)
{
Log.lock();
if (BuildTool.threadExitCode == 0)
{
Log.info('${Log.RED}${Log.BOLD}$e${Log.NORMAL}\n');
BuildTool.setThreadError(-1);
}
Log.unlock();
return -1;
}
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<String> = 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){ }
if (output.length==1 && ~/^\S+\.(cpp|c|cc)$/.match(output[0]))
{
// Microsoft prints the name of the cpp file for some reason
output = [];
}
var errOut:Array<String> = Thread.readMessage(true);
var code = process.exitCode();
process.close();
if (code != 0)
{
if (BuildTool.threadExitCode == 0)
{
Log.lock();
var message = "";
if (Log.verbose)
{
Log.println("");
message += "Error while running command\n";
message += formatMessage(command,args) + "\n\n";
}
if (output.length > 0)
{
message += output.join("\n") + "\n";
}
if (errOut != null)
{
message += errOut.join("\n") + '${Log.NORMAL}';
}
Log.error(message,"",null,false);
Log.unlock();
}
return code;
}
if (errOut!=null && errOut.length>0)
output = output.concat(errOut);
if (output.length>0)
{
Log.info(output.join("\n"));
}
return 0;
}
}

View File

@ -0,0 +1,140 @@
class Entry
{
public var name:String;
public var entry:Float;
public var total:Float;
public var running:Bool;
public var children:Array<Entry>;
public var current:Entry;
public function new(inName:String)
{
name = inName;
total = 0.0;
children = [];
entry = haxe.Timer.stamp();
running = true;
current = null;
}
public function start()
{
if (running)
trace("===== Restarted " + name);
entry = haxe.Timer.stamp();
running = true;
}
public function stop()
{
if (running)
{
total += haxe.Timer.stamp() - entry;
running = false;
}
}
public function find(inName:String)
{
for(c in children)
if (c.name==inName)
{
current = c;
current.start();
return current;
}
var result = new Entry(inName);
children.push(result);
current = result;
return result;
}
static function timeString(t:Float)
{
return Std.int(t*1000.0) + "ms";
}
public function dump(indent = "")
{
if (running)
trace("========== running?");
Sys.println(indent + name + " : " + timeString(total) );
for(c in children)
c.dump( indent + " " );
}
}
class Profile
{
static var valid = false;
static var t0:Float;
static var root:Entry;
static var current:Entry;
static var currentParent:Entry;
static var stack:Array<Entry>;
public static function start()
{
t0 = now();
root = new Entry("Program");
currentParent = root;
current = null;
stack = [];
}
public static function enable()
{
valid = true;
Tools.addOnExitHook( dump );
}
public static function setEntry(inName:String)
{
if (!valid) return;
if (current!=null)
current.stop();
current = currentParent.find(inName);
}
public static function push(inName:String)
{
if (!valid) return;
stack.push(currentParent);
currentParent = current;
current = currentParent.find(inName);
}
public static function pop()
{
if (!valid) return;
current.stop();
currentParent = stack.pop();
current = currentParent.current;
}
static function dump(inExitCode:Int)
{
if (inExitCode==0)
{
if (current!=null)
current.stop();
if (currentParent!=null)
currentParent.stop();
for(s in stack)
s.stop();
root.dump();
}
}
inline static function now() return haxe.Timer.stamp();
}

View File

@ -0,0 +1,748 @@
import haxe.io.Eof;
import sys.io.Process;
import sys.FileSystem;
import BuildTool;
class Setup
{
static function findAndroidNdkRoot(defines: Map<String,String>, inBaseVersion:Int):String
{
var bestVersion = 0.0;
var result:String = null;
var ndkDir = defines.get("ANDROID_NDK_DIR");
if (ndkDir!=null)
{
Log.v("Looking in ANDROID_NDK_DIR " + ndkDir);
}
else
{
Log.v("ANDROID_NDK_DIR not set");
if (BuildTool.isMac)
{
var lib = defines.get("HOME") + "/Library/Android/sdk/ndk";
if (FileSystem.exists(lib))
{
Log.v("trying default " + lib);
ndkDir = lib;
}
}
}
if (ndkDir!=null)
{
ndkDir = ndkDir.split("\\").join("/");
var files:Array<String> = null;
var checkFiles:Bool = true;
try
{
files = FileSystem.readDirectory(ndkDir);
}
catch (e:Dynamic)
{
Log.warn('ANDROID_NDK_DIR "$ndkDir" does not point to a valid directory');
checkFiles=false;
}
if (checkFiles)
for (file in files)
{
file = file.split("\\").join("/");
var version = getNdkVersion(ndkDir + "/" + file);
if (inBaseVersion==0 || Std.int(version)==inBaseVersion)
{
if (version>bestVersion)
{
bestVersion = version;
result = ndkDir + "/" + file;
}
}
}
}
Log.v("Looking in ANDROID_SDK/ndk-bundle");
if (defines.exists("ANDROID_SDK"))
{
Log.v("checks default ndk-bundle in android sdk");
var ndkBundle = defines.get("ANDROID_SDK")+"/ndk-bundle";
ndkBundle = ndkBundle.split("\\").join("/");
var version = getNdkVersion(ndkBundle);
if (version>bestVersion && (inBaseVersion==0 || inBaseVersion==Std.int(version)) )
{
Log.v("Using default ndk-bundle in android sdk");
result = ndkBundle;
}
}
return result;
}
static public function getNdkVersion(inDirName:String):Float
{
Log.v("Try to get version from source.properties");
var src = toPath(inDirName+"/source.properties");
if (sys.FileSystem.exists(src))
{
var fin = sys.io.File.read(src, false);
try
{
while (true)
{
var str = fin.readLine();
var split = str.split ("=");
var name = StringTools.trim(split[0]);
if (name == "Pkg.Revision")
{
var revision = StringTools.trim(split[1]);
var split2 = revision.split( "." );
var result:Float = 1.0 * Std.parseInt(split2[0]) + 0.001 * Std.parseInt(split2[1]);
if (result>=8)
{
Log.v('Deduced NDK version '+result+' from "$inDirName"/source.properties');
fin.close();
return result;
}
}
}
}
catch (e:haxe.io.Eof)
{
Log.v('Could not deduce NDK version from "$inDirName"/source.properties');
}
fin.close();
}
var dir = inDirName.split("\\").join("/");
Log.v('Try to get version from directory name "$dir"');
var extract_version = ~/\/?(android-ndk-)?r(\d+)([a-z]?)$/;
if (extract_version.match(dir))
{
var major:Int = Std.parseInt( extract_version.matched(2) );
var result:Float = 1.0 * major;
var minor = extract_version.matched(3);
if (minor!=null && minor.length>0)
result += 0.001 * (minor.toLowerCase().charCodeAt(0)-'a'.code);
return result;
}
Log.v('Could not deduce NDK version from "$inDirName" - assuming 8');
return 8;
}
public static function initHXCPPConfig(ioDefines:Hash<String>)
{
var env = Sys.environment();
// If the user has set it themselves, they mush know what they are doing...
if (env.exists("HXCPP_CONFIG"))
return;
var home = "";
if (env.exists("HOME"))
home = env.get("HOME");
else if (env.exists("USERPROFILE"))
home = env.get("USERPROFILE");
else
{
Log.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;
}
ioDefines.set("HXCPP_HOME", home);
var config = toPath(home+"/.hxcpp_config.xml");
ioDefines.set("HXCPP_CONFIG",config);
if (BuildTool.HXCPP!="")
{
var src = toPath(BuildTool.HXCPP + "/toolchain/example.hxcpp_config.xml");
if (!sys.FileSystem.exists(config))
{
try
{
Log.info("", "Copying HXCPP config \"" + src + "\" to \"" + config + "\"");
sys.io.File.copy(src,config);
}
catch(e:Dynamic)
{
Log.warn("Could not create HXCPP config \"" + config + "\"");
//Sys.println("Warning : could not create config: " + config );
}
}
}
}
public static function setupMingw(ioDefines:Hash<String>)
{
// Setup MINGW_ROOT or fail
if (!ioDefines.exists("MINGW_ROOT"))
{
var haxelib = PathManager.getHaxelib("minimingw","",false);
if (haxelib!=null && haxelib!="")
{
ioDefines.set("MINGW_ROOT", haxelib);
Log.v('Using haxelib version of MinGW, $haxelib');
return;
}
var guesses = ["c:/MinGW"];
for (guess in guesses)
{
if (FileSystem.exists(guess))
{
ioDefines.set("MINGW_ROOT", guess);
Log.v('Using default version of MinGW, $guess');
return;
}
}
if (ioDefines.exists("mingw"))
{
//when mingw is explicitly indicated but not properly configured, this log will be shown
Log.error('Could not guess MINGW_ROOT (tried $guesses) - please set explicitly');
}
else
{
//when both mingw and MSVC is not properly configured, this log will be shown
Log.error('Could not setup any C++ compiler, please install or reinstall a valid C++ compiler');
}
}
}
public static function setupEmscripten(ioDefines:Hash<String>)
{
// Setup EMSCRIPTEN_SDK if possible - else assume developer has it in path
if (!ioDefines.exists("EMSCRIPTEN_SDK"))
{
var home = ioDefines.get("HXCPP_HOME");
var file = home + "/.emscripten";
if (FileSystem.exists(file))
{
var content = sys.io.File.getContent(file);
content = content.split("\r").join("");
var value = ~/^(\w*)\s*=\s*'(.*)'/;
for (line in content.split("\n"))
{
if (value.match(line))
{
var name = value.matched(1);
var val= value.matched(2);
if (name=="EMSCRIPTEN_ROOT")
{
ioDefines.set("EMSCRIPTEN_SDK", val);
}
if (name=="PYTHON")
ioDefines.set("EMSCRIPTEN_PYTHON", val);
if (name=="NODE_JS")
ioDefines.set("EMSCRIPTEN_NODE_JS", val);
}
}
}
}
}
public static function isRaspberryPi()
{
var modelFile = '/sys/firmware/devicetree/base/model';
if( !FileSystem.exists( modelFile ) )
return false;
try {
var model = sys.io.File.getContent( modelFile );
return ~/Raspberry/.match( model );
} catch(e:Dynamic) {
trace( e );
}
return false;
}
static public function startPdbServer()
{
var oldPath = Sys.getCwd();
try
{
// Run it in hxcpp directory so it does not lock the build directory after build finishes
Sys.setCwd(BuildTool.HXCPP);
var proc = new Process("mspdbsrv.exe",["-start"]);
Tools.addOnExitHook(function(_) {
proc.kill();
});
}
catch(e:Dynamic)
{
Log.v("Could not start mspdbsrv:" + e);
}
Sys.setCwd(oldPath);
}
public static function setup(inWhat:String,ioDefines:Map<String,String>)
{
if (ioDefines.exists("HXCPP_CLEAN_ONLY"))
return;
Profile.push("setup " + inWhat);
if (inWhat=="androidNdk")
{
setupAndroidNdk(ioDefines);
}
else if (inWhat=="blackberry")
{
setupBlackBerryNativeSDK(ioDefines);
}
else if (inWhat=="msvc")
{
setupMSVC(ioDefines, ioDefines.exists("HXCPP_M64"), ioDefines.exists("HXCPP_ARM64"), ioDefines.exists("winrt"));
}
else if (inWhat=="pdbserver")
{
startPdbServer();
}
else if (inWhat=="mingw")
{
setupMingw(ioDefines);
}
else if (inWhat=="emscripten")
{
setupEmscripten(ioDefines);
}
else if (inWhat=="nvcc")
{
BuildTool.setupNvcc();
}
else
{
Log.error('Unknown setup feature "$inWhat"');
//throw 'Unknown setup feature $inWhat';
}
Profile.pop();
}
static public function setupAndroidNdk(defines:Map<String,String>)
{
var root:String = null;
if (Log.verbose) Log.println("");
var ndkVersion = 0;
for (i in 6...20)
{
if (defines.exists("NDKV" + i))
{
ndkVersion = i;
Log.info("", "\x1b[33;1mRequested Android NDK r" + i + "\x1b[0m");
break;
}
}
if (!defines.exists("ANDROID_NDK_ROOT") || ndkVersion!=0)
{
root = Setup.findAndroidNdkRoot( defines, ndkVersion );
if (root==null)
{
var ndkDir = defines.exists("ANDROID_NDK_DIR") ? defines.get("ANDROID_NDK_DIR") : "not set";
if (ndkVersion!=0)
Log.error('ANDROID_NDK_DIR ["$ndkDir"] or ndk-bundle does not contain requested NDK $ndkVersion');
else
Log.error('ANDROID_NDK_DIR ["$ndkDir"] or ndk-bundle does not contain a matching NDK');
}
else
{
Sys.putEnv("ANDROID_NDK_ROOT", root);
defines.set("ANDROID_NDK_ROOT", root);
}
}
else
{
root = defines.get("ANDROID_NDK_ROOT");
Log.info("", "\x1b[33;1mUsing Android NDK root: " + root + "\x1b[0m");
}
if (ndkVersion==0)
{
var version = Setup.getNdkVersion( root );
if (version > 0)
{
Log.info("", "\x1b[33;1mDetected Android NDK " + version + "\x1b[0m");
defines.set("NDKV" + Std.int(version), "1" );
ndkVersion = Std.int(version);
}
else
Log.error("Invalid ndk version");
}
for (i in 5...ndkVersion+1)
defines.set("NDKV" + i + "+", "1");
var arm_type = 'arm-linux-androideabi';
var arm_64 = defines.exists('HXCPP_ARM64');
if(arm_64) arm_type = 'aarch64-linux-android';
// Find toolchain
if (!defines.exists("TOOLCHAIN_VERSION"))
{
try
{
var files = FileSystem.readDirectory(root+"/toolchains");
// Prefer clang?
var extract_version = ~/^arm-linux-androideabi-(\d.*)/;
if(arm_64) extract_version = ~/^aarch64-linux-android-(\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);
Log.info("", "\x1b[33;1mDetected Android toolchain: "+arm_type+"-" + bestVer + "\x1b[0m");
}
}
catch(e:Dynamic) { }
}
// See what ANDROID_HOST to use ...
try
{
var prebuilt = root+"/toolchains/";
if (defines.exists("TOOLCHAIN_VERSION"))
prebuilt += arm_type + "-" + defines.get("TOOLCHAIN_VERSION") + "/prebuilt";
else
prebuilt += "llvm/prebuilt";
var files = FileSystem.readDirectory(prebuilt);
for (file in files)
{
if (!FileSystem.isDirectory (prebuilt + "/" + file))
{
files.remove (file);
}
}
if (files.length==1)
{
defines.set("ANDROID_HOST", files[0]);
Log.info("", "\x1b[33;1mDetected Android host: " + files[0] + "\x1b[0m");
}
else
{
Log.info("", "\x1b[33;1mCould not detect ANDROID_HOST (" + files + ") - using default\x1b[0m");
}
}
catch(e:Dynamic) { }
if(defines.exists('NDKV20+')) {
Log.v([
"x86 Platform: 16",
"arm Platform: 16",
"x86_64 Platform: 21",
"arm_64 Platform: 21",
"Frameworks should set the minSdkVersion for each APK to these values."
].join('\n'));
}
else {
globallySetThePlatform(root, defines);
}
}
private static function globallySetThePlatform(root:String, defines:Map<String,String>) {
var androidPlatform = 5;
if (!defines.exists("PLATFORM"))
{
for (i in 5...100)
{
var test = "android-" + i;
if (defines.exists(test))
{
defines.set("PLATFORM",test);
break;
}
}
}
if (defines.exists("PLATFORM"))
{
var platform = defines.get("PLATFORM");
var id = Std.parseInt( platform.substr("android-".length) );
if (id==0 || id==null)
Log.error('Badly formed android PLATFORM "$platform" - should be like android-123');
androidPlatform = id;
Log.info("", "\x1b[33;1mUsing Android NDK platform: " + defines.get("PLATFORM") + "\x1b[0m");
}
else
{
var base = 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)
{
Log.error("Could not detect Android API platforms in \"" + base + "\"");
//throw "Could not find platform in " + base;
}
Log.info("", "\x1b[33;1mUsing newest Android NDK platform: " + best + "\x1b[0m");
defines.set("PLATFORM", "android-" + best);
androidPlatform = best;
}
defines.set("ANDROID_PLATFORM_DEFINE", "HXCPP_ANDROID_PLATFORM=" + androidPlatform);
if (Log.verbose) Log.println("");
}
public static function setupBlackBerryNativeSDK(ioDefines:Hash<String>)
{
if (!ioDefines.exists ("BLACKBERRY_NDK_ROOT"))
{
Log.error("Could not find BLACKBERRY_NDK_ROOT variable");
}
var fileName = ioDefines.get ("BLACKBERRY_NDK_ROOT");
if (BuildTool.isWindows)
{
fileName += "\\bbndk-env.bat";
}
else
{
fileName += "/bbndk-env.sh";
}
if (FileSystem.exists (fileName))
{
var fin = sys.io.File.read(fileName, false);
try
{
while(true)
{
var str = fin.readLine();
var split = str.split ("=");
var name = StringTools.trim (split[0].substr (split[0].lastIndexOf (" ") + 1));
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);
}
if (StringTools.startsWith(value, "\""))
{
value = value.substr (1);
}
if (StringTools.endsWith(value, "\""))
{
value = value.substr (0, value.length - 1);
}
if (name == "QNX_HOST_VERSION" || name == "QNX_TARGET_VERSION")
{
if (Sys.getEnv (name) != null)
{
continue;
}
}
else
{
value = StringTools.replace (value, "$BASE_DIR", ioDefines.get ("BLACKBERRY_NDK_ROOT"));
value = StringTools.replace (value, "%BASE_DIR%", ioDefines.get ("BLACKBERRY_NDK_ROOT"));
value = StringTools.replace (value, "$TARGET", "qnx6");
value = StringTools.replace (value, "%TARGET%", "qnx6");
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_TARGET_VERSION%", Sys.getEnv("QNX_TARGET_VERSION"));
}
ioDefines.set(name,value);
Sys.putEnv(name,value);
}
}
}
catch( ex:Eof )
{}
fin.close();
}
else
{
Log.error("Could not find \"" + fileName + "\"");
}
}
public static function setupMSVC(ioDefines:Hash<String>, in64:Bool, inArm64, isWinRT:Bool)
{
var detectMsvc = !ioDefines.exists("NO_AUTO_MSVC") &&
!ioDefines.exists("HXCPP_MSVC_CUSTOM");
if (ioDefines.exists("HXCPP_MSVC_VER"))
{
var val = ioDefines.get("HXCPP_MSVC_VER");
if (val=="")
detectMsvc = false;
else
{
var ival = Std.parseInt(ioDefines.get("HXCPP_MSVC_VER"));
if (ival>0)
{
var varName = "VS" + ival+ "COMNTOOLS";
var where = Sys.getEnv(varName);
if (where==null)
{
for (env in Sys.environment().keys())
{
if (env.substr(0,2)=="VS")
{
Log.info("Found VS variable: " + env);
//Sys.println("Found VS variable " + env);
}
}
Log.error("Could not find specified MSVC version: " + ival);
//throw "Could not find specified MSVC version " + ival;
}
ioDefines.set("HXCPP_MSVC", where );
Sys.putEnv("HXCPP_MSVC", where);
Log.info("", 'Using MSVC Ver $ival in $where ($varName)');
}
else
{
Log.info("", 'Using specified MSVC Ver $val');
ioDefines.set("HXCPP_MSVC", val );
Sys.putEnv("HXCPP_MSVC", val);
}
}
}
if (detectMsvc)
{
var extra:String = "";
if (isWinRT)
extra += "-winrt";
if (inArm64)
extra += "-arm64";
else if (in64)
extra += "64";
var xpCompat = false;
if (ioDefines.exists("HXCPP_WINXP_COMPAT"))
{
Sys.putEnv("HXCPP_WINXP_COMPAT","1");
xpCompat = true;
}
Sys.putEnv("msvc_host_arch", ioDefines.exists("windows_arm_host") ? "x86" : "x64" );
var vc_setup_proc = new Process("cmd.exe", ["/C", BuildTool.HXCPP + "\\toolchain\\msvc" + extra + "-setup.bat" ]);
var vars_found = false;
var error_string = "";
var output = new Array<String>();
try{
while(true)
{
var str = vc_setup_proc.stdout.readLine();
if (str=="HXCPP_VARS")
vars_found = true;
else if (!vars_found)
{
if (str.substr(0,5)=="Error" || ~/missing/.match(str) )
error_string = str;
output.push(str);
}
else
{
var pos = str.indexOf("=");
var name = str.substr(0,pos);
switch(name.toLowerCase())
{
case "path", "vcinstalldir", "windowssdkdir","framework35version",
"frameworkdir", "frameworkdir32", "frameworkversion",
"frameworkversion32", "devenvdir", "include", "lib", "libpath", "hxcpp_xp_define",
"hxcpp_hack_pdbsrv"
:
var value = str.substr(pos+1);
ioDefines.set(name,value);
Log.v(' msvs $name=$value');
Sys.putEnv(name,value);
}
}
}
} catch (e:Dynamic) {
};
vc_setup_proc.exitCode();
vc_setup_proc.close();
if (!vars_found || error_string!="")
{
for (o in output)
{
Log.info(o);
//BuildTool.println(o);
}
if (error_string!="")
{
Log.error (error_string);
//throw(error_string);
}
else
{
Log.info("Missing HXCPP_VARS");
//BuildTool.println("Missing HXCPP_VARS");
}
Log.error("Could not automatically setup MSVC");
//throw("Could not automatically setup MSVC");
}
}
try
{
var proc = new Process("cl.exe",[]);
var str = proc.stderr.readLine();
proc.close();
if (str>"")
{
Log.v("MSVC output:" + str);
var reg = ~/(\d{2})\.\d+/i;
if (reg.match(str))
{
var cl_version = Std.parseInt(reg.matched(1));
Log.info("", "Using MSVC 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");
if (cl_version==19)
ioDefines.set("MSVC19","1");
BuildTool.sAllowNumProcs = cl_version >= 14;
var threads = BuildTool.getThreadCount();
if (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);
}
static function toPath(inPath:String)
{
if (!BuildTool.isWindows)
return inPath;
var bits = inPath.split("/");
return bits.join("\\");
}
}

View File

@ -0,0 +1,29 @@
class Stripper
{
public var mExe:String;
public var mFlags:Array<String>;
public function new(inExe:String)
{
mFlags = [];
mExe = inExe;
}
public function strip(inTarget:String)
{
var args = new Array<String>();
args = args.concat(mFlags);
args.push(inTarget);
var split = mExe.split(" ");
var exe = split.shift();
args = split.concat(args);
var result = ProcessManager.runCommand("", exe, args);
if (result!=0)
{
Tools.exit(result);
//throw "Error : " + result + " - build cancelled";
}
}
}

View File

@ -0,0 +1,106 @@
class Target
{
public var mBuildDir:String;
public var mOutput:String;
public var mOutputDir:String;
public var mTool:String;
public var mToolID:String;
private var mExt:String;
public var mFullOutputName:String;
public var mFullUnstrippedName:String;
// These attributes are merged by the "merge" command
public var mFiles:Array<File>;
public var mFileGroups:Array<FileGroup>;
public var mDepends:Array<String>;
public var mSubTargets:Array<String>;
public var mAutoLibs:Array<String>;
public var mLibs:Array<String>;
public var mLibPaths:Array<String>;
public var mFlags:Array<String>;
public var mErrors:Array<String>;
public var mDirs:Array<String>;
public function new(inOutput:String, inTool:String,inToolID:String)
{
mOutput = inOutput;
mOutputDir = "";
mBuildDir = "";
mToolID = inToolID;
mTool = inTool;
mFiles = [];
mDepends = [];
mAutoLibs = [];
mLibs = [];
mLibPaths = [];
mFlags = [];
mExt = null;
mFullOutputName = null;
mSubTargets = [];
mFileGroups = [];
mFlags = [];
mErrors=[];
mDirs=[];
}
public function merge(other:Target)
{
mFiles = mFiles.concat(other.mFiles);
mFileGroups = mFileGroups.concat(other.mFileGroups);
mDepends = mDepends.concat(other.mDepends);
mSubTargets = mSubTargets.concat(other.mSubTargets);
mLibPaths = mLibPaths.concat(other.mLibPaths);
mAutoLibs = mAutoLibs.concat(other.mAutoLibs);
mLibs = mLibs.concat(other.mLibs);
mFlags = mFlags.concat(other.mFlags);
mErrors = mErrors.concat(other.mErrors);
mDirs = mDirs.concat(other.mDirs);
}
public function toString() return mToolID;
public function getExt(inDefault:String)
{
return mExt==null ? inDefault : mExt;
}
public function setExt(inExt:String)
{
mExt = inExt;
}
public function addError(inError:String)
{
mErrors.push(inError);
}
public function addFiles(inGroup:FileGroup, inAsLibrary:Bool)
{
inGroup.mAsLibrary = inGroup.mAsLibrary || inAsLibrary;
mFiles = mFiles.concat([for(file in inGroup.mFiles) file]);
mFileGroups.push(inGroup);
}
public function checkError()
{
if (mErrors.length>0)
{
Log.error(mErrors.join(", "));
//throw mErrors.join("/");
}
}
public function clean()
{
for(dir in mDirs)
{
Log.info("Remove " + dir + "...");
PathManager.removeDirectory(dir);
}
}
public function getKey()
{
return mOutput + (mExt==null ? "" : mExt);
}
}

View File

@ -0,0 +1,105 @@
#if haxe4
import sys.thread.Thread;
import sys.thread.Mutex;
#else
#if neko
import neko.vm.Thread;
import neko.vm.Mutex;
#else
import cpp.vm.Thread;
import cpp.vm.Mutex;
#end
#end
#if cpp
import cpp.AtomicInt;
#end
class ThreadPool
{
var threads:Array<Thread>;
var mainThread:Thread;
#if cpp
var arrayIndex:AtomicInt;
#else
var arrayIndex:Int;
#end
var arrayCount:Int;
public var mutex:Mutex;
public function new(inCount:Int)
{
mutex = new Mutex();
mainThread = Thread.current();
threads = [];
for(i in 0...inCount)
threads.push( Thread.create( function() threadLoop(i) ) );
// Is this needed?
Tools.addOnExitHook( function(_) runJob(null) );
}
function threadLoop(threadId:Int)
{
while(true)
{
var job:Int->Void = Thread.readMessage(true);
if (job==null)
{
mainThread.sendMessage("done");
break;
}
try
{
job(threadId);
}
catch (error:Dynamic)
{
if (BuildTool.threadExitCode!=0)
BuildTool.setThreadError(-1);
else
Log.warn("Error in compile thread: " + error);
}
mainThread.sendMessage("ok");
}
}
public function setArrayCount(inCount:Int)
{
arrayIndex = 0;
arrayCount = inCount;
}
public function getNextIndex() : Int
{
#if cpp
var index = AtomicInt.atomicInc( cpp.Pointer.addressOf(arrayIndex) );
#else
mutex.acquire();
var index = arrayIndex++;
mutex.release();
#end
if (index<arrayCount)
return index;
return -1;
}
public function runJob(job:Int->Void)
{
for(thread in threads)
thread.sendMessage( job );
for(i in 0...threads.length)
Thread.readMessage(true);
// Already printed the error from the thread, just need to exit
if (job!=null && BuildTool.threadExitCode!=0)
Tools.exit(BuildTool.threadExitCode);
}
}

View File

@ -0,0 +1,14 @@
class Tools {
private static var onExit:Array<Int->Void> = [];
public static function addOnExitHook(fn:Int->Void) {
onExit.push(fn);
}
public static function exit(exitCode:Int) {
for (hook in onExit) {
hook(exitCode);
}
Sys.exit(exitCode);
}
}

View File

@ -0,0 +1,6 @@
-cpp cpp
-main BuildTool
-D HXCPP_STACK_TRACE
-D HXCPP_STACK_LINE
-D HXCPP_NEKO_BUILDTOOL=1
-D destination=../../../bin/{BINDIR}/BuildTool{EXESUFFIX}

View File

@ -0,0 +1,4 @@
-neko ../../hxcpp.n
-main BuildTool
-D neko_v1
-debug

View File

@ -0,0 +1,131 @@
import sys.FileSystem;
class RunMain
{
public static function log(s:String) Sys.println(s);
public static function showMessage()
{
var varName = "HXCPP_NONINTERACTIVE";
var nonInteractive:Bool =Sys.getEnv(varName)!=null;
if (!nonInteractive)
for(arg in Sys.args())
if (arg.indexOf("-D"+varName)==0 )
nonInteractive = true;
var dir = Sys.getCwd();
if (nonInteractive)
{
Sys.println('HXCPP in $dir is missing hxcpp.n');
Sys.exit(-1);
}
log('This version of hxcpp ($dir) appears to be a source/developement version.');
log("Before this can be used, you need to:");
log(" 1. Rebuild the main command-line tool, this can be done with:");
log(" cd tools/hxcpp");
log(" haxe compile.hxml");
log(" 2. FOR HXCPP API < 330:");
log(" Build the binaries appropriate to your system(s), this can be done with:");
log(" cd project");
log(" neko build.n");
var gotUserResponse = false;
sys.thread.Thread.create(function() {
Sys.sleep(30);
if (!gotUserResponse)
{
Sys.println("\nTimeout waiting for response.");
Sys.println("Can't continue without hxcpp.n");
Sys.exit(-1);
}
} );
while(true)
{
Sys.print("\nWould you like to do this now [y/n]");
var code = Sys.getChar(true);
gotUserResponse = true;
if (code<=32)
break;
var answer = String.fromCharCode(code);
if (answer=="y" || answer=="Y")
{
log("");
setup();
if (!executeHxcpp())
break;
return;
}
if (answer=="n" || answer=="N")
break;
}
Sys.println("\nCan't continue without hxcpp.n");
Sys.exit(-1);
}
public static function setup()
{
log("Compiling hxcpp tool...");
run("tools/hxcpp","haxe", [ "compile.hxml"]);
log("Initial setup complete.");
}
public static function run(dir:String, command:String, args:Array<String>)
{
var oldDir:String = "";
if (dir!="")
{
oldDir = Sys.getCwd();
Sys.setCwd(dir);
}
Sys.command(command,args);
if (oldDir!="")
Sys.setCwd(oldDir);
}
public static function executeHxcpp()
{
if (!sys.FileSystem.exists("./hxcpp.n"))
return false;
if (Sys.args().indexOf("-DHXCPP_NEKO_BUILDTOOL=1")<0)
{
var os = Sys.systemName();
var isWindows = (new EReg("window","i")).match(os);
var isMac = (new EReg("mac","i")).match(os);
var isLinux = (new EReg("linux","i")).match(os);
var binDir = isWindows ? "Windows64" : isMac ? "Mac64" : isLinux ? "Linux64" : null;
if (binDir!=null)
{
var compiled = 'bin/$binDir/BuildTool';
if (isWindows)
compiled += ".exe";
if (FileSystem.exists(compiled))
{
var dotN = FileSystem.stat("hxcpp.n").mtime.getTime();
var dotExe= FileSystem.stat(compiled).mtime.getTime();
if (dotExe<dotN)
{
var path = Sys.getCwd() + compiled;
Sys.println('Warning - $path file is out-of-date. Please delete or rebuild.');
}
else
{
Sys.exit( Sys.command( compiled, Sys.args() ) );
}
}
}
}
neko.vm.Loader.local().loadModule("./hxcpp.n");
return true;
}
public static function main()
{
if (!executeHxcpp())
showMessage();
}
}

View File

@ -0,0 +1,4 @@
-neko ../../run.n
-main RunMain
-D neko_v1
-debug

View File

@ -0,0 +1,51 @@
import sys.io.File;
class Write
{
public static function main()
{
var args = Sys.args();
var buildNumber = Std.parseInt(args[0]);
if (buildNumber<1 || buildNumber==null)
throw "Usage: Write buildNumber";
var jsonFile = "haxelib.json";
var lines = File.getContent(jsonFile).split("\n");
var idx = 0;
var versionMatch = ~/(.*"version"\s*:\s*")(.*)(".*)/;
var found = false;
var newVersion = "";
while(idx<lines.length)
{
if (versionMatch.match(lines[idx]))
{
var parts = versionMatch.matched(2).split(".");
if (parts.length==3)
parts[2] = buildNumber+"";
else
parts.push(buildNumber+"");
newVersion = parts.join(".");
lines[idx]=versionMatch.matched(1) + newVersion + versionMatch.matched(3);
found = true;
break;
}
idx++;
}
if (!found)
throw "Could not find version in " + jsonFile;
File.saveContent(jsonFile, lines.join("\n") );
var writeVersionFilename = "include/HxcppVersion.h";
var define = "HXCPP_VERSION";
var lines = [
'#ifndef $define',
'#define $define "$newVersion"',
'#endif'
];
File.saveContent( writeVersionFilename, lines.join("\n") );
Sys.println("hxcpp_release=" + newVersion );
}
}