Merge branch 'idb-preload-cache' of github.com:modeswitch/emscripten into modeswitch-idb-preload-cache

This commit is contained in:
Alon Zakai 2013-04-25 11:34:20 -07:00
Родитель a00ffce0b7 b5c6a0ad07
Коммит 4b1c3fbdb4
4 изменённых файлов: 397 добавлений и 177 удалений

5
.gitignore поставляемый
Просмотреть файл

@ -10,4 +10,7 @@ src/relooper.js.raw.js
src/relooper/*.o
src/relooper/*.out
tests/fake/
tests/fake/
third_party/lzma.js/lzip/*.o
third_party/lzma.js/lzma-native

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

@ -16,7 +16,7 @@ Example uses:
with that command as an argument, for example
emconfigure.py ./configure [options]
emconfigure.py is a tiny script that just sets some environment vars
as a convenience. The command just shown is equivalent to
@ -47,7 +47,7 @@ Example uses:
return os.path.join(__rootpath__, *pathelems)
sys.path += [path_from_root('')]
from tools.shared import *
For using the Emscripten compilers/linkers/etc. you can do:
env = Environment()
...
@ -720,6 +720,7 @@ try:
jcache = False
save_bc = False
memory_init_file = False
use_preload_cache = False
if use_cxx:
default_cxx_std = '-std=c++03' # Enforce a consistent C++ standard when compiling .cpp files, if user does not specify one on the cmdline.
@ -819,6 +820,9 @@ try:
Compression.on = True
newargs[i] = ''
newargs[i+1] = ''
elif newargs[i].startswith('--use-preload-cache'):
use_preload_cache = True;
newargs[i] = ''
elif newargs[i] == '--ignore-dynamic-linking':
ignore_dynamic_linking = True
newargs[i] = ''
@ -1010,16 +1014,16 @@ try:
if closure:
print >> sys.stderr, 'emcc: warning: disabling closure because it is not compatible with asm.js code generation'
closure = False
if shared.Settings.CORRECT_SIGNS != 1:
if shared.Settings.CORRECT_SIGNS != 1:
print >> sys.stderr, 'emcc: warning: setting CORRECT_SIGNS to 1 for asm.js code generation'
shared.Settings.CORRECT_SIGNS = 1
if shared.Settings.CORRECT_OVERFLOWS != 1:
if shared.Settings.CORRECT_OVERFLOWS != 1:
print >> sys.stderr, 'emcc: warning: setting CORRECT_OVERFLOWS to 1 for asm.js code generation'
shared.Settings.CORRECT_OVERFLOWS = 1
assert not shared.Settings.PGO, 'cannot run PGO in ASM_JS mode'
if shared.Settings.CORRECT_SIGNS >= 2 or shared.Settings.CORRECT_OVERFLOWS >= 2 or shared.Settings.CORRECT_ROUNDINGS >= 2:
keep_llvm_debug = True # must keep debug info to do line-by-line operations
keep_llvm_debug = True # must keep debug info to do line-by-line operations
if (keep_llvm_debug or keep_js_debug) and closure:
print >> sys.stderr, 'emcc: warning: disabling closure because debug info was requested'
@ -1405,6 +1409,8 @@ try:
file_args += embed_files
if Compression.on:
file_args += ['--compress', Compression.encoder, Compression.decoder, Compression.js_name]
if use_preload_cache:
file_args.append('--use-preload-cache')
code = execute([shared.PYTHON, shared.FILE_PACKAGER, unsuffixed(target) + '.data'] + file_args, stdout=PIPE)[0]
src = open(final).read().replace('// {{PRE_RUN_ADDITIONS}}', '// {{PRE_RUN_ADDITIONS}}\n' + code)
final += '.files.js'

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

@ -1198,9 +1198,9 @@ m_divisor is 1091269979
// from cube2, zlib licensed
#define N (624)
#define M (397)
#define K (0x9908B0DFU)
#define N (624)
#define M (397)
#define K (0x9908B0DFU)
static uint state[N];
static int next = N;
@ -1378,7 +1378,7 @@ c5,de,15,8a
#include <string>
#include <sstream>
typedef unsigned long long quint64;
typedef unsigned long long quint64;
using namespace std;
@ -1406,14 +1406,14 @@ c5,de,15,8a
printf("1\n");
s >> hex >> int64bitInt;
printf("2\n");
stringstream out;
out << hex << qbswap(int64bitInt);
cout << out.str() << endl;
cout << hex << int64bitInt << endl;
cout << string64bitInt << endl;
if (out.str() != "bbccddeeff3344")
{
cout << "Failed!" << endl;
@ -1455,7 +1455,7 @@ Succeeded!
# A good test of i64 math
if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2 C-style memory aliasing')
self.do_run('', 'Usage: hashstring <seed>',
libraries=self.get_library('cube2hash', ['cube2hash.bc'], configure=None),
libraries=self.get_library('cube2hash', ['cube2hash.bc'], configure=None),
includes=[path_from_root('tests', 'cube2hash')])
for text, output in [('fleefl', '892BDB6FD3F62E863D63DA55851700FDE3ACF30204798CE9'),
@ -2238,7 +2238,7 @@ cat |umber one top notchfi FI FO FUM WHEN WHERE WHY HOW WHO|''', ['wowie', 'too'
total += c->value;
c = c->next;
} while (c != chunk);
printf("*%d,%d*\\n", total, b.next);
// NULL *is* 0, in C/C++. No JS null! (null == 0 is false, etc.)
@ -2330,19 +2330,19 @@ cat |umber one top notchfi FI FO FUM WHEN WHERE WHY HOW WHO|''', ['wowie', 'too'
src = r'''
#include <stdio.h>
#include <setjmp.h>
static jmp_buf buf;
void second(void) {
printf("second\n"); // prints
longjmp(buf,1); // jumps back to where setjmp was called - making setjmp now return 1
}
void first(void) {
second();
printf("first\n"); // does not print
}
int main() {
volatile int x = 0;
if ( ! setjmp(buf) ) {
@ -2351,7 +2351,7 @@ cat |umber one top notchfi FI FO FUM WHEN WHERE WHY HOW WHO|''', ['wowie', 'too'
} else { // when longjmp jumps back, setjmp returns 1
printf("main: %d\n", x); // prints
}
return 0;
}
'''
@ -2510,7 +2510,7 @@ Exception execution path of first function! 1
src = r'''
#include <stdio.h>
#include <setjmp.h>
static jmp_buf buf;
void (*fp)() = NULL;
@ -2519,12 +2519,12 @@ Exception execution path of first function! 1
printf("second\n"); // prints
longjmp(buf,1); // jumps back to where setjmp was called - making setjmp now return 1
}
void first(void) {
fp();
printf("first\n"); // does not print
}
int main(int argc, char **argv) {
fp = argc == 200 ? NULL : second;
@ -2535,7 +2535,7 @@ Exception execution path of first function! 1
} else { // when longjmp jumps back, setjmp returns 1
printf("main: %d\n", x); // prints
}
return 0;
}
'''
@ -2547,15 +2547,15 @@ Exception execution path of first function! 1
src = r'''
#include <stdio.h>
#include <setjmp.h>
static jmp_buf buf;
int main() {
volatile int x = 0;
printf("setjmp:%d\n", setjmp(buf));
x++;
printf("x:%d\n", x);
if (x < 4) longjmp(buf, x*2);
if (x < 4) longjmp(buf, x*2);
return 0;
}
'''
@ -2685,7 +2685,7 @@ back
src = '''
#include <iostream>
class MyException
{
public:
@ -2693,21 +2693,21 @@ back
MyException( const MyException & ) { std::cout << "Copy..."; }
~MyException(){ std::cout << "Destruct..."; }
};
int function()
{
std::cout << "Throw...";
throw MyException();
}
int function2()
{
return function();
}
int main()
{
try
try
{
function2();
}
@ -2715,8 +2715,8 @@ back
{
std::cout << "Catched...";
}
try
try
{
function2();
}
@ -2724,11 +2724,11 @@ back
{
std::cout << "Catched...";
}
return 0;
}
'''
Settings.DISABLE_EXCEPTION_CATCHING = 0
if '-O2' in self.emcc_args:
self.emcc_args.pop() ; self.emcc_args.pop() # disable closure to work around a closure bug
@ -2741,7 +2741,7 @@ back
src = '''
#include <stdio.h>
void thrower() {
printf("infunc...");
throw(99);
@ -3358,7 +3358,7 @@ Exiting setjmp function, level: 0, prev_jmp: -1
static char s[100]="aaaaa";
static int func(void) {
if(s[0]!='a') return 0;
if(s[0]!='a') return 0;
printf("iso open %s\n", s, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001, 1.001);
return 0;
}
@ -3376,14 +3376,14 @@ Exiting setjmp function, level: 0, prev_jmp: -1
self.emcc_args += ['-std=c99']
src = open(path_from_root('tests', 'life.c'), 'r').read()
self.do_run(src, '''--------
[][][]
[][]
[][][]
[][]
[]
[]
[][]
[]
[][]
--------
''', ['8', '8', '25000'], force_c=True)
@ -3844,7 +3844,7 @@ def process(filename):
def test_cxx03_do_run(self):
src = '''
#include <stdio.h>
#if __cplusplus != 199711L
#error By default, if no -std is specified, emscripten should be compiling with -std=c++03!
#endif
@ -3916,7 +3916,7 @@ def process(filename):
#pragma pack(push,1)
typedef struct header
{
{
unsigned char id;
unsigned short colour;
unsigned char desc;
@ -3924,7 +3924,7 @@ def process(filename):
#pragma pack(pop)
typedef struct fatheader
{
{
unsigned char id;
unsigned short colour;
unsigned char desc;
@ -4269,14 +4269,14 @@ The current type of b is: 9
src = r'''
#include <stdio.h>
#include <stdlib.h>
static void cleanA() {
printf("A");
}
static void cleanB() {
printf("B");
}
int main() {
atexit(cleanA);
atexit(cleanB);
@ -4810,9 +4810,9 @@ The current type of b is: 9
chain *c = NULL;
printf("*%d,%d,%d,%d,%d,%d|%d,%d,%d,%d,%d,%d,%d,%d|%d,%d,%d,%d,%d,%d,%d,%d,%d,%d*\\n",
sizeof(base),
int(&(b->x)), int(&(b->y)), int(&(b->a)), int(&(b->b)), int(&(b->c)),
int(&(b->x)), int(&(b->y)), int(&(b->a)), int(&(b->b)), int(&(b->c)),
sizeof(hashtableentry),
int(&(e->key)), int(&(e->data)), int(&(e->data.x)), int(&(e->data.y)), int(&(e->data.a)), int(&(e->data.b)), int(&(e->data.c)),
int(&(e->key)), int(&(e->data)), int(&(e->data.x)), int(&(e->data.y)), int(&(e->data.a)), int(&(e->data.b)), int(&(e->data.c)),
sizeof(hashset::chain),
int(&(c->elem)), int(&(c->next)), int(&(c->elem.key)), int(&(c->elem.data)), int(&(c->elem.data.x)), int(&(c->elem.data.y)), int(&(c->elem.data.a)), int(&(c->elem.data.b)), int(&(c->elem.data.c))
);
@ -5425,7 +5425,7 @@ at function.:blag
src = open(path_from_root('tests', 'parseInt', 'src.c'), 'r').read()
expected = open(path_from_root('tests', 'parseInt', 'output.txt'), 'r').read()
self.do_run(src, expected)
def test_transtrcase(self):
src = '''
#include <stdio.h>
@ -5565,7 +5565,7 @@ at function.:blag
}
'''
self.do_run(src, '22 : me and myself 25 1.34\n21 waka 95\n')
def test_perrar(self):
src = r'''
#include <sys/types.h>
@ -5869,7 +5869,7 @@ Pass: 0.000012 0.000012''')
return 0;
}
'''
self.do_run(src, '''0:173,16 1:16,173 2:183,173 3:17,287 4:98,123''')
self.do_run(src, '''0:173,16 1:16,173 2:183,173 3:17,287 4:98,123''')
def test_sscanf_3(self):
# i64
@ -5878,11 +5878,11 @@ Pass: 0.000012 0.000012''')
#include <stdio.h>
int main(){
int64_t s, m, l;
printf("%d\n", sscanf("123 1073741823 1125899906842620", "%lld %lld %lld", &s, &m, &l));
printf("%lld,%lld,%lld\n", s, m, l);
int64_t negS, negM, negL;
printf("%d\n", sscanf("-123 -1073741823 -1125899906842620", "%lld %lld %lld", &negS, &negM, &negL));
printf("%lld,%lld,%lld\n", negS, negM, negL);
@ -5890,8 +5890,8 @@ Pass: 0.000012 0.000012''')
return 0;
}
'''
self.do_run(src, '3\n123,1073741823,1125899906842620\n' +
self.do_run(src, '3\n123,1073741823,1125899906842620\n' +
'3\n-123,-1073741823,-1125899906842620\n')
def test_sscanf_4(self):
@ -6482,7 +6482,7 @@ def process(filename):
'''
self.do_run(src, "some string constant")
def test_istream(self):
if self.emcc_args is None: return self.skip('requires libcxx')
@ -6490,15 +6490,15 @@ def process(filename):
#include <string>
#include <sstream>
#include <iostream>
int main()
{
std::string mystring("1 2 3");
std::istringstream is(mystring);
int one, two, three;
is >> one >> two >> three;
printf( "%i %i %i", one, two, three );
}
'''
@ -6520,19 +6520,19 @@ def process(filename):
src = '''
#include <dirent.h>
#include <stdio.h>
int main()
{
DIR * dir;
dirent * entity;
dir = opendir( "test" );
while( ( entity = readdir( dir ) ) )
{
printf( "%s is a %s\\n", entity->d_name, entity->d_type & DT_DIR ? "directory" : "file" );
}
return 0;
}
@ -7051,7 +7051,7 @@ int main(int argc, char **argv) {
int main ( int argc, char *argv[] )
{
std::vector<S> ar;
std::vector<S> ar;
S s;
s.a = 789;
@ -7130,7 +7130,7 @@ extern "C" {
int main()
{
const char* jsonString = "{\\"key\\": \\"value\\",\\"array\\": [\\"array_item1\\",\\"array_item2\\",\\"array_item3\\"],\\"dict\\":{\\"number\\": 3,\\"float\\": 2.2}}";
json_error_t error;
json_t *root = json_loadb(jsonString, strlen(jsonString), 0, &error);
@ -7145,7 +7145,7 @@ extern "C" {
}
printf("%s\\n", json_string_value(json_object_get(root, "key")));
json_t *array = json_object_get(root, "array");
if(!array) {
printf("Node `array` is `null`.");
@ -7171,7 +7171,7 @@ extern "C" {
json_t *numberNode = json_object_get(dict, "number");
json_t *floatNode = json_object_get(dict, "float");
if(!numberNode || !json_is_number(numberNode) ||
!floatNode || !json_is_real(floatNode))
return 0;
@ -7261,7 +7261,7 @@ extern "C" {
def test_dlmalloc_partial(self):
if self.emcc_args is None: return self.skip('only emcc will link in dlmalloc')
# present part of the symbols of dlmalloc, not all
src = open(path_from_root('tests', 'new.cpp')).read().replace('{{{ NEW }}}', 'new int').replace('{{{ DELETE }}}', 'delete') + '''
src = open(path_from_root('tests', 'new.cpp')).read().replace('{{{ NEW }}}', 'new int').replace('{{{ DELETE }}}', 'delete') + '''
void *
operator new(size_t size)
{
@ -7393,7 +7393,7 @@ void*:16
struct DATA
{
int value;
DATA()
{
value = 0;
@ -7403,7 +7403,7 @@ void*:16
DATA & GetData()
{
static DATA data;
return data;
}
@ -7437,7 +7437,7 @@ void*:16
#include <stdio.h>
#include <sys/mman.h>
#include <assert.h>
int main(int argc, char *argv[]) {
for (int i = 0; i < 10; i++) {
int* map = (int*)mmap(0, 5000, PROT_READ | PROT_WRITE,
@ -7448,23 +7448,23 @@ void*:16
const int NUM_BYTES = 8 * 1024 * 1024;
const int NUM_INTS = NUM_BYTES / sizeof(int);
int* map = (int*)mmap(0, NUM_BYTES, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANON, -1, 0);
assert(map != MAP_FAILED);
int i;
for (i = 0; i < NUM_INTS; i++) {
map[i] = i;
}
for (i = 0; i < NUM_INTS; i++) {
assert(map[i] == i);
}
assert(munmap(map, NUM_BYTES) == 0);
printf("hello,world");
return 0;
}
@ -7577,7 +7577,7 @@ def process(filename):
'''
# Not needed for js, but useful for debugging
shutil.copyfile(path_from_root('tests', 'freetype', 'LiberationSansBold.ttf'), os.path.join(self.get_dir(), 'font.ttf'))
shutil.copyfile(path_from_root('tests', 'freetype', 'LiberationSansBold.ttf'), os.path.join(self.get_dir(), 'font.ttf'))
# Main
self.do_run(open(path_from_root('tests', 'freetype', 'main.c'), 'r').read(),
@ -8329,7 +8329,7 @@ def process(filename):
script_src = '''
var sme = Module._.ScriptMe.__new__(83); // malloc(sizeof(ScriptMe)), ScriptMe::ScriptMe(sme, 83) / new ScriptMe(83) (at addr sme)
Module._.ScriptMe.mulVal(sme, 2); // ScriptMe::mulVal(sme, 2) sme.mulVal(2)
Module.print('*' + Module._.ScriptMe.getVal(sme) + '*');
Module.print('*' + Module._.ScriptMe.getVal(sme) + '*');
_free(sme);
Module.print('*ok*');
'''
@ -9102,7 +9102,7 @@ finalizing 3 (global == 0)
class %s(T):
def tearDown(self):
super(%s, self).tearDown()
def setUp(self):
super(%s, self).setUp()
@ -9457,16 +9457,16 @@ f.close()
cmake_outputs = ['hello_world.js', 'hello_world_gles.html']
for i in range(0, 2):
for configuration in ['Debug', 'Release']:
# Create a temp workspace folder
cmakelistsdir = path_from_root('tests', 'cmake', cmake_cases[i])
tempdirname = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=TEMP_DIR)
try:
os.chdir(tempdirname)
# Run Cmake
cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+emscriptencmaketoolchain,
'-DCMAKE_BUILD_TYPE=' + configuration,
cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+emscriptencmaketoolchain,
'-DCMAKE_BUILD_TYPE=' + configuration,
'-DCMAKE_MODULE_PATH=' + path_from_root('cmake').replace('\\', '/'),
'-G' 'Unix Makefiles', cmakelistsdir]
ret = Popen(cmd, stdout=PIPE, stderr=PIPE).communicate()
@ -9477,7 +9477,7 @@ f.close()
print >> sys.stderr, 'Result:\n' + ret[1]
raise Exception('cmake call failed!')
assert os.path.exists(tempdirname + '/Makefile'), 'CMake call did not produce a Makefile!'
# Build
cmd = [make_command]
ret = Popen(cmd, stdout=PIPE).communicate()
@ -9488,7 +9488,7 @@ f.close()
print >> sys.stderr, 'Result:\n' + ret[0]
raise Exception('make failed!')
assert os.path.exists(tempdirname + '/' + cmake_outputs[i]), 'Building a cmake-generated Makefile failed to produce an output file %s!' % tempdirname + '/' + cmake_outputs[i]
# Run through node, if CMake produced a .js file.
if cmake_outputs[i].endswith('.js'):
ret = Popen(listify(NODE_JS) + [tempdirname + '/' + cmake_outputs[i]], stdout=PIPE).communicate()[0]
@ -9521,14 +9521,14 @@ f.close()
open(os.path.join(self.get_dir(), 'test.cpp'), 'w').write(r'''
#include <vector>
#include <stdio.h>
class Test {
public:
std::vector<int> vector;
};
Test globalInstance;
int main() {
printf("hello, world!\n");
return 0;
@ -9802,7 +9802,7 @@ f.close()
#include <testa.h>
TestA::TestA() {
printf("TestA\n");
printf("TestA\n");
}
''')
open('testb.cpp', 'w').write(r'''
@ -9812,7 +9812,7 @@ f.close()
/*
*/
TestB::TestB() {
printf("TestB\n");
printf("TestB\n");
TestA* testa = new TestA();
}
''')
@ -10120,7 +10120,7 @@ f.close()
}
for (int i = 0; i < num; i++) {
buf2[i] = buf[i];
}
}
for (int i = 1; i < num; i++) {
buf2[i] += buf2[i-1];
}
@ -10432,7 +10432,7 @@ f.close()
output = Popen([os.path.join(self.get_dir(), 'files.o.run')], stdin=open(os.path.join(self.get_dir(), 'stdin')), stdout=PIPE, stderr=PIPE).communicate()
self.assertContained('''size: 37
data: 119,97,107,97,32,119,97,107,97,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35
loop: 119 97 107 97 32 119 97 107 97 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35
loop: 119 97 107 97 32 119 97 107 97 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35 35
input:inter-active
texto
$
@ -10690,7 +10690,7 @@ elif 'browser' in str(sys.argv):
# On Windows, shutil.rmtree() in tearDown() raises this exception if we do not wait a bit:
# WindowsError: [Error 32] The process cannot access the file because it is being used by another process.
time.sleep(0.1)
def run_browser(self, html_file, message, expectedResult=None):
if expectedResult is not None:
try:
@ -10814,9 +10814,9 @@ elif 'browser' in str(sys.argv):
assert os.path.exists(os.path.join(self.get_dir(), 'something.js')), 'must be main js file'
assert os.path.exists(os.path.join(self.get_dir(), 'something_functions.js')), 'must be functions js file'
assert os.path.exists(os.path.join(self.get_dir(), 'something.include.html')), 'must be js include file'
open(os.path.join(self.get_dir(), 'something.html'), 'w').write('''
<!doctype html>
<html lang="en-us">
<head>
@ -10834,7 +10834,7 @@ elif 'browser' in str(sys.argv):
<hr/>
<div class="emscripten" id="status">Downloading...</div>
<div class="emscripten">
<progress value="0" max="100" id="progress" hidden=1></progress>
<progress value="0" max="100" id="progress" hidden=1></progress>
</div>
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
<hr/>
@ -10896,7 +10896,7 @@ elif 'browser' in str(sys.argv):
</body>
</html>
''')
self.run_browser('something.html', 'You should see "hello, world!" and a colored cube.', '/report_result?0')
def test_split_in_source_filenames(self):
@ -10925,7 +10925,7 @@ elif 'browser' in str(sys.argv):
<hr/>
<div class="emscripten" id="status">Downloading...</div>
<div class="emscripten">
<progress value="0" max="100" id="progress" hidden=1></progress>
<progress value="0" max="100" id="progress" hidden=1></progress>
</div>
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
<hr/>
@ -11066,6 +11066,57 @@ elif 'browser' in str(sys.argv):
Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--pre-js', 'pre.js', '-o', 'page.html']).communicate()
self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?1')
def test_preload_caching(self):
open(os.path.join(self.get_dir(), 'somefile.txt'), 'w').write('''load me right before running the code please''')
def make_main(path):
print path
open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(self.with_report_result(r'''
#include <stdio.h>
#include <string.h>
#include <emscripten.h>
extern "C" {
extern int checkPreloadResults();
}
int main(int argc, char** argv) {
FILE *f = fopen("%s", "r");
char buf[100];
fread(buf, 1, 20, f);
buf[20] = 0;
fclose(f);
printf("|%%s|\n", buf);
int result = 0;
result += !strcmp("load me right before", buf);
result += checkPreloadResults();
REPORT_RESULT();
return 0;
}
''' % path))
open(os.path.join(self.get_dir(), 'test.js'), 'w').write('''
mergeInto(LibraryManager.library, {
checkPreloadResults: function() {
var cached = 0;
var packages = Object.keys(Module['preloadResults']);
packages.forEach(function(package) {
var fromCache = Module['preloadResults'][package]['fromCache'];
if (fromCache)
++ cached;
});
return cached;
}
});
''')
make_main('somefile.txt')
Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '--use-preload-cache', '--js-library', os.path.join(self.get_dir(), 'test.js'), '--preload-file', 'somefile.txt', '-o', 'page.html']).communicate()
self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?1')
self.run_browser('page.html', 'You should see |load me right before|.', '/report_result?2')
def test_multifile(self):
# a few files inside a directory
self.clear()
@ -11826,7 +11877,7 @@ elif 'browser' in str(sys.argv):
def test_sdl_canvas_palette_2(self):
open(os.path.join(self.get_dir(), 'pre.js'), 'w').write('''
Module['preRun'].push(function() {
Module['preRun'].push(function() {
SDL.defaults.copyOnLock = false;
});
''')
@ -11842,7 +11893,7 @@ elif 'browser' in str(sys.argv):
open(os.path.join(self.get_dir(), 'args-b.js'), 'w').write('''
Module['arguments'] = ['-b'];
''')
self.btest('sdl_canvas_palette_2.c', reference='sdl_canvas_palette_r.png', args=['--pre-js', 'pre.js', '--pre-js', 'args-r.js'])
self.btest('sdl_canvas_palette_2.c', reference='sdl_canvas_palette_g.png', args=['--pre-js', 'pre.js', '--pre-js', 'args-g.js'])
self.btest('sdl_canvas_palette_2.c', reference='sdl_canvas_palette_b.png', args=['--pre-js', 'pre.js', '--pre-js', 'args-b.js'])
@ -12178,7 +12229,7 @@ elif 'benchmark' in str(sys.argv):
try:
d = os.getcwd()
os.chdir(os.path.expanduser('~/Dev/mozilla-central'))
fingerprint.append('sm: ' + filter(lambda line: 'changeset' in line,
fingerprint.append('sm: ' + filter(lambda line: 'changeset' in line,
Popen(['hg', 'tip'], stdout=PIPE).communicate()[0].split('\n'))[0])
except:
pass
@ -12350,7 +12401,7 @@ elif 'benchmark' in str(sys.argv):
}
printf("final: %d.\\n", final);
return 0;
}
}
'''
self.do_benchmark('memops', src, [], 'final: 400.')
@ -12393,7 +12444,7 @@ elif 'benchmark' in str(sys.argv):
}
printf("ok");
return 0;
}
}
'''
self.do_benchmark(src, [], 'ok')
@ -12436,7 +12487,7 @@ elif 'benchmark' in str(sys.argv):
}
printf("sum:%d\n", total);
return 0;
}
}
'''
self.do_benchmark('copy', src, [], 'sum:2836\n', emcc_args=['-s', 'QUANTUM_SIZE=4', '-s', 'USE_TYPED_ARRAYS=2'])
@ -12463,7 +12514,7 @@ elif 'benchmark' in str(sys.argv):
}
printf("final: %d:%d.\n", f, s);
return 0;
}
}
'''
self.do_benchmark('corrections', src, [], 'final: 40006013:10225.', emcc_args=['-s', 'CORRECT_SIGNS=1', '-s', 'CORRECT_OVERFLOWS=1', '-s', 'CORRECT_ROUNDINGS=1'])
@ -12484,38 +12535,38 @@ elif 'benchmark' in str(sys.argv):
def test_life(self):
src = open(path_from_root('tests', 'life.c'), 'r').read()
self.do_benchmark('life', src, ['32', '32', '15000'], '''--------------------------------
[] [][][] [] [] [][]
[] [][][] [] [] [][]
[] [][] [] [] [] []
[] [][] [][] []
[] [] [] []
[] [] [] [] [] [] [] []
[][][][] [] [][] [][]
[]
[]
[] []
[][] [] []
[][] [][][]
[]
[]
[] []
[][]
[] [] [][] [][]
[] [] [] []
[][] []
[][][][]
[][][] [][]
[][][] [][]
[]
[]
[] [][][] []
[] []
[][] []
[][][]
[][][] [][]
[][][][][] [] [][]
[] [][] [] []
[] [][] [][] []
[] [] [] []
[] [] [] [] [] [] [] []
[][][][] [] [][] [][]
[]
[]
[] []
[][] [] []
[][] [][][]
[]
[]
[] []
[][]
[] [] [][] [][]
[] [] [] []
[][] []
[][][][]
[][][] [][]
[][][] [][]
[]
[]
[] [][][] []
[] []
[][] []
[][][]
[][][] [][]
[][][][][] [] [][]
[] [][] [] []
--------------------------------
''', shared_args=['-std=c99'], force_c=True)
@ -13023,7 +13074,7 @@ fi
continue
print >> sys.stderr, args, input_file, expect_pre_save, expect_pre_load, expect_funcs_save, expect_funcs_load, expect_jsfuncs_save, expect_jsfuncs_load, expected
out, err = Popen([PYTHON, EMCC, '-O2', path_from_root('tests', input_file)] + args, stdout=PIPE, stderr=PIPE).communicate()
errtail = err.split('emcc invocation')[-1]
self.assertContained('hello, world!', run_js('a.out.js'), errtail)

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

@ -28,6 +28,8 @@ Usage:
--no-force Don't create output if no valid input file is specified.
--use-preload-cache Stores package in IndexedDB so that subsequent loads don't need to do XHR. Checks package version.
Notes:
* The file packager generates unix-style file paths. So if you are on windows and a file is accessed at
@ -37,14 +39,14 @@ TODO: You can also provide .crn files yourself, pre-crunched. With this o
to dds files in the browser, exactly the same as if this tool compressed them.
'''
import os, sys, shutil, random
import os, sys, shutil, random, uuid
import shared
from shared import Compression, execute, suffix, unsuffixed
from subprocess import Popen, PIPE, STDOUT
if len(sys.argv) == 1:
print '''Usage: file_packager.py TARGET [--preload A...] [--embed B...] [--compress COMPRESSION_DATA] [--pre-run] [--crunch[=X]] [--js-output=OUTPUT.js] [--no-force]
print '''Usage: file_packager.py TARGET [--preload A...] [--embed B...] [--compress COMPRESSION_DATA] [--pre-run] [--crunch[=X]] [--js-output=OUTPUT.js] [--no-force] [--use-preload-cache]
See the source for more details.'''
sys.exit(0)
@ -70,6 +72,7 @@ crunch = 0
plugins = []
jsoutput = None
force = True
use_preload_cache = False
for arg in sys.argv[1:]:
if arg == '--preload':
@ -93,6 +96,8 @@ for arg in sys.argv[1:]:
in_compress = 0
elif arg == '--no-force':
force = False
elif arg == '--use-preload-cache':
use_preload_cache = True
elif arg.startswith('--js-output'):
jsoutput = arg.split('=')[1] if '=' in arg else None
elif arg.startswith('--crunch'):
@ -256,6 +261,7 @@ if has_preloaded:
start += len(curr)
data.write(curr)
data.close()
# TODO: sha256sum on data_target
if Compression.on:
Compression.compress(data_target)
@ -356,8 +362,9 @@ if has_preloaded:
byteArray = new Uint8Array(decompressed);
%s
});
''' % use_data
''' % use_data
package_uuid = uuid.uuid4();
code += r'''
if (!Module.expectedDataFileDownloads) {
Module.expectedDataFileDownloads = 0;
@ -365,49 +372,202 @@ if has_preloaded:
}
Module.expectedDataFileDownloads++;
var dataFile = new XMLHttpRequest();
dataFile.onprogress = function(event) {
var url = '%s';
if (event.loaded && event.total) {
if (!dataFile.addedTotal) {
dataFile.addedTotal = true;
if (!Module.dataFileDownloads) Module.dataFileDownloads = {};
Module.dataFileDownloads[url] = {
loaded: event.loaded,
total: event.total
var PACKAGE_PATH = window.encodeURIComponent(window.location.pathname.toString().substring(0, window.location.pathname.toString().lastIndexOf('/')) + '/');
var PACKAGE_NAME = '%s';
var REMOTE_PACKAGE_NAME = '%s';
var PACKAGE_UUID = '%s';
''' % (data_target, os.path.basename(Compression.compressed_name(data_target) if Compression.on else data_target), package_uuid)
if use_preload_cache:
code += r'''
var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
var IDB_RO = "readonly";
var IDB_RW = "readwrite";
var DB_NAME = 'EM_PRELOAD_CACHE';
var DB_VERSION = 1;
var METADATA_STORE_NAME = 'METADATA';
var PACKAGE_STORE_NAME = 'PACKAGES';
function openDatabase(callback, errback) {
try {
var openRequest = indexedDB.open(DB_NAME, DB_VERSION);
} catch (e) {
return errback(e);
}
openRequest.onupgradeneeded = function(event) {
var db = event.target.result;
if(db.objectStoreNames.contains(PACKAGE_STORE_NAME)) {
db.deleteObjectStore(PACKAGE_STORE_NAME);
}
var packages = db.createObjectStore(PACKAGE_STORE_NAME);
if(db.objectStoreNames.contains(METADATA_STORE_NAME)) {
db.deleteObjectStore(METADATA_STORE_NAME);
}
var metadata = db.createObjectStore(METADATA_STORE_NAME);
};
openRequest.onsuccess = function(event) {
var db = event.target.result;
callback(db);
};
openRequest.onerror = function(error) {
errback(error);
};
};
/* Check if there's a cached package, and if so whether it's the latest available */
function checkCachedPackage(db, packageName, callback, errback) {
var transaction = db.transaction([METADATA_STORE_NAME], IDB_RO);
var metadata = transaction.objectStore(METADATA_STORE_NAME);
var getRequest = metadata.get(packageName);
getRequest.onsuccess = function(event) {
var result = event.target.result;
if (!result) {
return callback(false);
} else {
return callback(PACKAGE_UUID === result.uuid);
}
};
getRequest.onerror = function(error) {
errback(error);
};
};
function fetchCachedPackage(db, packageName, callback, errback) {
var transaction = db.transaction([PACKAGE_STORE_NAME], IDB_RO);
var packages = transaction.objectStore(PACKAGE_STORE_NAME);
var getRequest = packages.get(packageName);
getRequest.onsuccess = function(event) {
var result = event.target.result;
callback(result);
};
getRequest.onerror = function(error) {
errback(error);
};
};
function cacheRemotePackage(db, packageName, packageData, packageMeta, callback, errback) {
var transaction = db.transaction([PACKAGE_STORE_NAME, METADATA_STORE_NAME], IDB_RW);
var packages = transaction.objectStore(PACKAGE_STORE_NAME);
var metadata = transaction.objectStore(METADATA_STORE_NAME);
var putPackageRequest = packages.put(packageData, packageName);
putPackageRequest.onsuccess = function(event) {
var putMetadataRequest = metadata.put(packageMeta, packageName);
putMetadataRequest.onsuccess = function(event) {
callback(packageData);
};
} else {
Module.dataFileDownloads[url].loaded = event.loaded;
}
var total = 0;
var loaded = 0;
var num = 0;
for (var download in Module.dataFileDownloads) {
putMetadataRequest.onerror = function(error) {
errback(error);
};
};
putPackageRequest.onerror = function(error) {
errback(error);
};
};
'''
code += r'''
function fetchRemotePackage(packageName, callback, errback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', packageName, true);
xhr.responseType = 'arraybuffer';
xhr.onprogress = function(event) {
var url = packageName;
if (event.loaded && event.total) {
if (!xhr.addedTotal) {
xhr.addedTotal = true;
if (!Module.dataFileDownloads) Module.dataFileDownloads = {};
Module.dataFileDownloads[url] = {
loaded: event.loaded,
total: event.total
};
} else {
Module.dataFileDownloads[url].loaded = event.loaded;
}
var total = 0;
var loaded = 0;
var num = 0;
for (var download in Module.dataFileDownloads) {
var data = Module.dataFileDownloads[download];
total += data.total;
loaded += data.loaded;
num++;
total += data.total;
loaded += data.loaded;
num++;
}
total = Math.ceil(total * Module.expectedDataFileDownloads/num);
Module['setStatus']('Downloading data... (' + loaded + '/' + total + ')');
} else if (!Module.dataFileDownloads) {
Module['setStatus']('Downloading data...');
}
total = Math.ceil(total * Module.expectedDataFileDownloads/num);
Module['setStatus']('Downloading data... (' + loaded + '/' + total + ')');
} else if (!Module.dataFileDownloads) {
Module['setStatus']('Downloading data...');
}
}
dataFile.open('GET', '%s', true);
dataFile.responseType = 'arraybuffer';
dataFile.onload = function() {
};
xhr.onload = function(event) {
var packageData = xhr.response;
callback(packageData);
};
xhr.send(null);
};
function processPackageData(arrayBuffer) {
Module.finishedDataFileDownloads++;
var arrayBuffer = dataFile.response;
assert(arrayBuffer, 'Loading data file failed.');
var byteArray = new Uint8Array(arrayBuffer);
var curr;
%s
};
Module['addRunDependency']('datafile_%s');
dataFile.send(null);
if (Module['setStatus']) Module['setStatus']('Downloading...');
''' % (data_target, os.path.basename(Compression.compressed_name(data_target) if Compression.on else data_target), use_data, data_target) # use basename because from the browser's point of view, we need to find the datafile in the same dir as the html file
function handleError(error) {
console.error('package error:', error);
};
''' % (use_data, data_target) # use basename because from the browser's point of view, we need to find the datafile in the same dir as the html file
code += r'''
if (!Module.preloadResults)
Module.preloadResults = {};
'''
if use_preload_cache:
code += r'''
function preloadFallback(error) {
console.error(error);
console.error('falling back to default preload behavior');
fetchRemotePackage(REMOTE_PACKAGE_NAME, processPackageData, handleError);
};
openDatabase(
function(db) {
checkCachedPackage(db, PACKAGE_PATH + PACKAGE_NAME,
function(useCached) {
Module.preloadResults[PACKAGE_NAME] = {fromCache: useCached};
if (useCached) {
console.info('loading ' + PACKAGE_NAME + ' from cache');
fetchCachedPackage(db, PACKAGE_PATH + PACKAGE_NAME, processPackageData, preloadFallback);
} else {
console.info('loading ' + PACKAGE_NAME + ' from remote');
fetchRemotePackage(REMOTE_PACKAGE_NAME,
function(packageData) {
cacheRemotePackage(db, PACKAGE_PATH + PACKAGE_NAME, packageData, {uuid:PACKAGE_UUID}, processPackageData,
function(error) {
console.error(error);
processPackageData(packageData);
});
}
, preloadFallback);
}
}
, preloadFallback);
}
, preloadFallback);
if (Module['setStatus']) Module['setStatus']('Downloading...');
'''
else:
code += r'''
Module.preloadResults[PACKAGE_NAME] = {fromCache: false};
fetchRemotePackage(REMOTE_PACKAGE_NAME, processPackageData, handleError);
'''
if pre_run:
ret += '''