diff options
-rwxr-xr-x | emcc | 9 | ||||
-rw-r--r-- | src/jsifier.js | 2 | ||||
-rw-r--r-- | src/library_egl.js | 76 | ||||
-rw-r--r-- | src/library_gl.js | 74 | ||||
-rw-r--r-- | src/settings.js | 13 | ||||
-rw-r--r-- | src/utility.js | 6 | ||||
-rw-r--r-- | tests/gles2_uniform_arrays.cpp | 9 | ||||
-rw-r--r-- | tests/test_benchmark.py | 2 | ||||
-rw-r--r-- | tests/test_browser.py | 6 | ||||
-rw-r--r-- | tests/test_egl.c | 73 | ||||
-rw-r--r-- | tests/test_other.py | 49 | ||||
-rw-r--r-- | tests/zlib/CMakeLists.txt | 190 | ||||
-rw-r--r-- | tests/zlib/zconf.h.cmakein (renamed from tests/zlib/zconf.h) | 4 |
13 files changed, 446 insertions, 67 deletions
@@ -1133,10 +1133,11 @@ try: heap = 4096 while heap < shared.Settings.TOTAL_MEMORY: - if heap <= 16*1024*1024: - heap *= 2 - else: - heap += 16*1024*1024 + heap *= 2 + #if heap <= 16*1024*1024: + # heap *= 2 + #else: + # heap += 16*1024*1024 if heap != shared.Settings.TOTAL_MEMORY: logging.warning('increasing TOTAL_MEMORY to %d to be more reasonable for asm.js' % heap) shared.Settings.TOTAL_MEMORY = heap diff --git a/src/jsifier.js b/src/jsifier.js index a9505bb8..22a230ca 100644 --- a/src/jsifier.js +++ b/src/jsifier.js @@ -497,7 +497,7 @@ function JSify(data, functionsOnly, givenFunctions) { } if (!LINKABLE && !LibraryManager.library.hasOwnProperty(shortident) && !LibraryManager.library.hasOwnProperty(shortident + '__inline')) { if (ERROR_ON_UNDEFINED_SYMBOLS) error('unresolved symbol: ' + shortident); - if (VERBOSE || WARN_ON_UNDEFINED_SYMBOLS) printErr('warning: unresolved symbol: ' + shortident); + else if (VERBOSE || WARN_ON_UNDEFINED_SYMBOLS) warn('unresolved symbol: ' + shortident); if (ASM_JS) { // emit a stub that will fail during runtime. this allows asm validation to succeed. LibraryManager.library[shortident] = new Function("Module['printErr']('missing function: " + shortident + "'); abort(-1);"); diff --git a/src/library_egl.js b/src/library_egl.js index cc702fec..73d5e544 100644 --- a/src/library_egl.js +++ b/src/library_egl.js @@ -9,12 +9,16 @@ var LibraryEGL = { $EGL: { // This variable tracks the success status of the most recently invoked EGL function call. - eglErrorCode: 0x3000 /* EGL_SUCCESS */, + errorCode: 0x3000 /* EGL_SUCCESS */, + defaultDisplayInitialized: false, + currentContext: 0 /* EGL_NO_CONTEXT */, + currentReadSurface: 0 /* EGL_NO_SURFACE */, + currentDrawSurface: 0 /* EGL_NO_SURFACE */, stringCache: {}, setErrorCode: function(code) { - EGL.eglErrorCode = code; + EGL.errorCode = code; }, chooseConfig: function(display, attribList, config, config_size, numConfigs) { @@ -65,6 +69,7 @@ var LibraryEGL = { if (minorVersion) { {{{ makeSetValue('minorVersion', '0', '4', 'i32') }}}; // Advertise EGL Minor version: '4' } + EGL.defaultDisplayInitialized = true; EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); return 1; } @@ -80,18 +85,10 @@ var LibraryEGL = { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); return 0; } - // TODO: Tear down EGL here. Currently a no-op since we don't need to actually do anything here for the browser. - EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 1; - }, - -// EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy); - eglTerminate: function(display) { - if (display != 62000 /* Magic ID for Emscripten 'default display' */) { - EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0; - } - // TODO: Tear down EGL here. Currently a no-op since we don't need to actually do anything here for the browser. + EGL.currentContext = 0; + EGL.currentReadSurface = 0; + EGL.currentDrawSurface = 0; + EGL.defaultDisplayInitialized = false; EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); return 1; }, @@ -248,6 +245,12 @@ var LibraryEGL = { EGL.setErrorCode(0x300D /* EGL_BAD_SURFACE */); return 1; } + if (EGL.currentReadSurface == surface) { + EGL.currentReadSurface = 0; + } + if (EGL.currentDrawSurface == surface) { + EGL.currentDrawSurface = 0; + } EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); return 1; /* Magic ID for Emscripten 'default surface' */ }, @@ -265,6 +268,7 @@ var LibraryEGL = { EGL.windowID = _glutCreateWindow(); if (EGL.windowID != 0) { EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + // Note: This function only creates a context, but it shall not make it active. return 62004; // Magic ID for Emscripten EGLContext } else { EGL.setErrorCode(0x3009 /* EGL_BAD_MATCH */); // By the EGL 1.4 spec, an implementation that does not support GLES2 (WebGL in this case), this error code is set. @@ -280,10 +284,17 @@ var LibraryEGL = { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); return 0; } + if (context != 62004 /* Magic ID for Emscripten EGLContext */) { + EGL.setErrorCode(0x3006 /* EGL_BAD_CONTEXT */); + return 0; + } _glutDestroyWindow(EGL.windowID); EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 62004; // Magic ID for Emscripten EGLContext + if (EGL.currentContext == context) { + EGL.currentContext = 0; + } + return 1 /* EGL_TRUE */; }, // EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx); @@ -407,7 +418,7 @@ var LibraryEGL = { // EGLAPI EGLint EGLAPIENTRY eglGetError(void); eglGetError: function() { - return EGL.eglErrorCode; + return EGL.errorCode; }, // EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name); @@ -477,21 +488,46 @@ var LibraryEGL = { eglMakeCurrent: function(display, draw, read, context) { if (display != 62000 /* Magic ID for Emscripten 'default display' */) { EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); - return 0; + return 0 /* EGL_FALSE */; } //\todo An EGL_NOT_INITIALIZED error is generated if EGL is not initialized for dpy. - if (context != 62004 /* Magic ID for Emscripten EGLContext */) { + if (context != 0 && context != 62004 /* Magic ID for Emscripten EGLContext */) { EGL.setErrorCode(0x3006 /* EGL_BAD_CONTEXT */); return 0; } - if (read != 62006 || draw != 62006 /* Magic ID for Emscripten 'default surface' */) { + if ((read != 0 && read != 62006) || (draw != 0 && draw != 62006 /* Magic ID for Emscripten 'default surface' */)) { EGL.setErrorCode(0x300D /* EGL_BAD_SURFACE */); return 0; } + EGL.currentContext = context; + EGL.currentDrawSurface = draw; + EGL.currentReadSurface = read; EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); - return 1; + return 1 /* EGL_TRUE */; + }, + + // EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void); + eglGetCurrentContext: function() { + return EGL.currentContext; }, + // EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw); + eglGetCurrentSurface: function(readdraw) { + if (readdraw == 0x305A /* EGL_READ */) { + return EGL.currentReadSurface; + } else if (readdraw == 0x3059 /* EGL_DRAW */) { + return EGL.currentDrawSurface; + } else { + EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); + return 0 /* EGL_NO_SURFACE */; + } + }, + + // EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void); + eglGetCurrentDisplay: function() { + return EGL.currentContext ? 62000 /* Magic ID for Emscripten 'default display' */ : 0; + }, + // EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface); eglSwapBuffers: function() { EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); diff --git a/src/library_gl.js b/src/library_gl.js index 4b6ea579..630f116c 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -41,7 +41,11 @@ var LibraryGL = { 8 // GL_DOUBLE ], - uniformTable: {}, // name => uniform ID. the uID must be identical until relinking, cannot create a new uID each call to glGetUniformLocation + programInfos: {}, // Stores additional information needed for each shader program. Each entry is of form: + /* { uniforms: {}, // Maps ints back to the opaque WebGLUniformLocation objects. + maxUniformLength: int, // Cached in order to implement glGetProgramiv(GL_ACTIVE_UNIFORM_MAX_LENGTH) + maxAttributeLength: int // Cached in order to implement glGetProgramiv(GL_ACTIVE_ATTRIBUTE_MAX_LENGTH) + } */ stringCache: {}, @@ -463,15 +467,23 @@ var LibraryGL = { GL.validateGLObjectID(GL.programs, program, 'populateUniformTable', 'program'); #endif var p = GL.programs[program]; - GL.uniformTable[program] = {}; - var ptable = GL.uniformTable[program]; - // A program's uniformTable maps the string name of an uniform to an integer location of that uniform. + GL.programInfos[program] = { + uniforms: {}, + maxUniformLength: 0, // This is eagerly computed below, since we already enumerate all uniforms anyway. + maxAttributeLength: -1 // This is lazily computed and cached, computed when/if first asked, "-1" meaning not computed yet. + }; + + var ptable = GL.programInfos[program]; + var utable = ptable.uniforms; + // A program's uniform table maps the string name of an uniform to an integer location of that uniform. // The global GL.uniforms map maps integer locations to WebGLUniformLocations. var numUniforms = Module.ctx.getProgramParameter(p, Module.ctx.ACTIVE_UNIFORMS); for (var i = 0; i < numUniforms; ++i) { var u = Module.ctx.getActiveUniform(p, i); var name = u.name; + ptable.maxUniformLength = Math.max(ptable.maxUniformLength, name.length+1); + // Strip off any trailing array specifier we might have got, e.g. "[0]". if (name.indexOf(']', name.length-1) !== -1) { var ls = name.lastIndexOf('['); @@ -479,11 +491,11 @@ var LibraryGL = { } // Optimize memory usage slightly: If we have an array of uniforms, e.g. 'vec3 colors[3];', then - // only store the string 'colors' in ptable, and 'colors[0]', 'colors[1]' and 'colors[2]' will be parsed as 'colors'+i. + // only store the string 'colors' in utable, and 'colors[0]', 'colors[1]' and 'colors[2]' will be parsed as 'colors'+i. // Note that for the GL.uniforms table, we still need to fetch the all WebGLUniformLocations for all the indices. var loc = Module.ctx.getUniformLocation(p, name); var id = GL.getNewId(GL.uniforms); - ptable[name] = [u.size, id]; + utable[name] = [u.size, id]; GL.uniforms[id] = loc; for (var j = 1; j < u.size; ++j) { @@ -1002,11 +1014,12 @@ var LibraryGL = { name = name.slice(0, ls); } - var ptable = GL.uniformTable[program]; + var ptable = GL.programInfos[program]; if (!ptable) { return -1; } - var uniformInfo = ptable[name]; // returns pair [ dimension_of_uniform_array, uniform_location ] + var utable = ptable.uniforms; + var uniformInfo = utable[name]; // returns pair [ dimension_of_uniform_array, uniform_location ] if (uniformInfo && arrayOffset < uniformInfo[0]) { // Check if user asked for an out-of-bounds element, i.e. for 'vec4 colors[3];' user could ask for 'colors[10]' which should return -1. return uniformInfo[1]+arrayOffset; } else { @@ -1494,6 +1507,47 @@ var LibraryGL = { #endif if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH {{{ makeSetValue('p', '0', 'Module.ctx.getProgramInfoLog(GL.programs[program]).length + 1', 'i32') }}}; + } else if (pname == 0x8B87 /* GL_ACTIVE_UNIFORM_MAX_LENGTH */) { + var ptable = GL.programInfos[program]; + if (ptable) { + {{{ makeSetValue('p', '0', 'ptable.maxUniformLength', 'i32') }}}; + return; + } else if (program < GL.counter) { +#if GL_ASSERTIONS + Module.printErr("A GL object " + program + " that is not a program object was passed to glGetProgramiv!"); +#endif + GL.recordError(0x0502 /* GL_INVALID_OPERATION */); + } else { +#if GL_ASSERTIONS + Module.printErr("A GL object " + program + " that did not come from GL was passed to glGetProgramiv!"); +#endif + GL.recordError(0x0501 /* GL_INVALID_VALUE */); + } + } else if (pname == 0x8B8A /* GL_ACTIVE_ATTRIBUTE_MAX_LENGTH */) { + var ptable = GL.programInfos[program]; + if (ptable) { + if (ptable.maxAttributeLength == -1) { + var program = GL.programs[program]; + var numAttribs = Module.ctx.getProgramParameter(program, Module.ctx.ACTIVE_ATTRIBUTES); + ptable.maxAttributeLength = 0; // Spec says if there are no active attribs, 0 must be returned. + for(var i = 0; i < numAttribs; ++i) { + var activeAttrib = Module.ctx.getActiveAttrib(program, i); + ptable.maxAttributeLength = Math.max(ptable.maxAttributeLength, activeAttrib.name.length+1); + } + } + {{{ makeSetValue('p', '0', 'ptable.maxAttributeLength', 'i32') }}}; + return; + } else if (program < GL.counter) { +#if GL_ASSERTIONS + Module.printErr("A GL object " + program + " that is not a program object was passed to glGetProgramiv!"); +#endif + GL.recordError(0x0502 /* GL_INVALID_OPERATION */); + } else { +#if GL_ASSERTIONS + Module.printErr("A GL object " + program + " that did not come from GL was passed to glGetProgramiv!"); +#endif + GL.recordError(0x0501 /* GL_INVALID_VALUE */); + } } else { {{{ makeSetValue('p', '0', 'Module.ctx.getProgramParameter(GL.programs[program], pname)', 'i32') }}}; } @@ -1521,7 +1575,7 @@ var LibraryGL = { Module.ctx.deleteProgram(program); program.name = 0; GL.programs[program] = null; - GL.uniformTable[program] = null; + GL.programInfos[program] = null; }, glAttachShader__sig: 'vii', @@ -1557,7 +1611,7 @@ var LibraryGL = { GL.validateGLObjectID(GL.programs, program, 'glLinkProgram', 'program'); #endif Module.ctx.linkProgram(GL.programs[program]); - GL.uniformTable[program] = {}; // uniforms no longer keep the same names after linking + GL.programInfos[program] = null; // uniforms no longer keep the same names after linking GL.populateUniformTable(program); }, diff --git a/src/settings.js b/src/settings.js index 0d8d3da5..bc665973 100644 --- a/src/settings.js +++ b/src/settings.js @@ -390,13 +390,16 @@ var FAKE_X86_FP80 = 1; // Replaces x86_fp80 with double. This loses precision. I var GC_SUPPORT = 1; // Enables GC, see gc.h (this does not add overhead, so it is on by default) -var WARN_ON_UNDEFINED_SYMBOLS = 0; // If set to 1, we will warn on any undefined symbols that - // are not resolved by the library_*.js files. We by default - // do not warn because (1) it is normal in large projects to +var WARN_ON_UNDEFINED_SYMBOLS = 1; // If set to 1, we will warn on any undefined symbols that + // are not resolved by the library_*.js files. Note that + // it is common in large projects to // not implement everything, when you know what is not // going to actually be called (and don't want to mess with - // the existing buildsystem), and (2) functions might be - // implemented later on, say in --pre-js + // the existing buildsystem), and functions might be + // implemented later on, say in --pre-js, so you may + // want to build with -s WARN_ON_UNDEFINED_SYMBOLS=0 to + // disable the warnings if they annoy you. + // See also ERROR_ON_UNDEFINED_SYMBOLS var ERROR_ON_UNDEFINED_SYMBOLS = 0; // If set to 1, we will give a compile-time error on any // undefined symbols (see WARN_ON_UNDEFINED_SYMBOLS). diff --git a/src/utility.js b/src/utility.js index bec0eb8f..cd27b209 100644 --- a/src/utility.js +++ b/src/utility.js @@ -68,7 +68,7 @@ function warn(a, msg) { a = false; } if (!a) { - printErr('Warning: ' + msg); + printErr('warning: ' + msg); } } @@ -81,7 +81,7 @@ function warnOnce(a, msg) { if (!warnOnce.msgs) warnOnce.msgs = {}; if (msg in warnOnce.msgs) return; warnOnce.msgs[msg] = true; - printErr('Warning: ' + msg); + printErr('warning: ' + msg); } } @@ -89,7 +89,7 @@ var abortExecution = false; function error(msg) { abortExecution = true; - printErr('Error: ' + msg); + printErr('error: ' + msg); } function dedup(items, ident) { diff --git a/tests/gles2_uniform_arrays.cpp b/tests/gles2_uniform_arrays.cpp index 84e394dc..7293f9a9 100644 --- a/tests/gles2_uniform_arrays.cpp +++ b/tests/gles2_uniform_arrays.cpp @@ -35,6 +35,15 @@ void RunTest(int testVariant) glBindAttribLocation(program, 0, "pos"); glLinkProgram(program); + // Also test that GL_ACTIVE_ATTRIBUTE_MAX_LENGTH and GL_ACTIVE_UNIFORM_MAX_LENGTH work. See https://github.com/kripken/emscripten/issues/1796. + GLint param; + glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, ¶m); + printf("active attrib max length: %d\n", param); + assert(param == 4); // "pos"+null terminator + glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, ¶m); + printf("active uniform max length: %d\n", param); + assert(param == 10); // "colors[0]"+null terminator + int color_loc = glGetUniformLocation(program, "color"); assert(color_loc != -1); diff --git a/tests/test_benchmark.py b/tests/test_benchmark.py index 011ab256..63e0041f 100644 --- a/tests/test_benchmark.py +++ b/tests/test_benchmark.py @@ -420,7 +420,7 @@ process(sys.argv[1]) return 100.0/float(re.search('Unrolled Double Precision +([\d\.]+) Mflops', output).group(1)) self.do_benchmark('linpack_double', open(path_from_root('tests', 'linpack.c')).read(), '''Unrolled Double Precision''', force_c=True, output_parser=output_parser) - def test_linpack_float(self): + def test_linpack_float(self): # TODO: investigate if this might benefit from -ffast-math in LLVM 3.3+ which has fast math stuff in LLVM IR def output_parser(output): return 100.0/float(re.search('Unrolled Single Precision +([\d\.]+) Mflops', output).group(1)) self.do_benchmark('linpack_float', open(path_from_root('tests', 'linpack.c')).read(), '''Unrolled Single Precision''', force_c=True, output_parser=output_parser, shared_args=['-DSP']) diff --git a/tests/test_browser.py b/tests/test_browser.py index 1900e2cf..111702e6 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -1147,6 +1147,12 @@ keydown(100);keyup(100); // trigger the end Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'glfw.c'), '-o', 'page.html', '-s', 'LEGACY_GL_EMULATION=1']).communicate() self.run_browser('page.html', '', '/report_result?1') + def test_egl(self): + open(os.path.join(self.get_dir(), 'test_egl.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'test_egl.c')).read())) + + Popen([PYTHON, EMCC, '-O2', os.path.join(self.get_dir(), 'test_egl.c'), '-o', 'page.html']).communicate() + self.run_browser('page.html', '', '/report_result?1') + def test_egl_width_height(self): open(os.path.join(self.get_dir(), 'test_egl_width_height.c'), 'w').write(self.with_report_result(open(path_from_root('tests', 'test_egl_width_height.c')).read())) diff --git a/tests/test_egl.c b/tests/test_egl.c new file mode 100644 index 00000000..5864a797 --- /dev/null +++ b/tests/test_egl.c @@ -0,0 +1,73 @@ +#include <stdio.h> +#include <EGL/egl.h> + +int result = 1; // Success +#define assert(x) do { if (!(x)) {result = 0; printf("Assertion failure: %s in %s:%d!\n", #x, __FILE__, __LINE__); } } while(0) + +int main(int argc, char *argv[]) +{ + EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + assert(display != EGL_NO_DISPLAY); + assert(eglGetError() == EGL_SUCCESS); + + EGLint major = 0, minor = 0; + EGLBoolean ret = eglInitialize(display, &major, &minor); + assert(eglGetError() == EGL_SUCCESS); + assert(ret == EGL_TRUE); + assert(major * 10000 + minor >= 10004); + + EGLint numConfigs; + ret = eglGetConfigs(display, NULL, 0, &numConfigs); + assert(eglGetError() == EGL_SUCCESS); + assert(ret == EGL_TRUE); + + EGLint attribs[] = { + EGL_RED_SIZE, 5, + EGL_GREEN_SIZE, 6, + EGL_BLUE_SIZE, 5, + EGL_NONE + }; + EGLConfig config; + ret = eglChooseConfig(display, attribs, &config, 1, &numConfigs); + assert(eglGetError() == EGL_SUCCESS); + assert(ret == EGL_TRUE); + + EGLNativeWindowType dummyWindow; + EGLSurface surface = eglCreateWindowSurface(display, config, dummyWindow, NULL); + assert(eglGetError() == EGL_SUCCESS); + assert(surface != 0); + + EGLint contextAttribs[] = + { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + EGLContext context = eglCreateContext(display, config, NULL, contextAttribs); + assert(eglGetError() == EGL_SUCCESS); + assert(context != 0); + + assert(eglGetCurrentContext() == 0); // Creating a context does not yet activate it. + assert(eglGetError() == EGL_SUCCESS); + + ret = eglMakeCurrent(display, surface, surface, context); + assert(eglGetError() == EGL_SUCCESS); + assert(ret == EGL_TRUE); + assert(eglGetCurrentContext() == context); + assert(eglGetCurrentSurface(EGL_READ) == surface); + assert(eglGetCurrentSurface(EGL_DRAW) == surface); + + ret = eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + assert(eglGetError() == EGL_SUCCESS); + assert(ret == EGL_TRUE); + assert(eglGetCurrentContext() == EGL_NO_CONTEXT); + assert(eglGetCurrentSurface(EGL_READ) == EGL_NO_SURFACE); + assert(eglGetCurrentSurface(EGL_DRAW) == EGL_NO_SURFACE); + + ret = eglTerminate(display); + assert(eglGetError() == EGL_SUCCESS); + assert(ret == EGL_TRUE); + +#ifdef REPORT_RESULT + REPORT_RESULT(); +#endif +} diff --git a/tests/test_other.py b/tests/test_other.py index fafa6d33..beb6e5b2 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -819,8 +819,12 @@ f.close() }), ]: Building.COMPILER_TEST_OPTS = test_opts + if WINDOWS: + zlib_library = self.get_library('zlib', os.path.join('libz.a'), configure=['emconfigure.bat'], configure_args=['cmake', '.', '-DBUILD_SHARED_LIBS=OFF'], make=['mingw32-make'], make_args=[]) + else: + zlib_library = self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a']) test('zlib', path_from_root('tests', 'zlib', 'example.c'), - self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a']), + zlib_library, open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(), expected_ranges, args=['-I' + path_from_root('tests', 'zlib')], suffix='c') @@ -1440,10 +1444,12 @@ f.close() extern "C" { void something(); + void elsey(); } int main() { something(); + elsey(); return 0; } ''') @@ -1451,26 +1457,24 @@ f.close() def clear(): try_delete('a.out.js') for args in [[], ['-O2']]: - clear() - print 'warn', args - output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-s', 'WARN_ON_UNDEFINED_SYMBOLS=1'] + args, stderr=PIPE).communicate() - self.assertContained('unresolved symbol: something', output[1]) - - clear() - output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp')] + args, stderr=PIPE).communicate() - self.assertNotContained('unresolved symbol: something\n', output[1]) - - for args in [[], ['-O2']]: - clear() - print 'error', args - output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp'), '-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1'] + args, stderr=PIPE).communicate() - self.assertContained('unresolved symbol: something', output[1]) - assert not os.path.exists('a.out.js') - - clear() - output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp')] + args, stderr=PIPE).communicate() - self.assertNotContained('unresolved symbol: something\n', output[1]) - assert os.path.exists('a.out.js') + for action in ['WARN', 'ERROR', None]: + for value in ([0, 1] if action else [0]): + clear() + print 'warn', args, action, value + extra = ['-s', action + '_ON_UNDEFINED_SYMBOLS=%d' % value] if action else [] + output = Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.cpp')] + extra + args, stderr=PIPE).communicate() + if action == None or (action == 'WARN' and value): + self.assertContained('unresolved symbol: something', output[1]) + self.assertContained('unresolved symbol: elsey', output[1]) + assert os.path.exists('a.out.js') + elif action == 'ERROR' and value: + self.assertContained('unresolved symbol: something', output[1]) + self.assertContained('unresolved symbol: elsey', output[1]) + self.assertNotContained('warning', output[1]) + assert not os.path.exists('a.out.js') + elif action == 'WARN' and not value: + self.assertNotContained('unresolved symbol', output[1]) + assert os.path.exists('a.out.js') def test_toobig(self): # very large [N x i8], we should not oom in the compiler @@ -1909,7 +1913,8 @@ done. out, err = Popen([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-E'], stdout=PIPE).communicate() assert not os.path.exists('a.out.js') - assert '''tests/hello_world.c"''' in out + assert '''#line 1 ''' in out + assert '''hello_world.c"''' in out assert '''printf("hello, world!''' in out def test_demangle(self): diff --git a/tests/zlib/CMakeLists.txt b/tests/zlib/CMakeLists.txt new file mode 100644 index 00000000..01a19fb5 --- /dev/null +++ b/tests/zlib/CMakeLists.txt @@ -0,0 +1,190 @@ +cmake_minimum_required(VERSION 2.4.4) +set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) + +project(zlib C) + +if(NOT DEFINED BUILD_SHARED_LIBS) + option(BUILD_SHARED_LIBS "Build a shared library form of zlib" ON) +endif() + +include(CheckTypeSize) +include(CheckFunctionExists) +include(CheckIncludeFile) +include(CheckCSourceCompiles) +enable_testing() + +check_include_file(sys/types.h HAVE_SYS_TYPES_H) +check_include_file(stdint.h HAVE_STDINT_H) +check_include_file(stddef.h HAVE_STDDEF_H) + +# +# Check to see if we have large file support +# +set(CMAKE_REQUIRED_DEFINITIONS -D_LARGEFILE64_SOURCE=1) +# We add these other definitions here because CheckTypeSize.cmake +# in CMake 2.4.x does not automatically do so and we want +# compatibility with CMake 2.4.x. +if(HAVE_SYS_TYPES_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_SYS_TYPES_H) +endif() +if(HAVE_STDINT_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDINT_H) +endif() +if(HAVE_STDDEF_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDDEF_H) +endif() +check_type_size(off64_t OFF64_T) +if(HAVE_OFF64_T) + add_definitions(-D_LARGEFILE64_SOURCE=1) +endif() +set(CMAKE_REQUIRED_DEFINITIONS) # clear variable + +# +# Check for fseeko +# +check_function_exists(fseeko HAVE_FSEEKO) +if(NOT HAVE_FSEEKO) + add_definitions(-DNO_FSEEKO) +endif() + +# +# Check for unistd.h +# +check_include_file(unistd.h Z_HAVE_UNISTD_H) + +if(MSVC) + set(CMAKE_DEBUG_POSTFIX "d") + add_definitions(-D_CRT_SECURE_NO_DEPRECATE) + add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE) +endif() + +if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) + # If we're doing an out of source build and the user has a zconf.h + # in their source tree... + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h) + message(FATAL_ERROR + "You must remove ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h " + "from the source tree. This file is included with zlib " + "but CMake generates this file for you automatically " + "in the build directory.") + endif() +endif() + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.cmakein + ${CMAKE_CURRENT_BINARY_DIR}/zconf.h @ONLY) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + + +#============================================================================ +# zlib +#============================================================================ + +set(ZLIB_PUBLIC_HDRS + ${CMAKE_CURRENT_BINARY_DIR}/zconf.h + zlib.h +) +set(ZLIB_PRIVATE_HDRS + crc32.h + deflate.h + gzguts.h + inffast.h + inffixed.h + inflate.h + inftrees.h + trees.h + zutil.h +) +set(ZLIB_SRCS + adler32.c + compress.c + crc32.c + deflate.c + gzclose.c + gzlib.c + gzread.c + gzwrite.c + inflate.c + infback.c + inftrees.c + inffast.c + trees.c + uncompr.c + zutil.c +# win32/zlib1.rc XXX Emscripten remove the Windows resource file from build, not needed and not included in source tree. +) + +# parse the full version number from zlib.h and include in ZLIB_FULL_VERSION +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents) +string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([0-9A-Za-z.]+)\".*" + "\\1" ZLIB_FULL_VERSION ${_zlib_h_contents}) + +if(MINGW) + # This gets us DLL resource information when compiling on MinGW. + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj + COMMAND windres.exe + -D GCC_WINDRES + -I ${CMAKE_CURRENT_SOURCE_DIR} + -I ${CMAKE_CURRENT_BINARY_DIR} + -o ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj + -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zlib1.rc) + set(ZLIB_SRCS ${ZLIB_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) +endif(MINGW) + +add_library(zlib ${ZLIB_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL) + +set_target_properties(zlib PROPERTIES SOVERSION 1) + +if(NOT CYGWIN) + # This property causes shared libraries on Linux to have the full version + # encoded into their final filename. We disable this on Cygwin because + # it causes cygz-${ZLIB_FULL_VERSION}.dll to be created when cygz.dll + # seems to be the default. + # + # This has no effect with MSVC, on that platform the version info for + # the DLL comes from the resource file win32/zlib1.rc + set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION}) +endif() + +if(UNIX) + # On unix-like platforms the library is almost always called libz + set_target_properties(zlib PROPERTIES OUTPUT_NAME z) +elseif(BUILD_SHARED_LIBS AND WIN32) + # Creates zlib1.dll when building shared library version + set_target_properties(zlib PROPERTIES SUFFIX "1.dll") +endif() + +if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) + install(TARGETS zlib + RUNTIME DESTINATION bin + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib ) +endif() +if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL ) + install(FILES ${ZLIB_PUBLIC_HDRS} DESTINATION include) +endif() +if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) + install(FILES zlib.3 DESTINATION share/man/man3) +endif() + +#============================================================================ +# Example binaries +#============================================================================ + +add_executable(example example.c) +target_link_libraries(example zlib) +add_test(example example) + +add_executable(minigzip minigzip.c) +target_link_libraries(minigzip zlib) + +if(HAVE_OFF64_T) + add_executable(example64 example.c) + target_link_libraries(example64 zlib) + set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") + add_test(example64 example64) + + add_executable(minigzip64 minigzip.c) + target_link_libraries(minigzip64 zlib) + set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") +endif() diff --git a/tests/zlib/zconf.h b/tests/zlib/zconf.h.cmakein index b2343874..a2f71b1f 100644 --- a/tests/zlib/zconf.h +++ b/tests/zlib/zconf.h.cmakein @@ -7,6 +7,8 @@ #ifndef ZCONF_H #define ZCONF_H +#cmakedefine Z_PREFIX +#cmakedefine Z_HAVE_UNISTD_H /* * If you *really* need a unique prefix for all types and library functions, @@ -356,7 +358,7 @@ typedef uLong FAR uLongf; typedef Byte *voidp; #endif -#if 1 /* was set to #if 1 by ./configure */ +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_UNISTD_H #endif |