|
|
|
@ -34,12 +34,6 @@ var props = require('./properties'),
|
|
|
|
|
Queue.configure(Promise);
|
|
|
|
|
temp.track();
|
|
|
|
|
|
|
|
|
|
setInterval(function () {
|
|
|
|
|
temp.cleanup(function (err) {
|
|
|
|
|
if (err) throw new Error(err);
|
|
|
|
|
});
|
|
|
|
|
}, props.get('gcc-explorer', 'secsBetweenCleanups', 60) * 1000);
|
|
|
|
|
|
|
|
|
|
function Compile(compilers) {
|
|
|
|
|
this.compilersByExe = {};
|
|
|
|
|
var self = this;
|
|
|
|
@ -73,7 +67,7 @@ Compile.prototype.newTempDir = function () {
|
|
|
|
|
Compile.prototype.writeFile = Promise.denodeify(fs.writeFile);
|
|
|
|
|
Compile.prototype.stat = Promise.denodeify(fs.stat);
|
|
|
|
|
|
|
|
|
|
Compile.prototype.runCompiler = function(compiler, options) {
|
|
|
|
|
Compile.prototype.runCompiler = function (compiler, options) {
|
|
|
|
|
var okToCache = true;
|
|
|
|
|
var child = child_process.spawn(
|
|
|
|
|
compiler,
|
|
|
|
@ -104,87 +98,90 @@ Compile.prototype.runCompiler = function(compiler, options) {
|
|
|
|
|
|
|
|
|
|
Compile.prototype.compile = function (source, compiler, options, filters) {
|
|
|
|
|
var self = this;
|
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
|
|
|
var optionsError = self.checkOptions(options);
|
|
|
|
|
if (optionsError) return reject(optionsError);
|
|
|
|
|
var sourceError = self.checkSource(source);
|
|
|
|
|
if (sourceError) return reject(sourceError);
|
|
|
|
|
|
|
|
|
|
var compilerInfo = self.compilersByExe[compiler];
|
|
|
|
|
if (!compilerInfo) {
|
|
|
|
|
return reject("Bad compiler " + compiler);
|
|
|
|
|
var optionsError = self.checkOptions(options);
|
|
|
|
|
if (optionsError) return Promise.reject(optionsError);
|
|
|
|
|
var sourceError = self.checkSource(source);
|
|
|
|
|
if (sourceError) return Promise.reject(sourceError);
|
|
|
|
|
|
|
|
|
|
var compilerInfo = self.compilersByExe[compiler];
|
|
|
|
|
if (!compilerInfo) {
|
|
|
|
|
return Promise.reject("Bad compiler " + compiler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var key = compiler + " | " + source + " | " + options + " | " + filters.intel;
|
|
|
|
|
var cached = self.cache.get(key);
|
|
|
|
|
if (cached) {
|
|
|
|
|
self.cacheHits++;
|
|
|
|
|
self.cacheStats();
|
|
|
|
|
return Promise.resolve(cached);
|
|
|
|
|
}
|
|
|
|
|
self.cacheMisses++;
|
|
|
|
|
|
|
|
|
|
var tempFileAndDirPromise = self.compileQueue.add(function () {
|
|
|
|
|
return self.newTempDir().then(function (dirPath) {
|
|
|
|
|
var inputFilename = path.join(dirPath, props.get("gcc-explorer", "compileFilename"));
|
|
|
|
|
return self.writeFile(inputFilename, source).then(function () {
|
|
|
|
|
return {inputFilename: inputFilename, dirPath: dirPath};
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
var compileToAsmPromise = tempFileAndDirPromise.then(function (info) {
|
|
|
|
|
var inputFilename = info.inputFilename;
|
|
|
|
|
var dirPath = info.dirPath;
|
|
|
|
|
var postProcess = props.get("gcc-explorer", "postProcess");
|
|
|
|
|
var outputFilename = path.join(dirPath, 'output.S');
|
|
|
|
|
if (compilerInfo.supportedOpts['-masm']) {
|
|
|
|
|
var syntax = '-masm=att'; // default at&t
|
|
|
|
|
if (filters.intel == "true") syntax = '-masm=intel';
|
|
|
|
|
options = options.concat([syntax]);
|
|
|
|
|
}
|
|
|
|
|
var compileToAsm = props.get("gcc-explorer", "compileToAsm", "-S").split(" ");
|
|
|
|
|
options = options.concat(['-g', '-o', outputFilename]).concat(compileToAsm).concat([inputFilename]);
|
|
|
|
|
|
|
|
|
|
var key = compiler + " | " + source + " | " + options + " | " + filters.intel;
|
|
|
|
|
var cached = self.cache.get(key);
|
|
|
|
|
if (cached) {
|
|
|
|
|
self.cacheHits++;
|
|
|
|
|
self.cacheStats();
|
|
|
|
|
return resolve(cached);
|
|
|
|
|
var compilerWrapper = props.get("gcc-explorer", "compiler-wrapper");
|
|
|
|
|
if (compilerWrapper) {
|
|
|
|
|
options = [compiler].concat(options);
|
|
|
|
|
compiler = compilerWrapper;
|
|
|
|
|
}
|
|
|
|
|
self.cacheMisses++;
|
|
|
|
|
|
|
|
|
|
var queuedPromise = self.compileQueue.add(function () {
|
|
|
|
|
return self.newTempDir().then(function (dirPath) {
|
|
|
|
|
var inputFilename = path.join(dirPath, props.get("gcc-explorer", "compileFilename"));
|
|
|
|
|
return self.writeFile(inputFilename, source).then(function () {
|
|
|
|
|
return {inputFilename: inputFilename, dirPath: dirPath};
|
|
|
|
|
});
|
|
|
|
|
}).then(function (info) {
|
|
|
|
|
var inputFilename = info.inputFilename;
|
|
|
|
|
var dirPath = info.dirPath;
|
|
|
|
|
var postProcess = props.get("gcc-explorer", "postProcess");
|
|
|
|
|
var outputFilename = path.join(dirPath, 'output.S');
|
|
|
|
|
if (compilerInfo.supportedOpts['-masm']) {
|
|
|
|
|
var syntax = '-masm=att'; // default at&t
|
|
|
|
|
if (filters.intel == "true") syntax = '-masm=intel';
|
|
|
|
|
options = options.concat([syntax]);
|
|
|
|
|
}
|
|
|
|
|
var compileToAsm = props.get("gcc-explorer", "compileToAsm", "-S").split(" ");
|
|
|
|
|
options = options.concat(['-g', '-o', outputFilename]).concat(compileToAsm).concat([inputFilename]);
|
|
|
|
|
|
|
|
|
|
var compilerWrapper = props.get("gcc-explorer", "compiler-wrapper");
|
|
|
|
|
if (compilerWrapper) {
|
|
|
|
|
options = [compiler].concat(options);
|
|
|
|
|
compiler = compilerWrapper;
|
|
|
|
|
var maxSize = props.get("gcc-explorer", "max-asm-size", 8 * 1024 * 1024);
|
|
|
|
|
return self.runCompiler(compiler, options).then(function (result) {
|
|
|
|
|
result.dirPath = dirPath;
|
|
|
|
|
if (result.code !== 0) {
|
|
|
|
|
result.asm = "<Compilation failed>";
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
return self.stat(outputFilename).then(function (stat) {
|
|
|
|
|
if (stat.size >= maxSize) {
|
|
|
|
|
result.asm = "<No output: generated assembly was too large (" + size + " > " + maxSize + " bytes)>";
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
var maxSize = props.get("gcc-explorer", "max-asm-size", 8 * 1024 * 1024);
|
|
|
|
|
var gotAsmFinished = self.runCompiler(compiler, options).then(function (result) {
|
|
|
|
|
if (result.code !== 0) {
|
|
|
|
|
result.asm = "<Compilation failed>";
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
return self.stat(outputFilename).then(function (stat) {
|
|
|
|
|
if (stat.size >= maxSize) {
|
|
|
|
|
result.asm = "<No output: generated assembly was too large (" + size + " > " + maxSize + " bytes)>";
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
return new Promise(function (resolve) {
|
|
|
|
|
child_process.exec('cat "' + outputFilename + '" | ' + postProcess,
|
|
|
|
|
{maxBuffer: maxSize},
|
|
|
|
|
function (err, data) {
|
|
|
|
|
if (err)
|
|
|
|
|
data = '<No output: ' + err + '>';
|
|
|
|
|
result.asm = data;
|
|
|
|
|
resolve(result);
|
|
|
|
|
});
|
|
|
|
|
return new Promise(function (resolve) {
|
|
|
|
|
child_process.exec('cat "' + outputFilename + '" | ' + postProcess,
|
|
|
|
|
{maxBuffer: maxSize},
|
|
|
|
|
function (err, data) {
|
|
|
|
|
if (err)
|
|
|
|
|
data = '<No output: ' + err + '>';
|
|
|
|
|
result.asm = data;
|
|
|
|
|
resolve(result);
|
|
|
|
|
});
|
|
|
|
|
}, function () {
|
|
|
|
|
result.asm = "<No output file>";
|
|
|
|
|
return result;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return gotAsmFinished.then(function (result) {
|
|
|
|
|
if (result.okToCache) {
|
|
|
|
|
self.cache.set(key, result);
|
|
|
|
|
self.cacheStats();
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
});
|
|
|
|
|
}, function () {
|
|
|
|
|
result.asm = "<No output file>";
|
|
|
|
|
return result;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
return queuedPromise.then(resolve, reject);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return compileToAsmPromise.then(function (result) {
|
|
|
|
|
if (result.dirPath) {
|
|
|
|
|
fs.remove(result.dirPath);
|
|
|
|
|
result.dirPath = undefined;
|
|
|
|
|
}
|
|
|
|
|
if (result.okToCache) {
|
|
|
|
|
self.cache.set(key, result);
|
|
|
|
|
self.cacheStats();
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|