Merge remote-tracking branch 'origin/incoming' into merge-mar-13-2015

This commit is contained in:
Alon Zakai 2015-03-23 15:09:09 -07:00
Родитель c3f175d0bf bd3f4f8da8
Коммит 6d7cd58175
33 изменённых файлов: 473 добавлений и 146 удалений

Просмотреть файл

@ -180,4 +180,5 @@ a license to everyone to use it as detailed in LICENSE.)
* Matt McCormick <matt.mccormick@kitware.com>
* Thaddée Tyl <thaddee.tyl@gmail.com>
* Philipp Wiesemann <philipp.wiesemann@arcor.de>
* Jan Jongboom <janjongboom@gmail.com> (copyright owned by Telenor Digital AS)

34
emcc
Просмотреть файл

@ -976,10 +976,25 @@ try:
shared.Settings.ASM_JS = 2
if shared.Settings.POINTER_MASKING:
logging.warning('POINTER_MASKING is experimental')
size = shared.Settings.POINTER_MASKING + 1 # size plus 1 should be a power of 2
if size & (size-1) != 0:
raise Exception('POINTER_MASKING value must be a power of 2 minus 1')
if shared.Settings.ALLOW_MEMORY_GROWTH:
raise Exception('With POINTER_MASKING the ALLOW_MEMORY_GROWTH feature is not supported')
if not shared.Settings.POINTER_MASKING_DYNAMIC:
shared.Settings.POINTER_MASKING_DEFAULT_ENABLED = 1;
size = shared.Settings.TOTAL_MEMORY
if size & (size - 1) != 0:
raise Exception('With POINTER_MASKING the TOTAL_MEMORY must be a power of 2')
if shared.Settings.ASM_JS:
# Silently keep the total length a valid asm.js heap buffer length.
overflow = shared.Settings.POINTER_MASKING_OVERFLOW;
if overflow > 0:
if size <= 0x01000000:
shared.Settings.POINTER_MASKING_OVERFLOW = size;
else:
shared.Settings.POINTER_MASKING_OVERFLOW = (overflow + 0x00ffffff) & 0xff000000;
elif shared.Settings.POINTER_MASKING_DYNAMIC:
raise Exception('POINTER_MASKING_DYNAMIC requires POINTER_MASKING')
else:
shared.Settings.POINTER_MASKING_DEFAULT_ENABLED = 0
assert shared.LLVM_TARGET in shared.COMPILER_OPTS
if shared.LLVM_TARGET == 'i386-pc-linux-gnu':
@ -1504,10 +1519,11 @@ try:
# add explicit label setting, as we will run aggressiveVariableElimination late, *after* 'label' is no longer notable by name
js_optimizer_queue += ['safeLabelSetting']
if shared.Settings.EMTERPRETIFY:
# add explicit label setting, as we will run aggressiveVariableElimination late, *after* 'label' is no longer notable by name
js_optimizer_queue += ['safeLabelSetting']
if shared.Settings.EMTERPRETIFY:
# add explicit label setting, as we will run aggressiveVariableElimination late, *after* 'label' is no longer notable by name
js_optimizer_queue += ['safeLabelSetting']
if opt_level >= 1 and js_opts:
if opt_level >= 2:
if shared.Settings.RELOOP and not shared.Settings.ASM_JS:
js_optimizer_queue += ['optimizeShiftsAggressive', get_eliminate()] # aggressive shifts optimization requires loops, it breaks on switches
@ -1556,7 +1572,8 @@ try:
else:
js_optimizer_queue += ['registerize']
if shared.Settings.POINTER_MASKING and shared.Settings.ASM_JS: js_optimizer_queue += ['pointerMasking']
if shared.Settings.POINTER_MASKING:
js_optimizer_queue += ['pointerMasking']
if not shared.Settings.EMTERPRETIFY:
do_minify()
@ -1597,6 +1614,7 @@ try:
js_target = unsuffixed(target) + '.js'
if shared.Settings.EMTERPRETIFY:
flush_js_optimizer_queue()
logging.debug('emterpretifying')
assert memory_init_file, 'emterpreter requires a mem init file'
import json

Просмотреть файл

@ -1268,7 +1268,11 @@ function jsCall_%s_%s(%s) {
if settings['POINTER_MASKING']:
for i in [0, 1, 2, 3]:
asm_global_vars += ' var MASK%d=%d;\n' % (i, (settings['TOTAL_MEMORY']-1) & (~((2**i)-1)));
if settings['POINTER_MASKING_DYNAMIC']:
asm_global_vars += ' const MASK%d=env' % i + access_quote('MASK%d' % i) + '|0;\n';
basic_vars += ['MASK%d' %i]
else:
asm_global_vars += ' const MASK%d=%d;\n' % (i, (settings['TOTAL_MEMORY']-1) & (~((2**i)-1)));
# sent data
the_global = '{ ' + ', '.join(['"' + math_fix(s) + '": ' + s for s in fundamentals]) + ' }'
@ -1379,7 +1383,12 @@ function _emscripten_replace_memory(newBuffer) {
buffer = newBuffer;
return true;
}
'''] + ['''
'''] + \
['' if not settings['POINTER_MASKING'] or settings['POINTER_MASKING_DYNAMIC'] else '''
function _declare_heap_length() {
return HEAP8[%s] | 0;
}
''' % (settings['TOTAL_MEMORY'] + settings['POINTER_MASKING_OVERFLOW'] - 1)] + ['''
// EMSCRIPTEN_START_FUNCS
function stackAlloc(size) {
size = size|0;

Просмотреть файл

@ -3378,7 +3378,6 @@ LibraryManager.library = {
if ((ret | 0) == 32) ret = ret + (Math_clz32(l) | 0) | 0;
tempRet0 = 0;
return ret | 0;
#endif
},
llvm_cttz_i32__deps: [function() {

Просмотреть файл

@ -1312,7 +1312,6 @@ mergeInto(LibraryManager.library, {
},
emscripten_worker_respond_provisionally: function(data, size) {
if (!inWorkerCall) throw 'not in worker call!';
if (workerResponded) throw 'already responded with final response!';
postMessage({
'callbackId': workerCallbackId,
@ -1322,7 +1321,6 @@ mergeInto(LibraryManager.library, {
},
emscripten_worker_respond: function(data, size) {
if (!inWorkerCall) throw 'not in worker call!';
if (workerResponded) throw 'already responded with final response!';
workerResponded = true;
postMessage({

Просмотреть файл

@ -97,7 +97,7 @@ mergeInto(LibraryManager.library, {
while (FS.isLink(current.mode)) {
var link = FS.readlink(current_path);
current_path = PATH.resolve(PATH.dirname(current_path), link);
var lookup = FS.lookupPath(current_path, { recurse_count: opts.recurse_count });
current = lookup.node;
@ -427,7 +427,7 @@ mergeInto(LibraryManager.library, {
// we employ a simple trick: the pointer to a stream is its fd plus 1. This
// means that all valid streams have a valid non-zero pointer while allowing
// the fs for stdin to be the standard value of zero.
//
//
//
getStreamFromPtr: function(ptr) {
return FS.streams[ptr - 1];
@ -838,7 +838,7 @@ mergeInto(LibraryManager.library, {
if (!link.node_ops.readlink) {
throw new FS.ErrnoError(ERRNO_CODES.EINVAL);
}
return link.node_ops.readlink(link);
return PATH.resolve(FS.getPath(lookup.node.parent), link.node_ops.readlink(link));
},
stat: function(path, dontFollow) {
var lookup = FS.lookupPath(path, { follow: !dontFollow });

Просмотреть файл

@ -1,6 +1,6 @@
mergeInto(LibraryManager.library, {
$NODEFS__deps: ['$FS', '$PATH'],
$NODEFS__postset: 'if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); NODEFS.staticInit(); }',
$NODEFS__postset: 'if (ENVIRONMENT_IS_NODE) { var fs = require("fs"); var NODEJS_PATH = require("path"); NODEFS.staticInit(); }',
$NODEFS: {
isWindows: false,
staticInit: function() {
@ -24,7 +24,7 @@ mergeInto(LibraryManager.library, {
try {
stat = fs.lstatSync(path);
if (NODEFS.isWindows) {
// On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
// On Windows, directories return permission bits 'rw-rw-rw-', even though they have 'rwxrwxrwx', so
// propagate write bits to execute bits.
stat.mode = stat.mode | ((stat.mode & 146) >> 1);
}
@ -203,7 +203,9 @@ mergeInto(LibraryManager.library, {
readlink: function(node) {
var path = NODEFS.realPath(node);
try {
return fs.readlinkSync(path);
path = fs.readlinkSync(path);
path = NODEJS_PATH.relative(NODEJS_PATH.resolve(node.mount.opts.root), path);
return path;
} catch (e) {
if (!e.code) throw e;
throw new FS.ErrnoError(ERRNO_CODES[e.code]);

Просмотреть файл

@ -57,8 +57,10 @@ function preprocess(text) {
ret += '\n' + preprocess(included) + '\n'
}
} else if (line[2] == 'l') { // else
assert(showStack.length > 0);
showStack.push(!showStack.pop());
} else if (line[2] == 'n') { // endif
assert(showStack.length > 0);
showStack.pop();
} else {
throw "Unclear preprocessor command: " + line;

Просмотреть файл

@ -300,7 +300,7 @@ function messageResender() {
}
var buffer = 0, bufferSize = 0;
var inWorkerCall = false, workerResponded = false, workerCallbackId = -1;
var workerResponded = false, workerCallbackId = -1;
onmessage = function onmessage(msg) {
// if main has not yet been called (mem init file, other async things), buffer messages
@ -326,7 +326,6 @@ onmessage = function onmessage(msg) {
HEAPU8.set(data, buffer);
}
inWorkerCall = true;
workerResponded = false;
workerCallbackId = msg.data['callbackId'];
if (data) {
@ -334,7 +333,6 @@ onmessage = function onmessage(msg) {
} else {
func(0, 0);
}
inWorkerCall = false;
}
#endif

Просмотреть файл

@ -1329,9 +1329,49 @@ try {
var TOTAL_STACK = Module['TOTAL_STACK'] || {{{ TOTAL_STACK }}};
var TOTAL_MEMORY = Module['TOTAL_MEMORY'] || {{{ TOTAL_MEMORY }}};
var FAST_MEMORY = Module['FAST_MEMORY'] || {{{ FAST_MEMORY }}};
#if ASM_JS
#if POINTER_MASKING
#if POINTER_MASKING_DYNAMIC
var POINTER_MASKING_ENABLED = Module['POINTER_MASKING_DEFAULT_ENABLED'] || {{{ POINTER_MASKING_DEFAULT_ENABLED }}};
var POINTER_MASKING_OVERFLOW = Module['POINTER_MASKING_OVERFLOW'] || {{{ POINTER_MASKING_OVERFLOW }}}
var MASK0 = -1, MASK1 = -1, MASK2 = -1, MASK3 = -1;
function initPointerMasking() {
var totalMemory = 64*1024;
while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
if (POINTER_MASKING_ENABLED || totalMemory < 16*1024*1024) {
totalMemory *= 2;
} else {
totalMemory += 16*1024*1024
}
}
if (totalMemory !== TOTAL_MEMORY) {
Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be compliant with the asm.js spec (and given that TOTAL_STACK=' + TOTAL_STACK + ')');
TOTAL_MEMORY = totalMemory;
}
// Silently keep the total length a valid asm.js heap buffer length.
if (POINTER_MASKING_OVERFLOW > 0) {
if (TOTAL_MEMORY <= 0x01000000) {
POINTER_MASKING_OVERFLOW = TOTAL_MEMORY;
} else {
POINTER_MASKING_OVERFLOW = (POINTER_MASKING_OVERFLOW + 0x00ffffff) & 0xff000000;
}
}
MASK0 = POINTER_MASKING_ENABLED ? TOTAL_MEMORY - 1 : -1;
MASK1 = POINTER_MASKING_ENABLED ? (TOTAL_MEMORY - 1) & ~1 : -1;
MASK2 = POINTER_MASKING_ENABLED ? (TOTAL_MEMORY - 1) & ~3 : -1;
MASK3 = POINTER_MASKING_ENABLED ? (TOTAL_MEMORY - 1) & ~7 : -1;
}
initPointerMasking();
#else // POINTER_MASKING_DYNAMIC
var totalMemory = 64*1024;
while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
totalMemory *= 2;
}
#endif // POINTER_MASKING_DYNAMIC
#else // POINTER_MASKING
var totalMemory = 64*1024;
while (totalMemory < TOTAL_MEMORY || totalMemory < 2*TOTAL_STACK) {
if (totalMemory < 16*1024*1024) {
@ -1347,7 +1387,9 @@ if (totalMemory !== TOTAL_MEMORY) {
Module.printErr('increasing TOTAL_MEMORY to ' + totalMemory + ' to be compliant with the asm.js spec (and given that TOTAL_STACK=' + TOTAL_STACK + ')');
TOTAL_MEMORY = totalMemory;
}
#endif
#endif // POINTER_MASKING
// Initialize the runtime's memory
#if USE_TYPED_ARRAYS
@ -1362,8 +1404,19 @@ IHEAPU = new Uint32Array(IHEAP.buffer);
FHEAP = new Float64Array(TOTAL_MEMORY);
#endif
#endif
#if USE_TYPED_ARRAYS == 2
#if POINTER_MASKING
#if POINTER_MASKING_DYNAMIC
var buffer = new ArrayBuffer(TOTAL_MEMORY + (POINTER_MASKING_ENABLED ? POINTER_MASKING_OVERFLOW : 0));
#else
var buffer = new ArrayBuffer(TOTAL_MEMORY + {{{ POINTER_MASKING_OVERFLOW }}});
#endif
#else
var buffer = new ArrayBuffer(TOTAL_MEMORY);
#endif // POINTER_MASKING
#endif // USE_TYPED_ARRAYS == 2
HEAP8 = new Int8Array(buffer);
HEAP16 = new Int16Array(buffer);
HEAP32 = new Int32Array(buffer);
@ -1376,14 +1429,7 @@ HEAPF64 = new Float64Array(buffer);
// Endianness check (note: assumes compiler arch was little-endian)
HEAP32[0] = 255;
assert(HEAPU8[0] === 255 && HEAPU8[3] === 0, 'Typed arrays 2 must be run on a little-endian system');
#endif
#else
// Make sure that our HEAP is implemented as a flat array.
HEAP = []; // Hinting at the size with |new Array(TOTAL_MEMORY)| should help in theory but makes v8 much slower
for (var i = 0; i < FAST_MEMORY; i++) {
HEAP[i] = 0; // XXX We do *not* use {{| makeSetValue(0, 'i', 0, 'null') |}} here, since this is done just to optimize runtime speed
}
#endif
#endif // USE_TYPED_ARRAYS
Module['HEAP'] = HEAP;
#if USE_TYPED_ARRAYS == 1

Просмотреть файл

@ -61,6 +61,7 @@ var KeyboardEvent = {
function PropertyBag() {
this.addProperty = function(){};
this.removeProperty = function(){};
this.setProperty = function(){};
};
var IndexedObjects = {
@ -295,6 +296,11 @@ Audio.prototype.cloneNode = function() {
return new Audio;
}
var screen = {
width: 0,
height: 0
};
Module.canvas = document.createElement('canvas');
Module.setStatus = function(){};
@ -397,8 +403,8 @@ onmessage = function onmessage(message) {
}
case 'worker-init': {
Module.canvas = document.createElement('canvas');
Module.canvas.width_ = message.data.width;
Module.canvas.height_ = message.data.height;
screen.width = Module.canvas.width_ = message.data.width;
screen.height = Module.canvas.height_ = message.data.height;
document.URL = message.data.URL;
window.fireEvent({ type: 'load' });
removeRunDependency('worker-init');

Просмотреть файл

@ -58,8 +58,6 @@ var TOTAL_STACK = 5*1024*1024; // The total stack size. There is no way to enlar
var TOTAL_MEMORY = 16777216; // The total amount of memory to use. Using more memory than this will
// cause us to expand the heap, which can be costly with typed arrays:
// we need to copy the old heap into a new one in that case.
var FAST_MEMORY = 2*1024*1024; // The amount of memory to initialize to 0. This ensures it will be
// in a flat array. This only matters in non-typed array builds.
var ALLOW_MEMORY_GROWTH = 0; // If false, we abort with an error if we try to allocate more memory than
// we can (TOTAL_MEMORY). If true, we will grow the memory arrays at
// runtime, seamlessly and dynamically. This has a performance cost though,
@ -190,8 +188,26 @@ var OUTLINING_LIMIT = 0; // A function size above which we try to automatically
var AGGRESSIVE_VARIABLE_ELIMINATION = 0; // Run aggressiveVariableElimination in js-optimizer.js
var SIMPLIFY_IFS = 1; // Whether to simplify ifs in js-optimizer.js
var POINTER_MASKING = 0; // Whether to mask pointers (experimental optimization trying to reduce VM bounds checks).
// When using this option, TOTAL_MEMORY must be a power of 2.
var POINTER_MASKING = 0; // Whether pointers can be masked to a power-of-two heap
// length. An experimental optimization trying to reduce VM
// bounds checks.
var POINTER_MASKING_OVERFLOW = 64 * 1024; // The length added to the heap length to allow
// the compiler to derive that accesses are
// within bounds even when adding small constant
// offsets. This defaults to 64K, but in asm.js
// mode it is silently adjusted to keep the
// total buffer length a valid asm.js heap
// buffer length.
var POINTER_MASKING_DYNAMIC = 0; // When disabled, the masking is baked into the code with
// static masks and a static heap buffer length and the
// TOTAL_MEMORY must be a power of 2. When enabled, the
// masks are defined at runtime rather than compling them
// into the asm.js module as literal constants and the
// TOTAL_MEMORY can be defined at run time.
var POINTER_MASKING_DEFAULT_ENABLED = 1; // When POINTER_MASKING_DYNAMIC is enabled this
// sets the default for POINTER_MASKING_ENABLED,
// enabling or disabling pointer masking.
// Generated code debugging options
var SAFE_HEAP = 0; // Check each write to the heap, for example, this will give a clear
@ -614,6 +630,8 @@ var EMTERPRETIFY_ADVISE = 0; // Performs a static analysis to suggest which func
// appears they can be on the stack when a sync function is called in the EMTERPRETIFY_ASYNC option.
// After showing the suggested list, compilation will halt. You can apply the provided list as an
// emcc argument when compiling later.
// This will also advise on the YIELDLIST, if it contains at least one value (it then reports
// all things reachable from that function, as they may need to be in the YIELDLIST as well).
// Note that this depends on things like inlining. If you run this with different inlining than
// when you use the list, it might not work.

Просмотреть файл

@ -0,0 +1,2 @@
@echo off
python "%~dp0\sdl-config" %*

Просмотреть файл

@ -0,0 +1,2 @@
@echo off
python "%~dp0\sdl2-config" %*

Просмотреть файл

@ -44,7 +44,7 @@
setTimeout(function() {
var secondImage = Module.canvas.toDataURL();
reportResult(firstImage != secondImage);
}, 0);
}, 500);
}
Module.postRun = doTest;

Просмотреть файл

@ -25,8 +25,9 @@ void main_loop()
if (ret > 0) puts(str);
}
int err = ferror(stdin);
if (ferror(stdin) && errno != EAGAIN) {
puts("error");
printf("error %d\n", err);
exit(EXIT_FAILURE);
}

Просмотреть файл

@ -0,0 +1,18 @@
function z1() {
var i = 0, j = 0;
print(i);
}
function z2() {
var i = 0, label = 0;
label = 0;
print(i);
}
function z3() {
var i = 0, label = 0;
}
function z4() {
var label = 0;
label = 0;
print(0);
}

Просмотреть файл

@ -0,0 +1,17 @@
function z1() {
var i = 0, j = 0;
print(i);
}
function z2() {
var i = 0, label = 0;
print(i);
}
function z3() {
var i = 0, label = 0;
}
function z4() {
var label = 0;
print(0);
}
// EMSCRIPTEN_GENERATED_FUNCTIONS: ["z1", "z2", "z3", "z4"]

Просмотреть файл

@ -1,72 +1,72 @@
function f() {
HEAP8[x >> 0];
HEAP8[(x & MASK0) >> 0];
HEAP8[(x & MASK0) + 1 >> 0];
HEAP8[(x & MASK0) + 2 >> 0];
HEAP8[(x + 1 & MASK0) + 2 >> 0];
HEAP8[(x + 2 & MASK0) + 2 >> 0];
HEAP8[(x + 1 + y & MASK0) + 2 >> 0];
HEAP8[(x + 2 + y & MASK0) + 2 >> 0];
HEAP8[(x & MASK0) + 3 >> 0];
HEAP8[(x & MASK0) + 4 >> 0];
HEAP8[(x + y & MASK0) + 3 >> 0];
HEAP8[(x + y & MASK0) + 4 >> 0];
x();
HEAP16[x >> 1];
HEAP16[x + 1 >> 1];
HEAP16[(x & MASK1) >> 1];
HEAP16[(x + 1 & MASK1) >> 1];
HEAP16[(x & MASK1) + 2 >> 1];
HEAP16[(x + 1 & MASK1) + 2 >> 1];
HEAP16[(x + 2 & MASK1) + 2 >> 1];
HEAP16[(x & MASK1) + 4 >> 1];
HEAP16[(x + 1 + y & MASK1) + 2 >> 1];
HEAP16[(x + 2 + y & MASK1) + 2 >> 1];
HEAP16[(x + y & MASK1) + 4 >> 1];
HEAP16[(x + 1 + y & MASK1) + 4 >> 1];
HEAP16[(x + 2 + y & MASK1) + 4 >> 1];
HEAP16[(x + y & MASK1) + 6 >> 1];
HEAP16[(x + 1 + y & MASK1) + 4 >> 1];
HEAP16[(x + 4 + y & MASK1) + 2 >> 1];
HEAP16[(x + y & MASK1) + 6 >> 1];
x();
HEAP32[x >> 2];
HEAP32[x + 1 >> 2];
HEAP32[x + 2 >> 2];
HEAP32[x + 3 >> 2];
HEAP32[(x & MASK2) >> 2];
HEAP32[(x + 1 & MASK2) >> 2];
HEAP32[(x + 2 & MASK2) >> 2];
HEAP32[(x + 3 & MASK2) >> 2];
HEAP32[(x & MASK2) + 4 >> 2];
HEAP32[(x + 1 & MASK2) + 4 >> 2];
HEAP32[(x + 4 & MASK2) + 4 >> 2];
HEAP32[(x & MASK2) + 8 >> 2];
HEAP32[(x + 1 + y & MASK2) + 4 >> 2];
HEAP32[(x + 4 + y & MASK2) + 4 >> 2];
HEAP32[(x + y & MASK2) + 8 >> 2];
HEAP32[(x + 1 + y & MASK2) + 8 >> 2];
HEAP32[(x + 4 + y & MASK2) + 8 >> 2];
HEAP32[(x + y & MASK2) + 12 >> 2];
HEAP32[(x + 1 + y & MASK2) + 8 >> 2];
HEAP32[(x + 8 + y & MASK2) + 4 >> 2];
HEAP32[(x + y & MASK2) + 12 >> 2];
x();
HEAPU32[x >> 2];
HEAPU32[x + 1 >> 2];
HEAPU32[(x & MASK2) >> 2];
HEAPU32[(x + 1 & MASK2) >> 2];
HEAPU32[(x & MASK2) + 4 >> 2];
HEAPU32[(x + 1 & MASK2) + 4 >> 2];
HEAPU32[(x + 4 & MASK2) + 4 >> 2];
HEAPU32[(x & MASK2) + 8 >> 2];
HEAPU32[(x + 1 + y & MASK2) + 4 >> 2];
HEAPU32[(x + 4 + y & MASK2) + 4 >> 2];
HEAPU32[(x + y & MASK2) + 8 >> 2];
HEAPU32[(x + 1 + y & MASK2) + 8 >> 2];
HEAPU32[(x + 4 + y & MASK2) + 8 >> 2];
HEAPU32[(x + y & MASK2) + 12 >> 2];
HEAPU32[(x + 1 + y & MASK2) + 8 >> 2];
HEAPU32[(x + 8 + y & MASK2) + 4 >> 2];
HEAPU32[(x + y & MASK2) + 12 >> 2];
x();
HEAPF32[x >> 2];
HEAPF32[x + 1 >> 2];
HEAPF32[(x & MASK2) >> 2];
HEAPF32[(x + 1 & MASK2) >> 2];
HEAPF32[(x & MASK2) + 4 >> 2];
HEAPF32[(x + 1 & MASK2) + 4 >> 2];
HEAPF32[(x + 4 & MASK2) + 4 >> 2];
HEAPF32[(x & MASK2) + 8 >> 2];
HEAPF32[(x + 1 + y & MASK2) + 4 >> 2];
HEAPF32[(x + 4 + y & MASK2) + 4 >> 2];
HEAPF32[(x + y & MASK2) + 8 >> 2];
HEAPF32[(x + 1 + y & MASK2) + 8 >> 2];
HEAPF32[(x + 4 + y & MASK2) + 8 >> 2];
HEAPF32[(x + y & MASK2) + 12 >> 2];
HEAPF32[(x + 1 + y & MASK2) + 8 >> 2];
HEAPF32[(x + 8 + y & MASK2) + 4 >> 2];
HEAPF32[(x + y & MASK2) + 12 >> 2];
x();
HEAPF64[x >> 3];
HEAPF64[x + 1 >> 3];
HEAPF64[(x & MASK3) >> 3];
HEAPF64[(x + 1 & MASK3) >> 3];
HEAPF64[(x & MASK3) + 8 >> 3];
HEAPF64[(x + 1 & MASK3) + 8 >> 3];
HEAPF64[(x + 8 & MASK3) + 8 >> 3];
HEAPF64[(x & MASK3) + 16 >> 3];
HEAPF64[(x + 1 + y & MASK3) + 8 >> 3];
HEAPF64[(x + 8 + y & MASK3) + 8 >> 3];
HEAPF64[(x + y & MASK3) + 16 >> 3];
HEAPF64[(x + 1 + y & MASK3) + 16 >> 3];
HEAPF64[(x + 8 + y & MASK3) + 16 >> 3];
HEAPF64[(x + y & MASK3) + 24 >> 3];
HEAPF64[(x + 1 + y & MASK3) + 16 >> 3];
HEAPF64[(x + 16 + y & MASK3) + 8 >> 3];
HEAPF64[(x + y & MASK3) + 24 >> 3];
}

Просмотреть файл

@ -111,7 +111,7 @@ process(sys.argv[1])
'-O3', '-s', 'DOUBLE_MODE=0', '-s', 'PRECISE_I64_MATH=0',
'--memory-init-file', '0', '--js-transform', 'python hardcode.py',
'-s', 'TOTAL_MEMORY=128*1024*1024',
#'--profiling',
'--profiling',
#'--closure', '1',
'-o', final] + shared_args + emcc_args + self.extra_args, stdout=PIPE, stderr=PIPE, env=self.env).communicate()
assert os.path.exists(final), 'Failed to compile file: ' + output[0]
@ -136,6 +136,7 @@ try:
#NativeBenchmarker(default_native_name, os.path.join(default_native, 'clang'), os.path.join(default_native, 'clang++')),
#NativeBenchmarker('clang', CLANG_CC, CLANG),
#NativeBenchmarker('clang-3.6', os.path.join(LLVM_3_6, 'clang'), os.path.join(LLVM_3_6, 'clang++')),
#NativeBenchmarker(default_native_name, os.path.join(default_native, 'clang'), os.path.join(default_native, 'clang++')),
#NativeBenchmarker('clang-3.2-O3', os.path.join(default_native, 'clang'), os.path.join(default_native, 'clang++'), ['-O3']),
#NativeBenchmarker('clang-3.3', os.path.join(LLVM_3_3, 'clang'), os.path.join(LLVM_3_3, 'clang++')),
#NativeBenchmarker('clang-3.4', os.path.join(LLVM_3_4, 'clang'), os.path.join(LLVM_3_4, 'clang++')),

Просмотреть файл

@ -9,6 +9,8 @@ if emscripten_browser:
cmd = shlex.split(emscripten_browser)
def run_in_other_browser(url):
Popen(cmd + [url])
if EM_BUILD_VERBOSE_LEVEL >= 3:
print >> sys.stderr, "using Emscripten browser: " + str(cmd)
webbrowser.open_new = run_in_other_browser
def test_chunked_synchronous_xhr_server(support_byte_ranges, chunkSize, data, checksum):
@ -1936,6 +1938,10 @@ void *getBindBuffer() {
Popen([PYTHON, EMCC, path_from_root('tests', 'worker_api_3_worker.cpp'), '-o', 'worker.js', '-s', 'BUILD_AS_WORKER=1', '-s', 'EXPORTED_FUNCTIONS=["_one"]']).communicate()
self.btest('worker_api_3_main.cpp', expected='5')
def test_worker_api_sleep(self):
Popen([PYTHON, EMCC, path_from_root('tests', 'worker_api_worker_sleep.cpp'), '-o', 'worker.js', '-s', 'BUILD_AS_WORKER=1', '-s', 'EXPORTED_FUNCTIONS=["_one"]', '-s', 'EMTERPRETIFY=1', '-s', 'EMTERPRETIFY_ASYNC=1']).communicate()
self.btest('worker_api_main.cpp', expected='566')
def test_emscripten_async_wget2(self):
self.btest('http.cpp', expected='0', args=['-I' + path_from_root('tests')])

Просмотреть файл

@ -4794,6 +4794,22 @@ def process(filename):
Building.COMPILER_TEST_OPTS = orig_compiler_opts + ['-D' + fs]
self.do_run(src, expected, js_engines=[NODE_JS])
def test_unistd_symlink_on_nodefs(self):
self.clear()
if not self.is_emscripten_abi(): return self.skip('asmjs-unknown-emscripten needed for inline js')
orig_compiler_opts = Building.COMPILER_TEST_OPTS[:]
for fs in ['NODEFS']:
if WINDOWS and fs == 'NODEFS':
print >> sys.stderr, 'Skipping NODEFS part of this test for test_unistd_symlink_on_nodefs on Windows, since it would require administrative privileges.'
# Also, other detected discrepancies if you do end up running this test on NODEFS:
# test expects /, but Windows gives \ as path slashes.
# Calling readlink() on a non-link gives error 22 EINVAL on Unix, but simply error 0 OK on Windows.
continue
src = open(path_from_root('tests', 'unistd', 'symlink_on_nodefs.c'), 'r').read()
expected = open(path_from_root('tests', 'unistd', 'symlink_on_nodefs.out'), 'r').read()
Building.COMPILER_TEST_OPTS = orig_compiler_opts + ['-D' + fs]
self.do_run(src, expected, js_engines=[NODE_JS])
def test_unistd_sleep(self):
src = open(path_from_root('tests', 'unistd', 'sleep.c'), 'r').read()
expected = open(path_from_root('tests', 'unistd', 'sleep.out'), 'r').read()
@ -5554,10 +5570,18 @@ def process(filename):
Settings.CORRECT_SIGNS = 1
use_cmake_configure = WINDOWS
if use_cmake_configure:
make_args = []
configure = [PYTHON, path_from_root('emcmake'), 'cmake', '.', '-DBUILD_SHARED_LIBS=OFF']
else:
make_args = ['libz.a']
configure = ['sh', './configure']
self.do_run(open(path_from_root('tests', 'zlib', 'example.c'), 'r').read(),
open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(),
libraries=self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a']),
includes=[path_from_root('tests', 'zlib')],
libraries=self.get_library('zlib', os.path.join('libz.a'), make_args=make_args, configure=configure),
includes=[path_from_root('tests', 'zlib'), os.path.join(self.get_dir(), 'building', 'zlib')],
force_c=True)
def test_the_bullet(self): # Called thus so it runs late in the alphabetical cycle... it is long
@ -7367,15 +7391,16 @@ def make_run(fullname, name=-1, compiler=-1, embetter=0, quantum_size=0,
TT = type(fullname, (T,), dict(run_name = fullname, env = env))
def tearDown(self):
super(TT, self).tearDown()
try:
super(TT, self).tearDown()
finally:
for k, v in self.env.iteritems():
del os.environ[k]
for k, v in self.env.iteritems():
del os.environ[k]
# clear global changes to Building
Building.COMPILER_TEST_OPTS = []
Building.COMPILER = CLANG
Building.LLVM_OPTS = 0
# clear global changes to Building
Building.COMPILER_TEST_OPTS = []
Building.COMPILER = CLANG
Building.LLVM_OPTS = 0
TT.tearDown = tearDown

Просмотреть файл

@ -9,6 +9,8 @@ if emscripten_browser:
cmd = shlex.split(emscripten_browser)
def run_in_other_browser(url):
Popen(cmd + [url])
if EM_BUILD_VERBOSE_LEVEL >= 3:
print >> sys.stderr, "using Emscripten browser: " + str(cmd)
webbrowser.open_new = run_in_other_browser
class interactive(BrowserCore):

Просмотреть файл

@ -418,18 +418,18 @@ f.close()
try:
os.chdir(tempdirname)
verbose_level = int(os.getenv('EM_BUILD_VERBOSE')) if os.getenv('EM_BUILD_VERBOSE') != None else 0
# Run Cmake
if invoke_method == 'cmake':
# Test invoking cmake directly.
cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+path_from_root('cmake', 'Modules', 'Platform', 'Emscripten.cmake'),
'-DCMAKE_BUILD_TYPE=' + configuration, cmake_arguments[i], '-G', generator, cmakelistsdir]
env = tools.shared.Building.remove_sh_exe_from_path(os.environ)
else:
# Test invoking via 'emconfigure cmake'
cmd = [emconfigure, 'cmake', '-DCMAKE_BUILD_TYPE=' + configuration, cmake_arguments[i], '-G', generator, cmakelistsdir]
ret = Popen(cmd, stdout=None if verbose_level >= 2 else PIPE, stderr=None if verbose_level >= 1 else PIPE).communicate()
env = os.environ.copy()
ret = Popen(cmd, stdout=None if EM_BUILD_VERBOSE_LEVEL >= 2 else PIPE, stderr=None if EM_BUILD_VERBOSE_LEVEL >= 1 else PIPE, env=env).communicate()
if len(ret) > 1 and ret[1] != None and len(ret[1].strip()) > 0:
logging.error(ret[1]) # If there were any errors, print them directly to console for diagnostics.
if len(ret) > 1 and ret[1] != None and 'error' in ret[1].lower():
@ -442,9 +442,9 @@ f.close()
# Build
cmd = make
if verbose_level >= 3 and 'Ninja' not in generator:
if EM_BUILD_VERBOSE_LEVEL >= 3 and 'Ninja' not in generator:
cmd += ['VERBOSE=1']
ret = Popen(cmd, stdout=None if verbose_level >= 2 else PIPE).communicate()
ret = Popen(cmd, stdout=None if EM_BUILD_VERBOSE_LEVEL >= 2 else PIPE).communicate()
if len(ret) > 1 and ret[1] != None and len(ret[1].strip()) > 0:
logging.error(ret[1]) # If there were any errors, print them directly to console for diagnostics.
if len(ret) > 0 and ret[0] != None and 'error' in ret[0].lower() and not '0 error(s)' in ret[0].lower():
@ -1247,12 +1247,13 @@ int f() {
for engine in JS_ENGINES:
if engine == V8_ENGINE: continue # no stdin support in v8 shell
engine[0] = os.path.normpath(engine[0])
print >> sys.stderr, engine
# work around a bug in python's subprocess module
# (we'd use run_js() normally)
try_delete('out.txt')
if os.name == 'nt': # windows
os.system('type "in.txt" | {} >out.txt'.format(' '.join(make_js_command(exe, engine))))
os.system('type "in.txt" | {} >out.txt'.format(' '.join(make_js_command(os.path.normpath(exe), engine))))
else: # posix
os.system('cat in.txt | {} > out.txt'.format(' '.join(make_js_command(exe, engine))))
self.assertContained('abcdef\nghijkl\neof', open('out.txt').read())
@ -2016,6 +2017,8 @@ int f() {
['asm', 'eliminate', 'registerize', 'asmLastOpts', 'last']),
(path_from_root('tests', 'optimizer', 'simd.js'), open(path_from_root('tests', 'optimizer', 'simd-output.js')).read(),
['asm', 'eliminate']), # eliminate, just enough to trigger asm normalization/denormalization
(path_from_root('tests', 'optimizer', 'safeLabelSetting.js'), open(path_from_root('tests', 'optimizer', 'safeLabelSetting-output.js')).read(),
['asm', 'safeLabelSetting']), # eliminate, just enough to trigger asm normalization/denormalization
]:
print input, passes
@ -4606,6 +4609,13 @@ function _main() {
out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'emterpreter_advise_funcptr.cpp'), '-s', 'EMTERPRETIFY=1', '-s', 'EMTERPRETIFY_ASYNC=1', '-s', 'EMTERPRETIFY_ADVISE=1'], stdout=PIPE).communicate()
self.assertContained('-s EMTERPRETIFY_WHITELIST=\'["__Z4posti", "__Z5post2i", "__Z6middlev", "__Z7sleeperv", "__Z8recurserv", "_main"]\'', out)
self.assertNotContained('EMTERPRETIFY_YIELDLIST', out);
out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'emterpreter_advise_funcptr.cpp'), '-s', 'EMTERPRETIFY=1', '-s', 'EMTERPRETIFY_ASYNC=1', '-s', 'EMTERPRETIFY_ADVISE=1', '-s', 'EMTERPRETIFY_YIELDLIST=["__Z6middlev"]'], stdout=PIPE).communicate()
self.assertContained('-s EMTERPRETIFY_YIELDLIST=\'["__Z6middlev", "__Z7siblingii", "__Z7sleeperv", "__Z8recurserv", "_printf"]\'', out)
out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'emterpreter_advise_funcptr.cpp'), '-s', 'EMTERPRETIFY=1', '-s', 'EMTERPRETIFY_ASYNC=1', '-s', 'EMTERPRETIFY_ADVISE=1', '-s', 'EMTERPRETIFY_YIELDLIST=["__Z3pref"]'], stdout=PIPE).communicate()
self.assertContained('-s EMTERPRETIFY_YIELDLIST=\'["__Z3pref", "__Z7siblingii", "_printf"]\'', out)
def test_link_with_a_static(self):
for args in [[], ['-O2']]:

Просмотреть файл

@ -1,17 +1,17 @@
readlink(link)
ret: 17
ret: 7
errno: 0
result: ../test/../there!
result: /there!
readlink(file)
ret: -1
errno: 22
result: ../test/../there!
result: /there!
readlink(folder)
ret: -1
errno: 22
result: ../test/../there!
result: /there!
symlink/overwrite
ret: -1
@ -21,11 +21,11 @@ symlink/normal
ret: 0
errno: 0
readlink(created link)
ret: 20
ret: 36
errno: 0
result: new-nonexistent-path
result: /working/folder/new-nonexistent-path
readlink(short buffer)
ret: 3
errno: 0
result: ../-nonexistent-path
result: /thrking/folder/new-nonexistent-path

Просмотреть файл

@ -0,0 +1,57 @@
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <emscripten.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <limits.h>
#include <stdlib.h>
int main() {
EM_ASM(
fs.mkdirSync('./new-directory', '0777');
fs.writeFileSync('./new-directory/test', 'Link it');
fs.symlinkSync(fs.realpathSync('./new-directory'), './symlink');
FS.mkdir('working');
FS.mount(NODEFS, { root: '.' }, 'working');
FS.mkdir('direct-link');
FS.mount(NODEFS, { root: './symlink' }, 'direct-link');
);
{
char* path = "/working/symlink/test";
printf("reading %s\n", path);
FILE* fd = fopen(path, "r");
if (fd == NULL) {
printf("failed to open file %s\n", path);
}
else {
char buffer[8];
fread(buffer, 1, 7, fd);
printf("buffer is %s\n", buffer);
fclose(fd);
}
}
printf("\n");
{
char* path = "/direct-link/test";
printf("reading %s\n", path);
FILE* fd = fopen(path, "r");
if (fd != NULL) {
// This should not happen, it resolves to ../new-directory which is not mounted
printf("opened file %s\n", path);
fclose(fd);
}
else {
printf("failed to open file %s\n", path);
}
}
return 0;
}

Просмотреть файл

@ -0,0 +1,5 @@
reading /working/symlink/test
buffer is Link it
reading /direct-link/test
failed to open file /direct-link/test

Просмотреть файл

@ -0,0 +1,17 @@
#include <assert.h>
#include <emscripten.h>
extern "C" {
void one(char *data, int size) {
int *x = (int*)data;
int num = size/sizeof(int);
for (int i = 0; i < num; i++) {
x[i] += 1234;
}
emscripten_sleep(1000);
emscripten_worker_respond(data, size);
}
}

Просмотреть файл

@ -706,6 +706,8 @@ if __name__ == '__main__':
outfile = sys.argv[2]
force_memfile = sys.argv[3] if len(sys.argv) >= 4 else None
original_yieldlist = YIELDLIST
extra_blacklist = []
if len(sys.argv) >= 5:
temp = sys.argv[4]
@ -775,6 +777,23 @@ if __name__ == '__main__':
print "Suggested list of functions to run in the emterpreter:"
print " -s EMTERPRETIFY_WHITELIST='" + str(sorted(list(advised))).replace("'", '"') + "'"
print "(%d%% out of %d functions)" % (int((100.0*len(advised))/len(can_call)), len(can_call))
if len(YIELDLIST) > len(original_yieldlist):
# advise on the yield list as well. Anything a yield function can reach, likely needs to also be a yield function
YIELD_IGNORE = set(['abort'])
to_check = list(YIELDLIST)
advised = set([str(f) for f in YIELDLIST])
while len(to_check) > 0:
curr = to_check.pop()
if curr not in can_call: continue
for next in can_call[curr]:
if next not in advised:
advised.add(str(next))
to_check.append(next)
advised = [next for next in advised if not is_dyn_call(next) and not is_function_table(next) and not next in original_yieldlist and next not in SYNC_FUNCS and next not in YIELD_IGNORE and next[0] == '_']
print
print "Suggested list of yield functions for the emterpreter:"
print " -s EMTERPRETIFY_YIELDLIST='" + str(sorted(list(advised))).replace("'", '"') + "'"
print "(%d%% out of %d functions)" % (int((100.0*len(advised))/len(can_call)), len(can_call))
sys.exit(0)
BLACKLIST = set(list(BLACKLIST) + extra_blacklist)

Просмотреть файл

@ -1,3 +1,6 @@
// -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 ; js-indent-level : 2 ; js-curly-indent-offset: 0 -*-
// vim: set ts=2 et sw=2 tw=80:
//==============================================================================
// Optimizer tool. This is meant to be run after the emscripten compiler has
// finished generating code. These optimizations are done on the generated
@ -1090,7 +1093,7 @@ function safeLabelSetting(ast) {
seenVar = true;
} else if (seenVar && curr[0] !== 'var') {
// first location after the vars
stats.splice(i+1, 0, ['stat', ['assign', true, ['name', 'label'], ['num', 0]]]);
stats.splice(i, 0, ['stat', ['assign', true, ['name', 'label'], ['num', 0]]]);
break;
}
}
@ -6071,46 +6074,63 @@ function optimizeFrounds(ast) {
traverseChildren(ast, fix);
}
// Optimize heap expressions into HEAP32[(x&m)+c>>2] where c is a small aligned constant, and m guarantees the pointer is without range+aligned
// Optimize heap expressions into HEAP32[(x&m)+c>>2] where c is an aligned
// constant, and m guarantees the pointer is within bounds and aligned.
function pointerMasking(ast) {
var MAX_SMALL_OFFSET = 32;
var parseHeapTemp = makeTempParseHeap();
traverse(ast, function(node, type) {
if (type === 'sub' && node[1][0] === 'name' && node[1][1][0] === 'H' && node[2][0] === 'binary' && node[2][1] === '>>' && node[2][3][0] === 'num') {
var addee = node[2][2];
if (!(addee[0] === 'binary' && addee[1] === '+')) return;
var shifts = node[2][3][1];
if (!parseHeap(node[1][1])) return;
if (parseHeapTemp.bits !== 8*Math.pow(2, shifts)) return;
// this is an HEAP[U]N[x + y >> n] expression. gather up all the top-level added items, seek a small constant amongst them
var addee = node[2][2];
if (!parseHeap(node[1][1], parseHeapTemp)) return;
if (parseHeapTemp.bits !== 8 * Math.pow(2, shifts)) return;
// Don't mask a shifted constant index. It will be folded later,
// and it is assumed that they are within bounds.
if (addee[0] === 'num') return;
if (!(addee[0] === 'binary' && addee[1] === '+')) {
node[2][2] = ['binary', '&', addee, ['name', 'MASK' + shifts]];
return;
}
// This is a HEAP[U]N[x + y >> n] expression. Gather up all the top-level
// added items, summing constants amongst them.
var addedConstants = 0;
var addedElements = [];
function addElements(node) {
if (node[0] === 'binary' && node[1] === '+') {
addElements(node[2]);
addElements(node[3]);
} else if (node[0] === 'num') {
var c = node[1];
// Check that it is aligned.
if (((c >> shifts) << shifts) === c) {
addedConstants += c;
} else {
addedElements.push(node);
}
} else {
addedElements.push(node);
}
}
addElements(addee);
assert(addedElements.length >= 2);
for (var i = 0; i < addedElements.length; i++) {
var element = addedElements[i];
if (element[0] === 'num') {
var c = element[1];
if (c < MAX_SMALL_OFFSET && ((c >> shifts) << shifts) === c) {
// this is a small aligned offset, we are good to go. gather the others, and finalize
addedElements.splice(i, 1);
var others = addedElements[0];
for (var j = 1; j < addedElements.length; j++) {
others = ['binary', '+', others, addedElements[j]];
}
others = ['binary', '&', others, ['name', 'MASK' + shifts]];
node[2][2] = ['binary', '+', others, element];
return;
}
if (addedElements.length > 0) {
var others = addedElements[0];
for (var j = 1; j < addedElements.length; j++) {
others = ['binary', '+', others, addedElements[j]];
}
others = ['binary', '&', others, ['name', 'MASK' + shifts]];
if (addedConstants != 0) {
others = ['binary', '+', others, ['num' , addedConstants]];
}
node[2][2] = others;
return;
}
node[2][2] = ['num' , addedConstants];
}
});
}

Просмотреть файл

@ -263,8 +263,7 @@ def run_on_chunk(command):
while os.path.exists(saved): saved = 'input' + str(int(saved.replace('input', '').replace('.txt', ''))+1) + '.txt'
print >> sys.stderr, 'running js optimizer command', ' '.join(map(lambda c: c if c != filename else saved, command))
shutil.copyfile(filename, os.path.join('/tmp/emscripten_temp', saved))
verbose_level = int(os.getenv('EM_BUILD_VERBOSE')) if os.getenv('EM_BUILD_VERBOSE') != None else 0
if verbose_level >= 3: print >> sys.stderr, str(command)
if shared.EM_BUILD_VERBOSE_LEVEL >= 3: print >> sys.stderr, 'run_on_chunk: ' + str(command)
proc = subprocess.Popen(command, stdout=subprocess.PIPE)
output = proc.communicate()[0]
assert proc.returncode == 0, 'Error in optimizer: ' + output

Просмотреть файл

@ -1,6 +1,6 @@
import os, shutil, logging
TAG = 'version_5'
TAG = 'version_6'
def get_with_configure(ports, settings, shared): # not currently used; no real need for configure on emscripten users' machines!
if settings.USE_SDL == 2:

Просмотреть файл

@ -297,6 +297,13 @@ if EM_POPEN_WORKAROUND and os.name == 'nt':
logging.debug('Installing Popen workaround handler to avoid bug http://bugs.python.org/issue3905')
Popen = WindowsPopen
# Verbosity level control for any intermediate subprocess spawns from the compiler. Useful for internal debugging.
# 0: disabled.
# 1: Log stderr of subprocess spawns.
# 2: Log stdout and stderr of subprocess spawns. Print out subprocess commands that were executed.
# 3: Log stdout and stderr, and pass VERBOSE=1 to CMake configure steps.
EM_BUILD_VERBOSE_LEVEL = int(os.getenv('EM_BUILD_VERBOSE')) if os.getenv('EM_BUILD_VERBOSE') != None else 0
# Expectations
EXPECTED_LLVM_VERSION = (3, 6)
@ -1068,6 +1075,17 @@ class Building:
return None
# Returns a clone of the given environment with all directories that contain sh.exe removed from the PATH.
# Used to work around CMake limitation with MinGW Makefiles, where sh.exe is not allowed to be present.
@staticmethod
def remove_sh_exe_from_path(env):
env = env.copy()
if not WINDOWS: return env
path = env['PATH'].split(';')
path = filter(lambda p: not os.path.exists(os.path.join(p, 'sh.exe')), path)
env['PATH'] = ';'.join(path)
return env
@staticmethod
def handle_CMake_toolchain(args, env):
@ -1085,8 +1103,13 @@ class Building:
# pulling in a native Visual Studio, or Unix Makefiles.
if WINDOWS and not '-G' in args and Building.which('mingw32-make'):
args += ['-G', 'MinGW Makefiles']
return args
# CMake has a requirement that it wants sh.exe off PATH if MinGW Makefiles is being used. This happens quite often,
# so do this automatically on behalf of the user. See http://www.cmake.org/Wiki/CMake_MinGW_Compiler_Issues
if WINDOWS and 'MinGW Makefiles' in args:
env = Building.remove_sh_exe_from_path(env)
return (args, env)
@staticmethod
def configure(args, stdout=None, stderr=None, env=None):
@ -1097,13 +1120,14 @@ class Building:
if 'cmake' in args[0]:
# Note: EMMAKEN_JUST_CONFIGURE shall not be enabled when configuring with CMake. This is because CMake
# does expect to be able to do config-time builds with emcc.
args = Building.handle_CMake_toolchain(args, env)
args, env = Building.handle_CMake_toolchain(args, env)
else:
# When we configure via a ./configure script, don't do config-time compilation with emcc, but instead
# do builds natively with Clang. This is a heuristic emulation that may or may not work.
env['EMMAKEN_JUST_CONFIGURE'] = '1'
try:
process = Popen(args, stdout=stdout, stderr=stderr, env=env)
if EM_BUILD_VERBOSE_LEVEL >= 3: print >> sys.stderr, 'configure: ' + str(args)
process = Popen(args, stdout=None if EM_BUILD_VERBOSE_LEVEL >= 2 else stdout, stderr=None if EM_BUILD_VERBOSE_LEVEL >= 1 else stderr, env=env)
process.communicate()
except Exception, e:
logging.error('Exception thrown when invoking Popen in configure with args: "%s"!' % ' '.join(args))
@ -1123,13 +1147,19 @@ class Building:
#args += ['VERBOSE=1']
# On Windows prefer building with mingw32-make instead of make, if it exists.
if WINDOWS and args[0] == 'make':
mingw32_make = Building.which('mingw32-make')
if mingw32_make:
args[0] = mingw32_make
if WINDOWS:
if args[0] == 'make':
mingw32_make = Building.which('mingw32-make')
if mingw32_make:
args[0] = mingw32_make
if 'mingw32-make' in args[0]:
env = Building.remove_sh_exe_from_path(env)
try:
process = Popen(args, stdout=stdout, stderr=stderr, env=env)
# On Windows, run the execution through shell to get PATH expansion and executable extension lookup, e.g. 'sdl2-config' will match with 'sdl2-config.bat' in PATH.
if EM_BUILD_VERBOSE_LEVEL >= 3: print >> sys.stderr, 'make: ' + str(args)
process = Popen(args, stdout=None if EM_BUILD_VERBOSE_LEVEL >= 2 else stdout, stderr=None if EM_BUILD_VERBOSE_LEVEL >= 1 else stderr, env=env, shell=WINDOWS)
process.communicate()
except Exception, e:
logging.error('Exception thrown when invoking Popen in make with args: "%s"!' % ' '.join(args))
@ -1170,13 +1200,12 @@ class Building:
# except:
# pass
env = Building.get_building_env(native)
verbose_level = int(os.getenv('EM_BUILD_VERBOSE')) if os.getenv('EM_BUILD_VERBOSE') != None else 0
for k, v in env_init.iteritems():
env[k] = v
if configure: # Useful in debugging sometimes to comment this out (and the lines below up to and including the |link| call)
try:
Building.configure(configure + configure_args, env=env, stdout=open(os.path.join(project_dir, 'configure_'), 'w') if verbose_level < 2 else None,
stderr=open(os.path.join(project_dir, 'configure_err'), 'w') if verbose_level < 1 else None)
Building.configure(configure + configure_args, env=env, stdout=open(os.path.join(project_dir, 'configure_'), 'w') if EM_BUILD_VERBOSE_LEVEL < 2 else None,
stderr=open(os.path.join(project_dir, 'configure_err'), 'w') if EM_BUILD_VERBOSE_LEVEL < 1 else None)
except subprocess.CalledProcessError, e:
pass # Ignore exit code != 0
def open_make_out(i, mode='r'):
@ -1185,15 +1214,15 @@ class Building:
def open_make_err(i, mode='r'):
return open(os.path.join(project_dir, 'make_err' + str(i)), mode)
if verbose_level >= 3:
if EM_BUILD_VERBOSE_LEVEL >= 3:
make_args += ['VERBOSE=1']
for i in range(2): # FIXME: Sad workaround for some build systems that need to be run twice to succeed (e.g. poppler)
with open_make_out(i, 'w') as make_out:
with open_make_err(i, 'w') as make_err:
try:
Building.make(make + make_args, stdout=make_out if verbose_level < 2 else None,
stderr=make_err if verbose_level < 1 else None, env=env)
Building.make(make + make_args, stdout=make_out if EM_BUILD_VERBOSE_LEVEL < 2 else None,
stderr=make_err if EM_BUILD_VERBOSE_LEVEL < 1 else None, env=env)
except subprocess.CalledProcessError, e:
pass # Ignore exit code != 0
try:
@ -1205,7 +1234,7 @@ class Building:
break
except Exception, e:
if i > 0:
if verbose_level == 0:
if EM_BUILD_VERBOSE_LEVEL == 0:
# Due to the ugly hack above our best guess is to output the first run
with open_make_err(0) as ferr:
for line in ferr: