aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xemcc3
-rw-r--r--src/analyzer.js33
-rw-r--r--src/library.js44
-rw-r--r--src/library_browser.js4
-rw-r--r--src/library_sdl.js18
-rw-r--r--src/preamble.js43
-rw-r--r--src/runtime.js45
-rw-r--r--src/settings.js2
-rw-r--r--system/include/emscripten/emscripten.h6
-rw-r--r--system/lib/libcxx/locale.cpp8
-rw-r--r--tests/cases/514.ll56
-rw-r--r--tests/cases/514.txt1
-rwxr-xr-xtests/runner.py100
-rw-r--r--tools/file_packager.py4
-rw-r--r--tools/shared.py24
15 files changed, 315 insertions, 76 deletions
diff --git a/emcc b/emcc
index 7cc59c53..6f68a355 100755
--- a/emcc
+++ b/emcc
@@ -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