325 lines
9.3 KiB
Haxe
325 lines
9.3 KiB
Haxe
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 "";
|
|
}
|
|
}
|