diff options
-rwxr-xr-x | emcc | 3 | ||||
-rw-r--r-- | src/analyzer.js | 33 | ||||
-rw-r--r-- | src/library.js | 44 | ||||
-rw-r--r-- | src/library_browser.js | 4 | ||||
-rw-r--r-- | src/library_sdl.js | 18 | ||||
-rw-r--r-- | src/preamble.js | 43 | ||||
-rw-r--r-- | src/runtime.js | 45 | ||||
-rw-r--r-- | src/settings.js | 2 | ||||
-rw-r--r-- | system/include/emscripten/emscripten.h | 6 | ||||
-rw-r--r-- | system/lib/libcxx/locale.cpp | 8 | ||||
-rw-r--r-- | tests/cases/514.ll | 56 | ||||
-rw-r--r-- | tests/cases/514.txt | 1 | ||||
-rwxr-xr-x | tests/runner.py | 100 | ||||
-rw-r--r-- | tools/file_packager.py | 4 | ||||
-rw-r--r-- | tools/shared.py | 24 |
15 files changed, 315 insertions, 76 deletions
@@ -542,7 +542,8 @@ try: input_files = [] has_source_inputs = False - lib_dirs = [shared.path_from_root('system', 'lib')] + lib_dirs = [shared.path_from_root('system', 'local', 'lib'), + shared.path_from_root('system', 'lib')] libs = [] for i in range(len(newargs)): # find input files XXX this a simple heuristic. we should really analyze based on a full understanding of gcc params, # right now we just assume that what is left contains no more |-x OPT| things diff --git a/src/analyzer.js b/src/analyzer.js index 4bf2255e..163ff4a8 100644 --- a/src/analyzer.js +++ b/src/analyzer.js @@ -253,6 +253,7 @@ function analyzer(data, sidePass) { } // This is an illegal-containing line, and it is unfolded. Legalize it now dprint('legalizer', 'Legalizing ' + item.intertype + ' at line ' + item.lineNum); + var finalizer = null; switch (item.intertype) { case 'store': { var toAdd = []; @@ -486,12 +487,13 @@ function analyzer(data, sidePass) { }; break; } - case 'or': case 'and': case 'xor': { + case 'or': case 'and': case 'xor': case 'icmp': { var otherElements = getLegalVars(value.params[1].ident, sourceBits); processor = function(result, j) { return { intertype: 'mathop', op: value.op, + variant: value.variant, type: 'i' + otherElements[j].bits, params: [ result, @@ -499,10 +501,35 @@ function analyzer(data, sidePass) { ] }; }; + if (value.op == 'icmp') { + if (sourceBits == 64) { // handle the i64 case in processMathOp, where we handle full i64 math + i++; + continue; + } + finalizer = function() { + var ident = ''; + for (var i = 0; i < targetElements.length; i++) { + if (i > 0) { + switch(value.variant) { + case 'eq': ident += '&&'; break; + case 'ne': ident += '||'; break; + default: throw 'unhandleable illegal icmp: ' + value.variant; + } + } + ident += targetElements[i].ident; + } + return { + intertype: 'value', + ident: ident, + type: 'rawJS', + assignTo: item.assignTo + }; + } + } break; } case 'add': case 'sub': case 'sdiv': case 'udiv': case 'mul': case 'urem': case 'srem': - case 'icmp':case 'uitofp': case 'sitofp': { + case 'uitofp': case 'sitofp': { // We cannot do these in parallel chunks of 32-bit operations. We will handle these in processMathop i++; continue; @@ -611,6 +638,8 @@ function analyzer(data, sidePass) { }; legalValue.assignTo = item.assignTo; toAdd.push(legalValue); + } else if (finalizer) { + toAdd.push(finalizer()); } i += removeAndAdd(label.lines, i, toAdd); continue; diff --git a/src/library.js b/src/library.js index bb73c48a..d1ede6bc 100644 --- a/src/library.js +++ b/src/library.js @@ -367,12 +367,13 @@ LibraryManager.library = { return input.cache.shift(); }; } + var utf8 = new Runtime.UTF8Processor(); function simpleOutput(val) { if (val === null || val === '\n'.charCodeAt(0)) { output.printer(output.buffer.join('')); output.buffer = []; } else { - output.buffer.push(String.fromCharCode(val)); + output.buffer.push(utf8.processCChar(val)); } } if (!output) { @@ -2281,6 +2282,14 @@ LibraryManager.library = { var fields = 0; var argIndex = 0; var next; + // remove initial whitespace + while (1) { + next = get(); + if (next == 0) return 0; + if (!(next in __scanString.whiteSpace)) break; + } + unget(next); + next = 1; for (var formatIndex = 0; formatIndex < format.length; formatIndex++) { if (next <= 0) return fields; var next = get(); @@ -2319,11 +2328,10 @@ LibraryManager.library = { } next = get(); } + unget(next); while (buffer.length > last) { - buffer.pop(); - unget(); + unget(buffer.pop().charCodeAt(0)); } - unget(); next = get(); } else { var first = true; @@ -2380,7 +2388,7 @@ LibraryManager.library = { next = get(); if (next <= 0) return fields; // End of input. } - unget(); + unget(next); } else { // Not a specifier. if (format[formatIndex].charCodeAt(0) !== next) { @@ -4519,33 +4527,11 @@ LibraryManager.library = { }, llvm_bswap_i16: function(x) { - x = unSign(x, 32); - var bytes = []; - bytes[0] = x & 255; - x >>= 8; - bytes[1] = x & 255; - x >>= 8; - var ret = 0; - ret <<= 8; - ret += bytes[0]; - ret <<= 8; - ret += bytes[1]; - return ret; + return ((x&0xff)<<8) | ((x>>8)&0xff); }, llvm_bswap_i32: function(x) { - x = unSign(x, 32); - var bytes = []; - for (var i = 0; i < 4; i++) { - bytes[i] = x & 255; - x >>= 8; - } - var ret = 0; - for (i = 0; i < 4; i++) { - ret <<= 8; - ret += bytes[i]; - } - return ret; + return ((x&0xff)<<24) | (((x>>8)&0xff)<<16) | (((x>>16)&0xff)<<8) | (x>>>24); }, llvm_ctlz_i32: function(x) { diff --git a/src/library_browser.js b/src/library_browser.js index 4c26037e..ce59dbdd 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -223,7 +223,8 @@ mergeInto(LibraryManager.library, { var wrapper = function() { if (Browser.mainLoop.queue.length > 0) { Browser.mainLoop.queue.shift()(); - Browser.mainLoop.scheduler(); + if (Browser.mainLoop.queue.length == 0 && Module['setStatus']) Module['setStatus'](''); + setTimeout(wrapper, 0); return; } if (Browser.mainLoop.shouldPause) { @@ -267,6 +268,7 @@ mergeInto(LibraryManager.library, { }, emscripten_push_main_loop_blocker: function(func) { + if (Module['setStatus']) Module['setStatus']('Please wait..'); Browser.mainLoop.queue.push(FUNCTION_TABLE[func]); }, diff --git a/src/library_sdl.js b/src/library_sdl.js index 48e45f27..662620d6 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -28,6 +28,9 @@ var LibrarySDL = { mixerNumChannels: 2, mixerChunkSize: 1024, + GL: false, // Set to true if we call SDL_SetVideoMode with SDL_OPENGL, and if so, we do not create 2D canvases&contexts for blitting + // Note that images loaded before SDL_SetVideoMode will not get this optimization + keyboardState: null, shiftKey: false, ctrlKey: false, @@ -263,6 +266,7 @@ var LibrarySDL = { // Decide if we want to use WebGL or not var useWebGL = (flags & 0x04000000) != 0; // SDL_OPENGL + SDL.GL = SDL.GL || useWebGL; var canvas; if (!usePageCanvas) { canvas = document.createElement('canvas'); @@ -695,6 +699,8 @@ var LibrarySDL = { // Copy data from the C++-accessible storage to the canvas backing SDL_UnlockSurface: function(surf) { + assert(!SDL.GL); // in GL mode we do not keep around 2D canvases and contexts + var surfData = SDL.surfaces[surf]; surfData.locked--; @@ -977,9 +983,13 @@ var LibrarySDL = { } var raw = Module["preloadedImages"][filename]; if (!raw) { + if (raw === null) Module.printErr('Trying to reuse preloaded image, but freePreloadedMediaOnUse is set!'); Runtime.warnOnce('Cannot find preloaded image ' + filename); return 0; } + if (Module['freePreloadedMediaOnUse']) { + Module["preloadedImages"][filename] = null; + } var surf = SDL.makeSurface(raw.width, raw.height, 0, false, 'load:' + filename); var surfData = SDL.surfaces[surf]; surfData.ctx.drawImage(raw, 0, 0, raw.width, raw.height, 0, 0, raw.width, raw.height); @@ -989,6 +999,10 @@ var LibrarySDL = { // are in fact available, so we retrieve it here. This does add overhead though. _SDL_LockSurface(surf); surfData.locked--; // The surface is not actually locked in this hack + if (SDL.GL) { + // After getting the pixel data, we can free the canvas and context if we do not need to do 2D canvas blitting + surfData.canvas = surfData.ctx = null; + } return surf; }, SDL_LoadBMP: 'IMG_Load', @@ -1110,9 +1124,13 @@ var LibrarySDL = { filename = FS.standardizePath(Pointer_stringify(filename)); var raw = Module["preloadedAudios"][filename]; if (!raw) { + if (raw === null) Module.printErr('Trying to reuse preloaded audio, but freePreloadedMediaOnUse is set!'); Runtime.warnOnce('Cannot find preloaded audio ' + filename); return 0; } + if (Module['freePreloadedMediaOnUse']) { + Module["preloadedAudios"][filename] = null; + } var id = SDL.audios.length; SDL.audios.push({ source: filename, diff --git a/src/preamble.js b/src/preamble.js index ae00b796..5c5e64fc 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -513,17 +513,17 @@ function allocate(slab, types, allocator) { Module['allocate'] = allocate; function Pointer_stringify(ptr, /* optional */ length) { + var utf8 = new Runtime.UTF8Processor(); var nullTerminated = typeof(length) == "undefined"; var ret = ""; var i = 0; var t; - var nullByte = String.fromCharCode(0); while (1) { - t = String.fromCharCode({{{ makeGetValue('ptr', 'i', 'i8', 0, 1) }}}); - if (nullTerminated && t == nullByte) { break; } else {} - ret += t; + t = {{{ makeGetValue('ptr', 'i', 'i8', 0, 1) }}}; + if (nullTerminated && t == 0) break; + ret += utf8.processCChar(t); i += 1; - if (!nullTerminated && i == length) { break; } + if (!nullTerminated && i == length) break; } return ret; } @@ -734,22 +734,9 @@ Module['String_len'] = String_len; // This processes a JS string into a C-line array of numbers, 0-terminated. // For LLVM-originating strings, see parser.js:parseLLVMString function function intArrayFromString(stringy, dontAddNull, length /* optional */) { - var ret = []; - var t; - var i = 0; - if (length === undefined) { - length = stringy.length; - } - while (i < length) { - var chr = stringy.charCodeAt(i); - if (chr > 0xFF) { -#if ASSERTIONS - assert(false, 'Character code ' + chr + ' (' + stringy[i] + ') at offset ' + i + ' not in 0x00-0xFF.'); -#endif - chr &= 0xFF; - } - ret.push(chr); - i = i + 1; + var ret = (new Runtime.UTF8Processor()).processJSString(stringy); + if (length) { + ret.length = length; } if (!dontAddNull) { ret.push(0); @@ -776,21 +763,13 @@ Module['intArrayToString'] = intArrayToString; // Write a Javascript array to somewhere in the heap function writeStringToMemory(string, buffer, dontAddNull) { + var array = intArrayFromString(string, dontAddNull); var i = 0; - while (i < string.length) { - var chr = string.charCodeAt(i); - if (chr > 0xFF) { -#if ASSERTIONS - assert(false, 'Character code ' + chr + ' (' + string[i] + ') at offset ' + i + ' not in 0x00-0xFF.'); -#endif - chr &= 0xFF; - } + while (i < array.length) { + var chr = array[i]; {{{ makeSetValue('buffer', 'i', 'chr', 'i8') }}} i = i + 1; } - if (!dontAddNull) { - {{{ makeSetValue('buffer', 'i', '0', 'i8') }}} - } } Module['writeStringToMemory'] = writeStringToMemory; diff --git a/src/runtime.js b/src/runtime.js index 1f8a618f..6defbb35 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -334,6 +334,51 @@ var Runtime = { return Runtime.funcWrappers[func]; }, + // Returns a processor of UTF. + // processCChar() receives characters from a C-like UTF representation and returns JS string fragments. + // processJSString() receives a JS string and returns a C-like UTF representation in an array + UTF8Processor: function() { + var buffer = []; + var needed = 0; + this.processCChar = function (code) { + code = code & 0xff; + if (needed) { + buffer.push(code); + needed--; + } + if (buffer.length == 0) { + if (code < 128) return String.fromCharCode(code); + buffer.push(code); + if (code > 191 && code < 224) { + needed = 1; + } else { + needed = 2; + } + return ''; + } + if (needed > 0) return ''; + var c1 = buffer[0]; + var c2 = buffer[1]; + var c3 = buffer[2]; + var ret; + if (c1 > 191 && c1 < 224) { + ret = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63)); + } else { + ret = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + } + buffer.length = 0; + return ret; + } + this.processJSString = function(string) { + string = unescape(encodeURIComponent(string)); + var ret = []; + for (var i = 0; i < string.length; i++) { + ret.push(string.charCodeAt(i)); + } + return ret; + } + }, + #if RUNTIME_DEBUG debug: true, // Switch to false at runtime to disable logging at the right times diff --git a/src/settings.js b/src/settings.js index 2526081b..16c28529 100644 --- a/src/settings.js +++ b/src/settings.js @@ -639,7 +639,7 @@ var C_DEFINES = {'SI_MESGQ': '5', 'SING': '2', 'M_INVLN2': '1.44269504089', 'SDL_TIMERS_DISABLED': '1', - 'M_TWOPI': '3.14159265359', + 'M_TWOPI': '6.28318530718', '_PC_REC_XFER_ALIGN': '19', '_NL_TIME_DATE_FMT': '84', '_SC_REALTIME_SIGNALS': '29', diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h index 575c3e2a..9bc6c410 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -52,7 +52,13 @@ extern void emscripten_cancel_main_loop(); * Add a function to a queue of events that will execute * before the main loop will continue. */ +#if EMSCRIPTEN extern void emscripten_push_main_loop_blocker(void (*func)()); +#else +inline void emscripten_push_main_loop_blocker(void (*func)()) { + func(); +} +#endif /* * Call a C function asynchronously, that is, after returning diff --git a/system/lib/libcxx/locale.cpp b/system/lib/libcxx/locale.cpp index 4675fec3..87c47636 100644 --- a/system/lib/libcxx/locale.cpp +++ b/system/lib/libcxx/locale.cpp @@ -1418,10 +1418,10 @@ codecvt<wchar_t, char, mbstate_t>::do_in(state_type& st, case 0: ++frm; break; - case -1: + case static_cast<size_t>(-1): // XXX EMSCRIPTEN frm_nxt = frm; return error; - case -2: + case static_cast<size_t>(-2): // XXX EMSCRIPTEN frm_nxt = frm; return partial; default: @@ -1524,8 +1524,8 @@ codecvt<wchar_t, char, mbstate_t>::do_length(state_type& st, ++nbytes; ++frm; break; - case -1: - case -2: + case static_cast<size_t>(-1): // XXX EMSCRIPTEN + case static_cast<size_t>(-2): // XXX EMSCRIPTEN return nbytes; default: nbytes += n; diff --git a/tests/cases/514.ll b/tests/cases/514.ll new file mode 100644 index 00000000..ae60191c --- /dev/null +++ b/tests/cases/514.ll @@ -0,0 +1,56 @@ +; ModuleID = '/tmp/tmpxFUbAg/test_emcc1.bc' +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S128" +target triple = "i386-pc-linux-gnu" + +%struct.c_s = type { i8, float, i32 } + +@.str = private unnamed_addr constant [12 x i8] c"RESULT: %d\0A\00", align 1 + +define internal fastcc void @f2(%struct.c_s* noalias nocapture sret %agg.result) nounwind { + %agg.result.1 = getelementptr inbounds %struct.c_s* %agg.result, i32 0, i32 1 + store float 0.000000e+00, float* %agg.result.1, align 4 + %agg.result.2 = getelementptr inbounds %struct.c_s* %agg.result, i32 0, i32 2 + store i32 43110, i32* %agg.result.2, align 4 + ret void +} + +define internal fastcc void @f1(%struct.c_s* nocapture %tp) nounwind { + %1 = alloca %struct.c_s, align 8 + call fastcc void @f2(%struct.c_s* sret %1) + %2 = bitcast %struct.c_s* %1 to i96* + %srcval1 = load i96* %2, align 8 + %3 = and i96 %srcval1, 255 + %4 = icmp eq i96 %3, 0 + br i1 %4, label %5, label %12 + +; <label>:5 ; preds = %0 + %6 = lshr i96 %srcval1, 32 + %7 = trunc i96 %6 to i32 + %8 = bitcast i32 %7 to float + %9 = getelementptr inbounds %struct.c_s* %tp, i32 0, i32 1 + %10 = load float* %9, align 4 + %11 = fcmp olt float %8, %10 + br i1 %11, label %12, label %14 + +; <label>:12 ; preds = %5, %0 + %13 = bitcast %struct.c_s* %tp to i96* + store i96 %srcval1, i96* %13, align 4 + br label %14 + +; <label>:14 ; preds = %12, %5 + ret void +} + +define i32 @main() nounwind { + %t = alloca %struct.c_s, align 4 + %1 = getelementptr inbounds %struct.c_s* %t, i32 0, i32 1 + store float 1.000000e+00, float* %1, align 4 + call fastcc void @f1(%struct.c_s* %t) + %2 = getelementptr inbounds %struct.c_s* %t, i32 0, i32 2 + %3 = load i32* %2, align 4 + %4 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([12 x i8]* @.str, i32 0, i32 0), i32 %3) nounwind + ret i32 0 +} + +declare i32 @printf(i8* nocapture, ...) nounwind + diff --git a/tests/cases/514.txt b/tests/cases/514.txt new file mode 100644 index 00000000..68ab318c --- /dev/null +++ b/tests/cases/514.txt @@ -0,0 +1 @@ +RESULT: 43110 diff --git a/tests/runner.py b/tests/runner.py index d10a7c40..7085f5f9 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# This Python file uses the following encoding: utf-8 ''' Simple test runner @@ -14,7 +15,7 @@ will use 4 processes. To install nose do something like ''' from subprocess import Popen, PIPE, STDOUT -import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, tempfile, re, difflib, webbrowser, hashlib, threading, platform, BaseHTTPServer, multiprocessing, functools +import os, unittest, tempfile, shutil, time, inspect, sys, math, glob, tempfile, re, difflib, webbrowser, hashlib, threading, platform, BaseHTTPServer, multiprocessing, functools, stat if len(sys.argv) == 1: @@ -296,7 +297,7 @@ process(sys.argv[1]) os.makedirs(ret) return ret - def get_library(self, name, generated_libs, configure=['sh', './configure'], configure_args=[], make=['make'], make_args=['-j', '2'], cache=True): + def get_library(self, name, generated_libs, configure=['sh', './configure'], configure_args=[], make=['make'], make_args=['-j', '2'], cache=True, env_init={}): build_dir = self.get_build_dir() output_dir = self.get_dir() @@ -316,7 +317,7 @@ process(sys.argv[1]) print >> sys.stderr, '<building and saving into cache> ', return Building.build_library(name, build_dir, output_dir, generated_libs, configure, configure_args, make, make_args, self.library_cache, cache_name, - copy_project=True) + copy_project=True, env_init=env_init) def clear(self): for name in os.listdir(self.get_dir()): @@ -977,6 +978,36 @@ m_divisor is 1091269979 ''' self.do_run(src, ',0,,2,C!,0,C!,0,,65535,C!,0,') + def test_bswap(self): + if self.emcc_args == None: return self.skip('needs ta2') + + src = r''' + #include <stdio.h> + + extern "C" { + extern unsigned short llvm_bswap_i16(unsigned short x); + extern unsigned int llvm_bswap_i32(unsigned int x); + } + + int main(void) { + unsigned short x = 0xc8ef; + printf("%x,%x\n", x&0xff, x >> 8); + x = llvm_bswap_i16(x); + printf("%x,%x\n", x&0xff, x >> 8); + + unsigned int y = 0xc5de158a; + printf("%x,%x,%x,%x\n", y&0xff, (y>>8)&0xff, (y>>16)&0xff, (y>>24)&0xff); + y = llvm_bswap_i32(y); + printf("%x,%x,%x,%x\n", y&0xff, (y>>8)&0xff, (y>>16)&0xff, (y>>24)&0xff); + return 0; + } + ''' + self.do_run(src, '''ef,c8 +c8,ef +8a,15,de,c5 +c5,de,15,8a +''') + def test_sha1(self): if self.emcc_args == None: return self.skip('needs ta2') @@ -3969,6 +4000,10 @@ at function.:blag printf("%f, %f\n", atof("1.234567"), atof("cheez")); + float n = -1; + sscanf(" 2.8208", "%f", &n); + printf("%.4f\n", n); + float a = -1; sscanf("-3.03", "%f", &a); printf("%.4f\n", a); @@ -3998,7 +4033,7 @@ at function.:blag return 0; } ''' - self.do_run(src, 'en-us : 2\nen-r : 99\nen : 3\n1.234567, 0.000000\n-3.0300\n|some|\n|something|\n|somethingmoar|\n' + + self.do_run(src, 'en-us : 2\nen-r : 99\nen : 3\n1.234567, 0.000000\n2.8208\n-3.0300\n|some|\n|something|\n|somethingmoar|\n' + '1\n1499\n' + '5\n87,0.481565,0.059481,0,1\n' + '3\n-123,4294966531,-34\n') @@ -4478,6 +4513,22 @@ def process(filename): ''' self.do_run(src, re.sub('(^|\n)\s+', '\\1', expected), post_build=add_pre_run_and_checks) + def test_utf(self): + self.banned_js_engines = [SPIDERMONKEY_ENGINE] # only node handles utf well + src = r''' + #include <stdio.h> + #include <emscripten.h> + + int main() { + char *c = "μ†ℱ ╋ℯ╳╋"; + printf("%d %d %d %d %s\n", c[0]&0xff, c[1]&0xff, c[2]&0xff, c[3]&0xff, c); + emscripten_run_script("cheez = Module._malloc(100);" + "Module.writeStringToMemory(\"μ†ℱ ╋ℯ╳╋\", cheez);" + "Module.print([Pointer_stringify(cheez), Module.getValue(cheez, 'i8')&0xff, Module.getValue(cheez+1, 'i8')&0xff, Module.getValue(cheez+2, 'i8')&0xff, Module.getValue(cheez+3, 'i8')&0xff, ]);"); + } + ''' + self.do_run(src, '206 188 226 128 μ†ℱ ╋ℯ╳╋\nμ†ℱ ╋ℯ╳╋,206,188,226,128\n'); + def test_direct_string_constant_usage(self): if self.emcc_args is None: return self.skip('requires libcxx') @@ -5274,6 +5325,7 @@ def process(filename): [os.path.join('utils', 'pdftoppm.o'), os.path.join('utils', 'parseargs.o'), os.path.join('poppler', '.libs', 'libpoppler.a')], + env_init={ 'FONTCONFIG_CFLAGS': ' ', 'FONTCONFIG_LIBS': ' ' }, configure_args=['--disable-libjpeg', '--disable-libpng', '--disable-poppler-qt', '--disable-poppler-qt4', '--disable-cms', '--disable-cairo-output', '--disable-abiword-output', '--enable-shared=no']) # Combine libraries @@ -5305,7 +5357,7 @@ def process(filename): )) ).replace( '// {{POST_RUN_ADDITIONS}}', - "Module.print('Data: ' + JSON.stringify(FS.root.contents['image.raw'].contents));" + "Module.print('Data: ' + JSON.stringify(FS.analyzePath('image.raw').object.contents));" ) open(filename, 'w').write(src) ''' @@ -8403,6 +8455,44 @@ elif 'sanity' in str(sys.argv): output = self.check_working([EMCC, '-O2', 'tests/hello_world.cpp'], '') assert os.path.exists('a.out.js') + def test_llvm(self): + LLVM_WARNING = 'warning: LLVM version appears incorrect' + + restore() + + # Clang should report the version number we expect, and emcc should not warn + assert ('clang version ' + '.'.join(map(str, EXPECTED_LLVM_VERSION))) in Popen([CLANG, '-v'], stderr=PIPE).communicate()[1] + output = self.check_working(EMCC) + assert LLVM_WARNING not in output, output + + # Fake a different llvm version + restore() + f = open(CONFIG_FILE, 'a') + f.write('LLVM_ROOT = "' + path_from_root('tests', 'fake') + '"') + f.close() + + if not os.path.exists(path_from_root('tests', 'fake')): + os.makedirs(path_from_root('tests', 'fake')) + + try: + os.environ['EM_IGNORE_SANITY'] = '1' + for x in range(-2, 3): + for y in range(-2, 3): + f = open(path_from_root('tests', 'fake', 'clang'), 'w') + f.write('#!/bin/sh\n') + f.write('echo "clang version %d.%d" 1>&2\n' % (EXPECTED_LLVM_VERSION[0] + x, EXPECTED_LLVM_VERSION[1] + y)) + f.close() + shutil.copyfile(path_from_root('tests', 'fake', 'clang'), path_from_root('tests', 'fake', 'clang++')) + os.chmod(path_from_root('tests', 'fake', 'clang'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) + os.chmod(path_from_root('tests', 'fake', 'clang++'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) + if x != 0 or y != 0: + output = self.check_working(EMCC, LLVM_WARNING) + else: + output = self.check_working(EMCC) + assert LLVM_WARNING not in output, output + finally: + del os.environ['EM_IGNORE_SANITY'] + def test_emcc(self): SANITY_MESSAGE = 'Emscripten: Running sanity checks' SANITY_FAIL_MESSAGE = 'sanity check failed to run' diff --git a/tools/file_packager.py b/tools/file_packager.py index 3844b4ae..8c1e0a43 100644 --- a/tools/file_packager.py +++ b/tools/file_packager.py @@ -182,6 +182,10 @@ if crunch: except: format = [] Popen([CRUNCH, '-file', file_['name'], '-quality', crunch] + format, stdout=sys.stderr).communicate() + #if not os.path.exists(os.path.basename(crunch_name)): + # print >> sys.stderr, 'Failed to crunch, perhaps a weird dxt format? Looking for a source PNG for the DDS' + # Popen([CRUNCH, '-file', unsuffixed(file_['name']) + '.png', '-quality', crunch] + format, stdout=sys.stderr).communicate() + assert os.path.exists(os.path.basename(crunch_name)), 'crunch failed to generate output' shutil.move(os.path.basename(crunch_name), crunch_name) # crunch places files in the current dir # prepend the dds header crunched = open(crunch_name, 'rb').read() diff --git a/tools/shared.py b/tools/shared.py index 997c0ad9..4ab54273 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -43,12 +43,31 @@ except Exception, e: print >> sys.stderr, 'Error in evaluating %s (at %s): %s, text: %s' % (EM_CONFIG, CONFIG_FILE, str(e), config_text) sys.exit(1) +# Expectations + +EXPECTED_LLVM_VERSION = (3,1) + +def check_llvm_version(): + try: + expected = 'clang version ' + '.'.join(map(str, EXPECTED_LLVM_VERSION)) + actual = Popen([CLANG, '-v'], stderr=PIPE).communicate()[1].split('\n')[0][0:len(expected)] + if expected != actual: + print >> sys.stderr, 'warning: LLVM version appears incorrect (seeing "%s", expected "%s")' % (actual, expected) + except Exception, e: + print >> sys.stderr, 'warning: Could not verify LLVM version: %s' % str(e) + # Check that basic stuff we need (a JS engine to compile, Node.js, and Clang and LLVM) # exists. # The test runner always does this check (through |force|). emcc does this less frequently, # only when ${EM_CONFIG}_sanity does not exist or is older than EM_CONFIG (so, # we re-check sanity when the settings are changed) def check_sanity(force=False): + check_llvm_version() # just a warning, not a fatal check - do it even if EM_IGNORE_SANITY is on + + if os.environ.get('EM_IGNORE_SANITY'): + print >> sys.stderr, 'EM_IGNORE_SANITY set, ignoring sanity checks' + return + try: if not force: if not CONFIG_FILE: @@ -200,6 +219,7 @@ if USE_EMSDK: # allows projects to override them) # Note that -nostdinc++ is not needed, since -nostdinc implies that! EMSDK_OPTS = ['-nostdinc', '-Xclang', '-nobuiltininc', '-Xclang', '-nostdsysteminc', + '-Xclang', '-isystem' + path_from_root('system', 'local', 'include'), '-Xclang', '-isystem' + path_from_root('system', 'include'), '-Xclang', '-isystem' + path_from_root('system', 'include', 'emscripten'), '-Xclang', '-isystem' + path_from_root('system', 'include', 'bsd'), # posix stuff @@ -424,7 +444,7 @@ class Building: env['CXX'] = EMXX if not WINDOWS else 'python %r' % EMXX env['AR'] = EMAR if not WINDOWS else 'python %r' % EMAR env['RANLIB'] = EMRANLIB if not WINDOWS else 'python %r' % EMRANLIB - env['LIBTOOL'] = EMLIBTOOL if not WINDOWS else 'python %r' % EMLIBTOOL + #env['LIBTOOL'] = EMLIBTOOL if not WINDOWS else 'python %r' % EMLIBTOOL env['EMMAKEN_COMPILER'] = Building.COMPILER env['EMSCRIPTEN_TOOLS'] = path_from_root('tools') env['CFLAGS'] = env['EMMAKEN_CFLAGS'] = ' '.join(Building.COMPILER_TEST_OPTS) @@ -432,6 +452,8 @@ class Building: env['HOST_CXX'] = CLANG_CPP env['HOST_CFLAGS'] = "-W" #if set to nothing, CFLAGS is used, which we don't want env['HOST_CXXFLAGS'] = "-W" #if set to nothing, CXXFLAGS is used, which we don't want + env['PKG_CONFIG_LIBDIR'] = path_from_root('system', 'local', 'lib', 'pkgconfig') + os.path.pathsep + path_from_root('system', 'lib', 'pkgconfig') + env['PKG_CONFIG_PATH'] = os.environ.get ('EM_PKG_CONFIG_PATH') or '' return env @staticmethod |