diff --git a/cmake/Modules/CMakeSystemSpecificInformation.cmake b/cmake/Modules/CMakeSystemSpecificInformation.cmake new file mode 100644 index 0000000000000..cc223a63afb24 --- /dev/null +++ b/cmake/Modules/CMakeSystemSpecificInformation.cmake @@ -0,0 +1,123 @@ +# XXX Emscripten: +# This file is copied as-is from the CMake source tree. Due to how CMake +# platform toolchain files work, we must have a copy of this file located +# relative to Emscripten platform toolchain file, or file inclusion order +# in cmGlobalGenerator::EnableLanguage will not find Emscripten.cmake +# toolchain file, and as a result, it is not possible to set the default +# compilation output suffix to .js, and as a consequence the script +# check_function_exists() will not function properly (it will try to +# build to wrong file suffix) + +# CMake - Cross Platform Makefile Generator +# Copyright 2000-2014 Kitware, Inc. +# Copyright 2000-2011 Insight Software Consortium +# All rights reserved. + +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: + +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. + +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. + +# * Neither the names of Kitware, Inc., the Insight Software Consortium, +# nor the names of their contributors may be used to endorse or promote +# products derived from this software without specific prior written +# permission. + +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# ------------------------------------------------------------------------------ + +# The above copyright and license notice applies to distributions of +# CMake in source and binary form. Some source files contain additional +# notices of original copyright by their contributors; see each source +# for details. Third-party software packages supplied with CMake under +# compatible licenses provide their own copyright notices documented in +# corresponding subdirectories. + +# ------------------------------------------------------------------------------ + +# CMake was initially developed by Kitware with the following sponsorship: + +# * National Library of Medicine at the National Institutes of Health +# as part of the Insight Segmentation and Registration Toolkit (ITK). + +# * US National Labs (Los Alamos, Livermore, Sandia) ASC Parallel +# Visualization Initiative. + +# * National Alliance for Medical Image Computing (NAMIC) is funded by the +# National Institutes of Health through the NIH Roadmap for Medical Research, +# Grant U54 EB005149. + +# * Kitware, Inc. + +# This file is included by cmGlobalGenerator::EnableLanguage. +# It is included after the compiler has been determined, so +# we know things like the compiler name and if the compiler is gnu. + +# before cmake 2.6 these variables were set in cmMakefile.cxx. This is still +# done to keep scripts and custom language and compiler modules working. +# But they are reset here and set again in the platform files for the target +# platform, so they can be used for testing the target platform instead +# of testing the host platform. +set(APPLE ) +set(UNIX ) +set(CYGWIN ) +set(WIN32 ) + + +# include Generic system information +include(CMakeGenericSystem) + +# 2. now include SystemName.cmake file to set the system specific information +set(CMAKE_SYSTEM_INFO_FILE Platform/${CMAKE_SYSTEM_NAME}) + +include(${CMAKE_SYSTEM_INFO_FILE} OPTIONAL RESULT_VARIABLE _INCLUDED_SYSTEM_INFO_FILE) + +if(NOT _INCLUDED_SYSTEM_INFO_FILE) + message("System is unknown to cmake, create:\n${CMAKE_SYSTEM_INFO_FILE}" + " to use this system, please send your config file to " + "cmake@www.cmake.org so it can be added to cmake") + if(EXISTS ${CMAKE_BINARY_DIR}/CMakeCache.txt) + configure_file(${CMAKE_BINARY_DIR}/CMakeCache.txt + ${CMAKE_BINARY_DIR}/CopyOfCMakeCache.txt COPYONLY) + message("Your CMakeCache.txt file was copied to CopyOfCMakeCache.txt. " + "Please send that file to cmake@www.cmake.org.") + endif() +endif() + + +# optionally include a file which can do extra-generator specific things, e.g. +# CMakeFindEclipseCDT4.cmake asks gcc for the system include dirs for the Eclipse CDT4 generator +if(CMAKE_EXTRA_GENERATOR) + string(REPLACE " " "" _CMAKE_EXTRA_GENERATOR_NO_SPACES ${CMAKE_EXTRA_GENERATOR} ) + include("CMakeFind${_CMAKE_EXTRA_GENERATOR_NO_SPACES}" OPTIONAL) +endif() + + +# for most systems a module is the same as a shared library +# so unless the variable CMAKE_MODULE_EXISTS is set just +# copy the values from the LIBRARY variables +# this has to be done after the system information has been loaded +if(NOT CMAKE_MODULE_EXISTS) + set(CMAKE_SHARED_MODULE_PREFIX "${CMAKE_SHARED_LIBRARY_PREFIX}") + set(CMAKE_SHARED_MODULE_SUFFIX "${CMAKE_SHARED_LIBRARY_SUFFIX}") +endif() + + +set(CMAKE_SYSTEM_SPECIFIC_INFORMATION_LOADED 1) diff --git a/cmake/Platform/Emscripten.cmake b/cmake/Modules/Platform/Emscripten.cmake similarity index 85% rename from cmake/Platform/Emscripten.cmake rename to cmake/Modules/Platform/Emscripten.cmake index 553296396a62e..acfa31837577c 100644 --- a/cmake/Platform/Emscripten.cmake +++ b/cmake/Modules/Platform/Emscripten.cmake @@ -3,7 +3,7 @@ # from CMakeLists.txt that invoke emcc. # To use this toolchain file with CMake, invoke CMake with the following command line parameters -# cmake -DCMAKE_TOOLCHAIN_FILE=/cmake/Platform/Emscripten.cmake +# cmake -DCMAKE_TOOLCHAIN_FILE=/cmake/Modules/Platform/Emscripten.cmake # -DCMAKE_BUILD_TYPE= # -G "Unix Makefiles" (Linux and OSX) # -G "MinGW Makefiles" (Windows) @@ -12,20 +12,36 @@ # After that, build the generated Makefile with the command 'make'. On Windows, you may download and use 'mingw32-make' instead. # The following variable describes the target OS we are building to. -# Ideally, this could be 'Emscripten', but as Emscripten mimics the Linux platform, setting this to Linux will allow more of existing software to build. -# Be sure to run Emscripten test_openjpeg if planning to change this. -set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_SYSTEM_NAME Emscripten) set(CMAKE_SYSTEM_VERSION 1) set(CMAKE_CROSSCOMPILING TRUE) +# Tell CMake how it should instruct the compiler to generate multiple versions of an outputted .so library: e.g. "libfoo.so, libfoo.so.1, libfoo.so.1.4" etc. +# This feature is activated if a shared library project has the property SOVERSION defined. +set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-Wl,-soname,") + +# In CMake, CMAKE_HOST_WIN32 is set when we are cross-compiling from Win32 to Emscripten: http://www.cmake.org/cmake/help/v2.8.12/cmake.html#variable:CMAKE_HOST_WIN32 +# The variable WIN32 is set only when the target arch that will run the code will be WIN32, so unset WIN32 when cross-compiling. +set(WIN32) + +# The same logic as above applies for APPLE and CMAKE_HOST_APPLE, so unset APPLE. +set(APPLE) + +# And for UNIX and CMAKE_HOST_UNIX. However, Emscripten is often able to mimic being a Linux/Unix system, in which case a lot of existing CMakeLists.txt files can be configured for Emscripten while assuming UNIX build, so this is left enabled. +set(UNIX 1) + # Do a no-op access on the CMAKE_TOOLCHAIN_FILE variable so that CMake will not issue a warning on it being unused. if (CMAKE_TOOLCHAIN_FILE) endif() +# In order for check_function_exists() detection to work, we must signal it to pass an additional flag, which causes the compilation +# to abort if linking results in any undefined symbols. The CMake detection mechanism depends on the undefined symbol error to be raised. +set(CMAKE_REQUIRED_FLAGS "-s ERROR_ON_UNDEFINED_SYMBOLS=1") + # Locate where the Emscripten compiler resides in relative to this toolchain file. if ("${EMSCRIPTEN_ROOT_PATH}" STREQUAL "") - get_filename_component(GUESS_EMSCRIPTEN_ROOT_PATH "${CMAKE_CURRENT_LIST_DIR}/../../" ABSOLUTE) + get_filename_component(GUESS_EMSCRIPTEN_ROOT_PATH "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) if (EXISTS "${GUESS_EMSCRIPTEN_ROOT_PATH}/emranlib") set(EMSCRIPTEN_ROOT_PATH "${GUESS_EMSCRIPTEN_ROOT_PATH}") endif() @@ -92,9 +108,7 @@ set(CMAKE_SYSTEM_INCLUDE_PATH "${EMSCRIPTEN_ROOT_PATH}/system/include") #SET(CMAKE_STATIC_LIBRARY_SUFFIX ".bc") #SET(CMAKE_SHARED_LIBRARY_PREFIX "") #SET(CMAKE_SHARED_LIBRARY_SUFFIX ".bc") -#IF (NOT CMAKE_EXECUTABLE_SUFFIX) -# SET(CMAKE_EXECUTABLE_SUFFIX ".js") -#endif() +SET(CMAKE_EXECUTABLE_SUFFIX ".js") #SET(CMAKE_FIND_LIBRARY_PREFIXES "") #SET(CMAKE_FIND_LIBRARY_SUFFIXES ".bc") @@ -115,13 +129,26 @@ set(CMAKE_CXX_CREATE_STATIC_LIBRARY " rc 0: Prevent JS optimizer from running 1: Use JS optimizer (default) --llvm-opts 0: No LLVM optimizations (default in -O0) @@ -1264,6 +1264,8 @@ try: if value[0] == '@': value = '"@' + os.path.abspath(value[1:]) + '"' value = value.replace('\\\\', '/').replace('\\', '/') # Convert backslash paths to forward slashes on Windows as well, since the JS compiler otherwise needs the backslashes escaped (alternative is to escape all input paths passing to JS, which feels clumsier to read) + else: + value = value.replace('\\', '\\\\') exec('shared.Settings.' + key + ' = ' + value) if key == 'EXPORTED_FUNCTIONS': shared.Settings.ORIGINAL_EXPORTED_FUNCTIONS = shared.Settings.EXPORTED_FUNCTIONS[:] # used for warnings in emscripten.py diff --git a/emscripten-version.txt b/emscripten-version.txt index 6318f23258fc9..a08cf9edbab03 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1,2 +1,2 @@ -1.21.3 +1.21.4 diff --git a/emscripten.py b/emscripten.py index 45063947e930c..821871273ad19 100755 --- a/emscripten.py +++ b/emscripten.py @@ -853,8 +853,9 @@ def save_settings(): # Call js compiler if DEBUG: t = time.time() - out = jsrun.run_js(path_from_root('src', 'compiler.js'), compiler_engine, [settings_file, ';', 'glue'] + libraries, stdout=subprocess.PIPE, stderr=STDERR_FILE, - cwd=path_from_root('src')) + out = jsrun.run_js(path_from_root('src', 'compiler.js'), compiler_engine, + [settings_file, ';', 'glue'] + libraries, stdout=subprocess.PIPE, stderr=STDERR_FILE, + cwd=path_from_root('src'), error_limit=300) assert '//FORWARDED_DATA:' in out, 'Did not receive forwarded data in pre output - process failed?' glue, forwarded_data = out.split('//FORWARDED_DATA:') diff --git a/scons-tools/emscripten.py b/scons-tools/emscripten.py index 738c0d8e05f87..c82f43c87d9c8 100755 --- a/scons-tools/emscripten.py +++ b/scons-tools/emscripten.py @@ -42,7 +42,7 @@ def touch_file(target, source, env): env.AddPostAction( emscripten_version_file, - Delete(env.Dir('$EMSCRIPTEN_TEMP_DIR').abspath)) + Delete(env.Dir('$EMSCRIPTEN_TEMP_DIR/cache/jcache').abspath)) return emscripten_version_file @@ -150,21 +150,159 @@ def buildName(extension): 'system/lib/dlmalloc.c', 'system/lib/libc/musl/src/internal/floatscan.c', 'system/lib/libc/musl/src/internal/shgetc.c', - 'system/lib/libc/musl/src/math/scalbn.c', - 'system/lib/libc/musl/src/math/scalbnl.c', + 'system/lib/libc/musl/src/ctype/isalnum.c', + 'system/lib/libc/musl/src/ctype/isalpha.c', + 'system/lib/libc/musl/src/ctype/isascii.c', + 'system/lib/libc/musl/src/ctype/isblank.c', + 'system/lib/libc/musl/src/ctype/iscntrl.c', + 'system/lib/libc/musl/src/ctype/isdigit.c', + 'system/lib/libc/musl/src/ctype/isgraph.c', + 'system/lib/libc/musl/src/ctype/islower.c', + 'system/lib/libc/musl/src/ctype/isprint.c', + 'system/lib/libc/musl/src/ctype/ispunct.c', + 'system/lib/libc/musl/src/ctype/isspace.c', + 'system/lib/libc/musl/src/ctype/isupper.c', + 'system/lib/libc/musl/src/ctype/iswalnum.c', + 'system/lib/libc/musl/src/ctype/iswalpha.c', + 'system/lib/libc/musl/src/ctype/iswblank.c', + 'system/lib/libc/musl/src/ctype/iswcntrl.c', + 'system/lib/libc/musl/src/ctype/iswctype.c', + 'system/lib/libc/musl/src/ctype/iswdigit.c', + 'system/lib/libc/musl/src/ctype/iswgraph.c', + 'system/lib/libc/musl/src/ctype/iswlower.c', + 'system/lib/libc/musl/src/ctype/iswprint.c', + 'system/lib/libc/musl/src/ctype/iswpunct.c', + 'system/lib/libc/musl/src/ctype/iswspace.c', + 'system/lib/libc/musl/src/ctype/iswupper.c', + 'system/lib/libc/musl/src/ctype/iswxdigit.c', + 'system/lib/libc/musl/src/ctype/isxdigit.c', + 'system/lib/libc/musl/src/ctype/toascii.c', + 'system/lib/libc/musl/src/ctype/toupper.c', + 'system/lib/libc/musl/src/ctype/towctrans.c', + 'system/lib/libc/musl/src/ctype/wcswidth.c', + 'system/lib/libc/musl/src/ctype/wctrans.c', + 'system/lib/libc/musl/src/ctype/wcwidth.c', + 'system/lib/libc/musl/src/ctype/tolower.c', + 'system/lib/libc/musl/src/stdio/__overflow.c', + 'system/lib/libc/musl/src/stdio/__string_read.c', 'system/lib/libc/musl/src/stdio/__toread.c', 'system/lib/libc/musl/src/stdio/__towrite.c', 'system/lib/libc/musl/src/stdio/__uflow.c', + 'system/lib/libc/musl/src/stdio/asprintf.c', + 'system/lib/libc/musl/src/stdio/fputwc.c', + 'system/lib/libc/musl/src/stdio/fputws.c', + 'system/lib/libc/musl/src/stdio/fwprintf.c', + 'system/lib/libc/musl/src/stdio/fwrite.c', + 'system/lib/libc/musl/src/stdio/snprintf.c', + 'system/lib/libc/musl/src/stdio/sprintf.c', + 'system/lib/libc/musl/src/stdio/sscanf.c', + 'system/lib/libc/musl/src/stdio/swprintf.c', + 'system/lib/libc/musl/src/stdio/vasprintf.c', + 'system/lib/libc/musl/src/stdio/vfprintf.c', + 'system/lib/libc/musl/src/stdio/vfscanf.c', + 'system/lib/libc/musl/src/stdio/vfwprintf.c', + 'system/lib/libc/musl/src/stdio/vsnprintf.c', + 'system/lib/libc/musl/src/stdio/vsprintf.c', + 'system/lib/libc/musl/src/stdio/vsscanf.c', + 'system/lib/libc/musl/src/stdio/vswprintf.c', + 'system/lib/libc/musl/src/stdio/vwprintf.c', + 'system/lib/libc/musl/src/stdio/wprintf.c', + 'system/lib/libc/musl/src/stdlib/atof.c', 'system/lib/libc/musl/src/stdlib/strtod.c', + + 'system/lib/libc/musl/src/string/bcmp.c', + 'system/lib/libc/musl/src/string/bcopy.c', + 'system/lib/libc/musl/src/string/bzero.c', + 'system/lib/libc/musl/src/string/index.c', + 'system/lib/libc/musl/src/string/memccpy.c', + 'system/lib/libc/musl/src/string/memchr.c', 'system/lib/libc/musl/src/string/memcmp.c', + 'system/lib/libc/musl/src/string/memmem.c', + 'system/lib/libc/musl/src/string/mempcpy.c', + 'system/lib/libc/musl/src/string/memrchr.c', + 'system/lib/libc/musl/src/string/rindex.c', + 'system/lib/libc/musl/src/string/stpcpy.c', 'system/lib/libc/musl/src/string/strcasecmp.c', + 'system/lib/libc/musl/src/string/strcasestr.c', + 'system/lib/libc/musl/src/string/strchr.c', + 'system/lib/libc/musl/src/string/strchrnul.c', 'system/lib/libc/musl/src/string/strcmp.c', + 'system/lib/libc/musl/src/string/strcspn.c', + 'system/lib/libc/musl/src/string/strdup.c', + 'system/lib/libc/musl/src/string/strlcat.c', + 'system/lib/libc/musl/src/string/strlcpy.c', 'system/lib/libc/musl/src/string/strncasecmp.c', + 'system/lib/libc/musl/src/string/strncat.c', 'system/lib/libc/musl/src/string/strncmp.c', - 'system/lib/libc/musl/src/string/wmemset.c', + 'system/lib/libc/musl/src/string/strndup.c', + 'system/lib/libc/musl/src/string/strnlen.c', + 'system/lib/libc/musl/src/string/strpbrk.c', + 'system/lib/libc/musl/src/string/strrchr.c', + 'system/lib/libc/musl/src/string/strsep.c', + 'system/lib/libc/musl/src/string/strspn.c', + 'system/lib/libc/musl/src/string/strstr.c', + 'system/lib/libc/musl/src/string/strtok.c', + 'system/lib/libc/musl/src/string/strtok_r.c', + 'system/lib/libc/musl/src/string/strverscmp.c', + 'system/lib/libc/musl/src/string/wcpcpy.c', + 'system/lib/libc/musl/src/string/wcpncpy.c', + 'system/lib/libc/musl/src/string/wcscasecmp.c', + 'system/lib/libc/musl/src/string/wcscasecmp_l.c', + 'system/lib/libc/musl/src/string/wcscat.c', + 'system/lib/libc/musl/src/string/wcschr.c', + 'system/lib/libc/musl/src/string/wcscmp.c', + 'system/lib/libc/musl/src/string/wcscpy.c', + 'system/lib/libc/musl/src/string/wcscspn.c', + 'system/lib/libc/musl/src/string/wcsdup.c', + 'system/lib/libc/musl/src/string/wcslen.c', + 'system/lib/libc/musl/src/string/wcsncasecmp.c', + 'system/lib/libc/musl/src/string/wcsncasecmp_l.c', + 'system/lib/libc/musl/src/string/wcsncat.c', + 'system/lib/libc/musl/src/string/wcsncmp.c', + 'system/lib/libc/musl/src/string/wcsncpy.c', + 'system/lib/libc/musl/src/string/wcsnlen.c', + 'system/lib/libc/musl/src/string/wcspbrk.c', + 'system/lib/libc/musl/src/string/wcsrchr.c', + 'system/lib/libc/musl/src/string/wcsspn.c', + 'system/lib/libc/musl/src/string/wcsstr.c', + 'system/lib/libc/musl/src/string/wcstok.c', + 'system/lib/libc/musl/src/string/wcswcs.c', + 'system/lib/libc/musl/src/string/wmemchr.c', + 'system/lib/libc/musl/src/string/wmemcmp.c', 'system/lib/libc/musl/src/string/wmemcpy.c', + 'system/lib/libc/musl/src/string/wmemmove.c', + 'system/lib/libc/musl/src/string/wmemset.c', + + 'system/lib/libc/musl/src/math/__cos.c', + 'system/lib/libc/musl/src/math/__cosdf.c', + 'system/lib/libc/musl/src/math/__sin.c', + 'system/lib/libc/musl/src/math/__sindf.c', + 'system/lib/libc/musl/src/math/frexp.c', + 'system/lib/libc/musl/src/math/frexpf.c', + 'system/lib/libc/musl/src/math/frexpl.c', + 'system/lib/libc/musl/src/math/ilogb.c', + 'system/lib/libc/musl/src/math/ilogbf.c', + 'system/lib/libc/musl/src/math/ilogbl.c', + 'system/lib/libc/musl/src/math/ldexp.c', + 'system/lib/libc/musl/src/math/ldexpf.c', + 'system/lib/libc/musl/src/math/ldexpl.c', + 'system/lib/libc/musl/src/math/lgamma.c', + 'system/lib/libc/musl/src/math/lgamma_r.c', + 'system/lib/libc/musl/src/math/lgammaf.c', + 'system/lib/libc/musl/src/math/lgammaf_r.c', + 'system/lib/libc/musl/src/math/lgammal.c', + 'system/lib/libc/musl/src/math/logb.c', + 'system/lib/libc/musl/src/math/logbf.c', + 'system/lib/libc/musl/src/math/logbl.c', + 'system/lib/libc/musl/src/math/scalbn.c', + 'system/lib/libc/musl/src/math/scalbnf.c', + 'system/lib/libc/musl/src/math/scalbnl.c', + 'system/lib/libc/musl/src/math/signgam.c', + 'system/lib/libc/musl/src/math/tgamma.c', + 'system/lib/libc/musl/src/math/tgammaf.c', + 'system/lib/libc/musl/src/math/tgammal.c', ] LIBCXX_SOURCES = [os.path.join('system/lib/libcxx', x) for x in [ diff --git a/src/compiler.js b/src/compiler.js index 17a8e83c12eb7..a86af011f0f97 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -319,7 +319,9 @@ try { } } } catch(err) { - printErr('aborting from js compiler due to exception: ' + err + ' | ' + err.stack); + printErr('Internal compiler error in src/compiler.js! Please raise a bug report at https://github.com/kripken/emscripten/issues/ with a log of the build and the input files used to run. Exception message: ' + err + ' | ' + err.stack); + if (ENVIRONMENT_IS_NODE) process.exit(1); + else throw err; } //var M = keys(tokenCacheMisses).map(function(m) { return [m, misses[m]] }).sort(function(a, b) { return a[1] - b[1] }); diff --git a/src/deps_info.json b/src/deps_info.json index e098306475d0c..a2b24698ff367 100644 --- a/src/deps_info.json +++ b/src/deps_info.json @@ -1,4 +1,31 @@ { + "freopen": ["free"], + "munmap": ["free"], + "getenv": ["malloc", "free"], + "dlerror": ["malloc", "free"], + "readdir": ["malloc"], + "ttyname": ["malloc"], + "calloc": ["malloc"], + "realloc": ["malloc", "free"], + "getlogin": ["malloc"], + "tmpnam": ["malloc"], + "mmap": ["malloc"], + "realpath": ["malloc"], + "strerror": ["malloc"], + "__ctype_b_loc": ["malloc"], + "__ctype_tolower_loc": ["malloc"], + "__ctype_toupper_loc": ["malloc"], + "newlocale": ["malloc"], + "freelocale": ["free"], + "nl_langinfo": ["malloc"], + "inet_ntoa": ["malloc"], + "gethostbyname": ["malloc"], + "gethostbyname_r": ["free"], + "getaddrinfo": ["malloc"], + "freeaddrinfo": ["free"], + "gai_strerror": ["malloc"], + "setprotoent": ["malloc"], + "emscripten_run_script_string": ["malloc", "free"], "uuid_compare": ["memcmp"], "SDL_Init": ["malloc", "free"], "SDL_GL_GetProcAddress": ["emscripten_GetProcAddress"], diff --git a/src/emrun_postjs.js b/src/emrun_postjs.js index eec203ece1497..9d84e761cdece 100644 --- a/src/emrun_postjs.js +++ b/src/emrun_postjs.js @@ -7,10 +7,10 @@ function emrun_register_handlers() { // If the address contains localhost, or we are running the page from port 6931, we can assume we're running the test runner and should post stdout logs. if (document.URL.search("localhost") != -1 || document.URL.search(":6931/") != -1) { var emrun_http_sequence_number = 1; - var prevExit = Module['exit']; var prevPrint = Module['print']; var prevErr = Module['printErr']; - Module['exit'] = function emrun_exit(returncode) { post('^exit^'+returncode); prevExit(returncode); } + function emrun_exit() { post('^exit^'+EXITSTATUS); }; + Module['addOnExit'](emrun_exit); Module['print'] = function emrun_print(text) { post('^out^'+(emrun_http_sequence_number++)+'^'+text); prevPrint(text); } Module['printErr'] = function emrun_printErr(text) { post('^err^'+(emrun_http_sequence_number++)+'^'+text); prevErr(text); } } diff --git a/src/library.js b/src/library.js index 1efc936c44e95..b90ee267fcff0 100644 --- a/src/library.js +++ b/src/library.js @@ -131,7 +131,7 @@ LibraryManager.library = { stream.position++; return 0; }, - readdir__deps: ['readdir_r', '__setErrNo', '$ERRNO_CODES', 'malloc'], + readdir__deps: ['readdir_r', '__setErrNo', '$ERRNO_CODES'], readdir: function(dirp) { // struct dirent *readdir(DIR *dirp); // http://pubs.opengroup.org/onlinepubs/007908799/xsh/readdir_r.html @@ -327,6 +327,7 @@ LibraryManager.library = { path = Pointer_stringify(path); // remove a trailing slash, if one - /a/b/ has basename of '', but // we want to create b in the context of this function + path = PATH.normalize(path); if (path[path.length-1] === '/') path = path.substr(0, path.length-1); try { FS.mkdir(path, mode, 0); @@ -1033,7 +1034,7 @@ LibraryManager.library = { return -1; } }, - ttyname__deps: ['ttyname_r', 'malloc'], + ttyname__deps: ['ttyname_r'], ttyname: function(fildes) { // char *ttyname(int fildes); // http://pubs.opengroup.org/onlinepubs/000095399/functions/ttyname.html @@ -1299,7 +1300,7 @@ LibraryManager.library = { return -1; } }, - getlogin__deps: ['getlogin_r', 'malloc'], + getlogin__deps: ['getlogin_r'], getlogin: function() { // char *getlogin(void); // http://pubs.opengroup.org/onlinepubs/000095399/functions/getlogin.html @@ -2717,7 +2718,7 @@ LibraryManager.library = { if (buf) _setvbuf(stream, buf, 0, 8192); // _IOFBF, BUFSIZ. else _setvbuf(stream, buf, 2, 8192); // _IONBF, BUFSIZ. }, - tmpnam__deps: ['$FS', 'malloc'], + tmpnam__deps: ['$FS'], tmpnam: function(s, dir, prefix) { // char *tmpnam(char *s); // http://pubs.opengroup.org/onlinepubs/000095399/functions/tmpnam.html @@ -2867,7 +2868,7 @@ LibraryManager.library = { // sys/mman.h // ========================================================================== - mmap__deps: ['$FS', 'malloc', 'memset'], + mmap__deps: ['$FS', 'memset'], mmap: function(start, num, prot, flags, fd, offset) { /* FIXME: Since mmap is normally implemented at the kernel level, * this implementation simply uses malloc underneath the call to @@ -2957,7 +2958,6 @@ LibraryManager.library = { #endif }, - calloc__deps: ['malloc'], calloc: function(n, s) { var ret = _malloc(n*s); _memset(ret, 0, n*s); @@ -2997,7 +2997,7 @@ LibraryManager.library = { Module['abort'](); }, - realloc__deps: ['malloc', 'memcpy', 'free'], + realloc__deps: ['memcpy'], realloc: function(ptr, size) { // Very simple, inefficient implementation - if you use a real malloc, best to use // a real realloc with it @@ -3572,7 +3572,7 @@ LibraryManager.library = { return ___setErrNo(ERRNO_CODES.EINVAL); } }, - strerror__deps: ['strerror_r', 'malloc'], + strerror__deps: ['strerror_r'], strerror: function(errnum) { if (!_strerror.buffer) _strerror.buffer = _malloc(256); _strerror_r(errnum, _strerror.buffer, 256); @@ -3584,7 +3584,6 @@ LibraryManager.library = { // ========================================================================== // Lookup tables for glibc ctype implementation. - __ctype_b_loc__deps: ['malloc'], __ctype_b_loc: function() { // http://refspecs.freestandards.org/LSB_3.0.0/LSB-Core-generic/LSB-Core-generic/baselib---ctype-b-loc.html var me = ___ctype_b_loc; @@ -3610,7 +3609,6 @@ LibraryManager.library = { } return me.ret; }, - __ctype_tolower_loc__deps: ['malloc'], __ctype_tolower_loc: function() { // http://refspecs.freestandards.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/libutil---ctype-tolower-loc.html var me = ___ctype_tolower_loc; @@ -3639,7 +3637,6 @@ LibraryManager.library = { } return me.ret; }, - __ctype_toupper_loc__deps: ['malloc'], __ctype_toupper_loc: function() { // http://refspecs.freestandards.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/libutil---ctype-toupper-loc.html var me = ___ctype_toupper_loc; @@ -4998,7 +4995,7 @@ LibraryManager.library = { }, timelocal: 'mktime', - gmtime__deps: ['malloc', '__tm_current', 'gmtime_r'], + gmtime__deps: ['__tm_current', 'gmtime_r'], gmtime: function(time) { return _gmtime_r(time, ___tm_current); }, @@ -5038,7 +5035,7 @@ LibraryManager.library = { return ret; }, - localtime__deps: ['malloc', '__tm_current', 'localtime_r'], + localtime__deps: ['__tm_current', 'localtime_r'], localtime: function(time) { return _localtime_r(time, ___tm_current); }, @@ -5068,7 +5065,7 @@ LibraryManager.library = { return tmPtr; }, - asctime__deps: ['malloc', '__tm_formatted', 'asctime_r'], + asctime__deps: ['__tm_formatted', 'asctime_r'], asctime: function(tmPtr) { return _asctime_r(tmPtr, ___tm_formatted); }, @@ -5999,7 +5996,6 @@ LibraryManager.library = { // locale.h // ========================================================================== - newlocale__deps: ['malloc'], newlocale: function(mask, locale, base) { return _malloc({{{ QUANTUM_SIZE}}}); }, @@ -6046,7 +6042,6 @@ LibraryManager.library = { // langinfo.h // ========================================================================== - nl_langinfo__deps: ['malloc'], nl_langinfo: function(item) { // char *nl_langinfo(nl_item item); // http://pubs.opengroup.org/onlinepubs/000095399/functions/nl_langinfo.html @@ -6673,7 +6668,7 @@ LibraryManager.library = { } return addr; }, - inet_ntoa__deps: ['_inet_ntop4_raw', 'malloc'], + inet_ntoa__deps: ['_inet_ntop4_raw'], inet_ntoa: function(in_addr) { if (!_inet_ntoa.buffer) { _inet_ntoa.buffer = _malloc(1024); @@ -7035,7 +7030,7 @@ LibraryManager.library = { return _gethostbyname(hostp); }, - gethostbyname__deps: ['$DNS', '_inet_pton4_raw', 'malloc'], + gethostbyname__deps: ['$DNS', '_inet_pton4_raw'], gethostbyname: function(name) { name = Pointer_stringify(name); @@ -7068,7 +7063,7 @@ LibraryManager.library = { return 0; }, - getaddrinfo__deps: ['$Sockets', '$DNS', '_inet_pton4_raw', '_inet_ntop4_raw', '_inet_pton6_raw', '_inet_ntop6_raw', '_write_sockaddr', 'htonl', 'malloc'], + getaddrinfo__deps: ['$Sockets', '$DNS', '_inet_pton4_raw', '_inet_ntop4_raw', '_inet_pton6_raw', '_inet_ntop6_raw', '_write_sockaddr', 'htonl'], getaddrinfo: function(node, service, hint, out) { // Note getaddrinfo currently only returns a single addrinfo with ai_next defaulting to NULL. When NULL // hints are specified or ai_family set to AF_UNSPEC or ai_socktype or ai_protocol set to 0 then we @@ -7285,7 +7280,7 @@ LibraryManager.library = { // are actually negative numbers and you can't have expressions as keys in JavaScript literals. $GAI_ERRNO_MESSAGES: {}, - gai_strerror__deps: ['$GAI_ERRNO_MESSAGES', 'malloc'], + gai_strerror__deps: ['$GAI_ERRNO_MESSAGES'], gai_strerror: function(val) { var buflen = 256; @@ -7327,7 +7322,7 @@ LibraryManager.library = { list: [], map: {} }, - setprotoent__deps: ['$Protocols', 'malloc'], + setprotoent__deps: ['$Protocols'], setprotoent: function(stayopen) { // void setprotoent(int stayopen); @@ -8241,6 +8236,40 @@ LibraryManager.library = { return 0; }, + getsockopt__deps: ['$SOCKFS', '__setErrNo', '$ERRNO_CODES'], + getsockopt: function(fd, level, optname, optval, optlen) { + // int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen); + // http://pubs.opengroup.org/onlinepubs/000095399/functions/getsockopt.html + // Minimal getsockopt aimed at resolving https://github.com/kripken/emscripten/issues/2211 + // so only supports SOL_SOCKET with SO_ERROR. + var sock = SOCKFS.getSocket(fd); + if (!sock) { + ___setErrNo(ERRNO_CODES.EBADF); + return -1; + } + + if (level === {{{ cDefine('SOL_SOCKET') }}}) { + if (optname === {{{ cDefine('SO_ERROR') }}}) { + {{{ makeSetValue('optval', 0, 'sock.error', 'i32') }}}; + {{{ makeSetValue('optlen', 0, 4, 'i32') }}}; + sock.error = null; // Clear the error (The SO_ERROR option obtains and then clears this field). + return 0; + } else { + ___setErrNo(ERRNO_CODES.ENOPROTOOPT); // The option is unknown at the level indicated. +#if ASSERTIONS + Runtime.warnOnce('getsockopt() returning an error as we currently only support optname SO_ERROR'); +#endif + return -1; + } + } else { + ___setErrNo(ERRNO_CODES.ENOPROTOOPT); //The option is unknown at the level indicated. +#if ASSERTIONS + Runtime.warnOnce('getsockopt() returning an error as we only support level SOL_SOCKET'); +#endif + return -1; + } + }, + mkport: function() { throw 'TODO' }, // ========================================================================== diff --git a/src/library_egl.js b/src/library_egl.js index 46ec939ea94c2..559236d13b448 100644 --- a/src/library_egl.js +++ b/src/library_egl.js @@ -268,13 +268,17 @@ var LibraryEGL = { // So user must pass EGL_CONTEXT_CLIENT_VERSION == 2 to initialize EGL. var glesContextVersion = 1; for(;;) { - var param = {{{ makeGetValue('contextAttribs', '0', 'i32') }}}; - if (!param) break; - var value = {{{ makeGetValue('contextAttribs', '4', 'i32') }}}; - if (param == 0x3098 /*EGL_CONTEXT_CLIENT_VERSION*/) { - glesContextVersion = value; - } - contextAttribs += 8; + var param = {{{ makeGetValue('contextAttribs', '0', 'i32') }}}; + if (param == 0x3098 /*EGL_CONTEXT_CLIENT_VERSION*/) { + glesContextVersion = {{{ makeGetValue('contextAttribs', '4', 'i32') }}}; + } else if (param == 0x3038 /*EGL_NONE*/) { + break; + } else { + /* EGL1.4 specifies only EGL_CONTEXT_CLIENT_VERSION as supported attribute */ + EGL.setErrorCode(0x3004 /*EGL_BAD_ATTRIBUTE*/); + return 0; + } + contextAttribs += 8; } if (glesContextVersion != 2) { #if GL_ASSERTIONS diff --git a/src/library_fs.js b/src/library_fs.js index 7932385e44ecb..5fc2c20325c63 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -48,6 +48,8 @@ mergeInto(LibraryManager.library, { path = PATH.resolve(FS.cwd(), path); opts = opts || {}; + if (!path) return { path: '', node: null }; + var defaults = { follow_mount: true, recurse_count: 0 @@ -607,6 +609,9 @@ mergeInto(LibraryManager.library, { var lookup = FS.lookupPath(path, { parent: true }); var parent = lookup.node; var name = PATH.basename(path); + if (!name || name === '.' || name === '..') { + throw new FS.ErrnoError(ERRNO_CODES.EINVAL); + } var err = FS.mayCreate(parent, name); if (err) { throw new FS.ErrnoError(err); @@ -638,8 +643,14 @@ mergeInto(LibraryManager.library, { return FS.mknod(path, mode, dev); }, symlink: function(oldpath, newpath) { + if (!PATH.resolve(oldpath)) { + throw new FS.ErrnoError(ERRNO_CODES.ENOENT); + } var lookup = FS.lookupPath(newpath, { parent: true }); var parent = lookup.node; + if (!parent) { + throw new FS.ErrnoError(ERRNO_CODES.ENOENT); + } var newname = PATH.basename(newpath); var err = FS.mayCreate(parent, newname); if (err) { @@ -825,6 +836,9 @@ mergeInto(LibraryManager.library, { stat: function(path, dontFollow) { var lookup = FS.lookupPath(path, { follow: !dontFollow }); var node = lookup.node; + if (!node) { + throw new FS.ErrnoError(ERRNO_CODES.ENOENT); + } if (!node.node_ops.getattr) { throw new FS.ErrnoError(ERRNO_CODES.EPERM); } diff --git a/src/library_gl.js b/src/library_gl.js index c20eb55dc0878..ffcbef629f66f 100644 --- a/src/library_gl.js +++ b/src/library_gl.js @@ -712,22 +712,22 @@ var LibraryGL = { "EXT_shader_texture_lod" ]; function shouldEnableAutomatically(extension) { - for(var i in automaticallyEnabledExtensions) { - var include = automaticallyEnabledExtensions[i]; + var ret = false; + automaticallyEnabledExtensions.forEach(function(include) { if (ext.indexOf(include) != -1) { - return true; + ret = true; } - } - return false; + }); + return ret; } - var extensions = GLctx.getSupportedExtensions(); - for(var e in extensions) { - var ext = extensions[e].replace('MOZ_', '').replace('WEBKIT_', ''); + + GLctx.getSupportedExtensions().forEach(function(ext) { + ext = ext.replace('MOZ_', '').replace('WEBKIT_', ''); if (automaticallyEnabledExtensions.indexOf(ext) != -1) { GLctx.getExtension(ext); // Calling .getExtension enables that extension permanently, no need to store the return value to be enabled. } - } + }); }, // In WebGL, uniforms in a shader program are accessed through an opaque object type 'WebGLUniformLocation'. diff --git a/src/library_html5.js b/src/library_html5.js index d5d0cd6637a9c..238575de574bb 100644 --- a/src/library_html5.js +++ b/src/library_html5.js @@ -198,7 +198,6 @@ var LibraryJSEvents = { }, fillMouseEventData: function(eventStruct, e) { - var rect = Module['canvas'].getBoundingClientRect(); {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.timestamp, 'JSEvents.tick()', 'double') }}}; {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.screenX, 'e.screenX', 'i32') }}}; {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.screenY, 'e.screenY', 'i32') }}}; @@ -212,8 +211,15 @@ var LibraryJSEvents = { {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.buttons, 'e.buttons', 'i16') }}}; {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.movementX, 'e["movementX"] || e["mozMovementX"] || e["webkitMovementX"] || (e.screenX-JSEvents.previousScreenX)', 'i32') }}}; {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.movementY, 'e["movementY"] || e["mozMovementY"] || e["webkitMovementY"] || (e.screenY-JSEvents.previousScreenY)', 'i32') }}}; - {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasX, 'e.clientX - rect.left', 'i32') }}}; - {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasY, 'e.clientY - rect.top', 'i32') }}}; + + if (Module['canvas']) { + var rect = Module['canvas'].getBoundingClientRect(); + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasX, 'e.clientX - rect.left', 'i32') }}}; + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasY, 'e.clientY - rect.top', 'i32') }}}; + } else { // Canvas is not initialized, return 0. + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasX, '0', 'i32') }}}; + {{{ makeSetValue('eventStruct', C_STRUCTS.EmscriptenMouseEvent.canvasY, '0', 'i32') }}}; + } JSEvents.previousScreenX = e.screenX; JSEvents.previousScreenY = e.screenY; }, diff --git a/src/library_path.js b/src/library_path.js index f00a75860fba3..d9348bec7bccc 100644 --- a/src/library_path.js +++ b/src/library_path.js @@ -85,7 +85,7 @@ mergeInto(LibraryManager.library, { if (typeof path !== 'string') { throw new TypeError('Arguments to path.resolve must be strings'); } else if (!path) { - continue; + return ''; // an invalid portion invalidates the whole thing } resolvedPath = path + '/' + resolvedPath; resolvedAbsolute = path.charAt(0) === '/'; diff --git a/src/library_sdl.js b/src/library_sdl.js index b55da6f7dcb02..c00c0d6c7925b 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -802,8 +802,9 @@ var LibrarySDL = { // returns false if the event was determined to be irrelevant makeCEvent: function(event, ptr) { if (typeof event === 'number') { - // This is a pointer to a native C event that was SDL_PushEvent'ed - _memcpy(ptr, event, {{{ C_STRUCTS.SDL_KeyboardEvent.__size__ }}}); // XXX + // This is a pointer to a copy of a native C event that was SDL_PushEvent'ed + _memcpy(ptr, event, {{{ C_STRUCTS.SDL_KeyboardEvent.__size__ }}}); + _free(event); // the copy is no longer needed return; } @@ -1785,7 +1786,9 @@ var LibrarySDL = { }, SDL_PushEvent: function(ptr) { - SDL.events.push(ptr); // XXX Should we copy it? Not clear from API + var copy = _malloc({{{ C_STRUCTS.SDL_KeyboardEvent.__size__ }}}); + _memcpy(copy, ptr, {{{ C_STRUCTS.SDL_KeyboardEvent.__size__ }}}); + SDL.events.push(copy); return 0; }, diff --git a/src/library_sockfs.js b/src/library_sockfs.js index 236414649b2d1..6bd68b659156e 100644 --- a/src/library_sockfs.js +++ b/src/library_sockfs.js @@ -3,6 +3,38 @@ mergeInto(LibraryManager.library, { $SOCKFS__deps: ['$FS', 'mkport'], $SOCKFS: { mount: function(mount) { + // If Module['websocket'] has already been defined (e.g. for configuring + // the subprotocol/url) use that, if not initialise it to a new object. + Module['websocket'] = (Module['websocket'] && + ('object' === typeof Module['websocket'])) ? Module['websocket'] : {}; + + // Add the Event registration mechanism to the exported websocket configuration + // object so we can register network callbacks from native JavaScript too. + // For more documentation see system/include/emscripten/emscripten.h + Module['websocket']._callbacks = {}; + Module['websocket']['on'] = function(event, callback) { + if ('function' === typeof callback) { + this._callbacks[event] = callback; + } + return this; + }; + + Module['websocket'].emit = function(event, param) { + if ('function' === typeof this._callbacks[event]) { + this._callbacks[event].call(this, param); + } + }; + + // If debug is enabled register simple default logging callbacks for each Event. +#if SOCKET_DEBUG + Module['websocket']['on']('error', function(error) {Module.printErr('Socket error ' + error);}); + Module['websocket']['on']('open', function(fd) {Module.print('Socket open fd = ' + fd);}); + Module['websocket']['on']('listen', function(fd) {Module.print('Socket listen fd = ' + fd);}); + Module['websocket']['on']('connection', function(fd) {Module.print('Socket connection fd = ' + fd);}); + Module['websocket']['on']('message', function(fd) {Module.print('Socket message fd = ' + fd);}); + Module['websocket']['on']('close', function(fd) {Module.print('Socket close fd = ' + fd);}); +#endif + return FS.createNode(null, '/', {{{ cDefine('S_IFDIR') }}} | 511 /* 0777 */, 0); }, createSocket: function(family, type, protocol) { @@ -17,6 +49,7 @@ mergeInto(LibraryManager.library, { type: type, protocol: protocol, server: null, + error: null, // Used in getsockopt for SOL_SOCKET/SO_ERROR test peers: {}, pending: [], recv_queue: [], @@ -136,8 +169,8 @@ mergeInto(LibraryManager.library, { // runtimeConfig gets set to true if WebSocket runtime configuration is available. var runtimeConfig = (Module['websocket'] && ('object' === typeof Module['websocket'])); - // The default value is 'ws://' the replace is needed because the compiler replaces "//" comments with '#' - // comments without checking context, so we'd end up with ws:#, the replace swaps the "#" for "//" again. + // The default value is 'ws://' the replace is needed because the compiler replaces '//' comments with '#' + // comments without checking context, so we'd end up with ws:#, the replace swaps the '#' for '//' again. var url = '{{{ WEBSOCKET_URL }}}'.replace('#', '//'); if (runtimeConfig) { @@ -224,6 +257,9 @@ mergeInto(LibraryManager.library, { #if SOCKET_DEBUG Module.print('websocket handle open'); #endif + + Module['websocket'].emit('open', sock.stream.fd); + try { var queued = peer.dgram_send_queue.shift(); while (queued) { @@ -264,6 +300,7 @@ mergeInto(LibraryManager.library, { } sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data }); + Module['websocket'].emit('message', sock.stream.fd); }; if (ENVIRONMENT_IS_NODE) { @@ -274,14 +311,32 @@ mergeInto(LibraryManager.library, { } handleMessage((new Uint8Array(data)).buffer); // copy from node Buffer -> ArrayBuffer }); - peer.socket.on('error', function() { + peer.socket.on('close', function() { + Module['websocket'].emit('close', sock.stream.fd); + }); + peer.socket.on('error', function(error) { + // Although the ws library may pass errors that may be more descriptive than + // ECONNREFUSED they are not necessarily the expected error code e.g. + // ENOTFOUND on getaddrinfo seems to be node.js specific, so using ECONNREFUSED + // is still probably the most useful thing to do. + sock.error = ERRNO_CODES.ECONNREFUSED; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. + Module['websocket'].emit('error', [sock.stream.fd, sock.error, 'ECONNREFUSED: Connection refused']); // don't throw }); } else { peer.socket.onopen = handleOpen; + peer.socket.onclose = function() { + Module['websocket'].emit('close', sock.stream.fd); + }; peer.socket.onmessage = function peer_socket_onmessage(event) { handleMessage(event.data); }; + peer.socket.onerror = function(error) { + // The WebSocket spec only allows a 'simple event' to be thrown on error, + // so we only really know as much as ECONNREFUSED. + sock.error = ERRNO_CODES.ECONNREFUSED; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. + Module['websocket'].emit('error', [sock.stream.fd, sock.error, 'ECONNREFUSED: Connection refused']); + }; } }, @@ -380,7 +435,7 @@ mergeInto(LibraryManager.library, { }, connect: function(sock, addr, port) { if (sock.server) { - throw new FS.ErrnoError(ERRNO_CODS.EOPNOTSUPP); + throw new FS.ErrnoError(ERRNO_CODES.EOPNOTSUPP); } // TODO autobind @@ -425,6 +480,7 @@ mergeInto(LibraryManager.library, { port: sock.sport // TODO support backlog }); + Module['websocket'].emit('listen', sock.stream.fd); // Send Event with listen fd. sock.server.on('connection', function(ws) { #if SOCKET_DEBUG @@ -440,17 +496,28 @@ mergeInto(LibraryManager.library, { // push to queue for accept to pick up sock.pending.push(newsock); + Module['websocket'].emit('connection', newsock.stream.fd); } else { // create a peer on the listen socket so calling sendto // with the listen socket and an address will resolve // to the correct client SOCKFS.websocket_sock_ops.createPeer(sock, ws); + Module['websocket'].emit('connection', sock.stream.fd); } }); sock.server.on('closed', function() { + Module['websocket'].emit('close', sock.stream.fd); sock.server = null; }); - sock.server.on('error', function() { + sock.server.on('error', function(error) { + // Although the ws library may pass errors that may be more descriptive than + // ECONNREFUSED they are not necessarily the expected error code e.g. + // ENOTFOUND on getaddrinfo seems to be node.js specific, so using EHOSTUNREACH + // is still probably the most useful thing to do. This error shouldn't + // occur in a well written app as errors should get trapped in the compiled + // app's own getaddrinfo call. + sock.error = ERRNO_CODES.EHOSTUNREACH; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. + Module['websocket'].emit('error', [sock.stream.fd, sock.error, 'EHOSTUNREACH: Host is unreachable']); // don't throw }); }, @@ -604,5 +671,65 @@ mergeInto(LibraryManager.library, { return res; } } + }, + + /* + * Mechanism to register handlers for the various Socket Events from C code. + * The registration functions are mostly variations on a theme, so we use this + * generic handler. Most of the callback functions take a file descriptor as a + * parameter, which will get passed to them by the emitting call. The error + * callback also takes an int representing the errno and a char* representing the + * error message, which we extract from the data passed to _callback and convert + * to a char* string before calling the registered C callback. + * Passing a NULL callback function to a emscripten_set_socket_*_callback call + * will deregister the callback registered for that Event. + */ + __set_network_callback: function(event, userData, callback) { + function _callback(data) { + try { + if (event === 'error') { + var sp = Runtime.stackSave(); + var msg = allocate(intArrayFromString(data[2]), 'i8', ALLOC_STACK); + Runtime.dynCall('viiii', callback, [data[0], data[1], msg, userData]); + Runtime.stackRestore(sp); + } else { + Runtime.dynCall('vii', callback, [data, userData]); + } + } catch (e) { + if (e instanceof ExitStatus) { + return; + } else { + if (e && typeof e === 'object' && e.stack) Module.printErr('exception thrown: ' + [e, e.stack]); + throw e; + } + } + }; + + Module['noExitRuntime'] = true; + Module['websocket']['on'](event, callback ? _callback : null); + }, + emscripten_set_socket_error_callback__deps: ['__set_network_callback'], + emscripten_set_socket_error_callback: function(userData, callback) { + ___set_network_callback('error', userData, callback); + }, + emscripten_set_socket_open_callback__deps: ['__set_network_callback'], + emscripten_set_socket_open_callback: function(userData, callback) { + ___set_network_callback('open', userData, callback); + }, + emscripten_set_socket_listen_callback__deps: ['__set_network_callback'], + emscripten_set_socket_listen_callback: function(userData, callback) { + ___set_network_callback('listen', userData, callback); + }, + emscripten_set_socket_connection_callback__deps: ['__set_network_callback'], + emscripten_set_socket_connection_callback: function(userData, callback) { + ___set_network_callback('connection', userData, callback); + }, + emscripten_set_socket_message_callback__deps: ['__set_network_callback'], + emscripten_set_socket_message_callback: function(userData, callback) { + ___set_network_callback('message', userData, callback); + }, + emscripten_set_socket_close_callback__deps: ['__set_network_callback'], + emscripten_set_socket_close_callback: function(userData, callback) { + ___set_network_callback('close', userData, callback); } }); diff --git a/src/preamble.js b/src/preamble.js index 953b552cc9734..93f9292e62794 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -427,6 +427,7 @@ var cwrap, ccall; // alert(my_function(99, 12)); // cwrap = function cwrap(ident, returnType, argTypes) { + argTypes = argTypes || []; var cfunc = getCFunc(ident); // When the function takes numbers and returns a number, we can just return // the original function @@ -935,6 +936,7 @@ function stackTrace() { var stack = new Error().stack; return stack ? demangleAll(stack) : '(no stack trace available)'; // Stack trace is not available at least on IE10 and Safari 6. } +Module['stackTrace'] = stackTrace; // Memory management diff --git a/src/struct_info.json b/src/struct_info.json index 655b6bc99575c..94a64845cd5f3 100644 --- a/src/struct_info.json +++ b/src/struct_info.json @@ -441,7 +441,9 @@ "SOCK_STREAM", "AF_INET", "AF_UNSPEC", - "AF_INET6" + "AF_INET6", + "SOL_SOCKET", + "SO_ERROR" ], "structs": {} }, diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index bd96f35f9c05e..32bf546af7e25 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -534,9 +534,7 @@ namespace emscripten { template inline T* getContext(const T& t) { // not a leak because this is called once per binding - T* p = reinterpret_cast(malloc(sizeof(T))); - new(p) T(t); - return p; + return new T(t); } template diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h index b495c0f559e16..7533be8c0df86 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -43,6 +43,13 @@ typedef double __attribute__((aligned(4))) emscripten_align4_double; typedef double __attribute__((aligned(2))) emscripten_align2_double; typedef double __attribute__((aligned(1))) emscripten_align1_double; +/* + * Function pointer types + */ + +typedef void (*em_callback_func)(void); +typedef void (*em_arg_callback_func)(void*); +typedef void (*em_str_callback_func)(const char *); /* Functions */ @@ -125,7 +132,7 @@ extern void emscripten_async_run_script(const char *script, int millis); * for this is to load an asset module, that is, the output of the * file packager. */ -extern void emscripten_async_load_script(const char *script, void (*onload)(void), void (*onerror)(void)); +extern void emscripten_async_load_script(const char *script, em_callback_func onload, em_callback_func onerror); /* * Set a C function as the main event loop. The JS environment @@ -171,8 +178,8 @@ extern void emscripten_async_load_script(const char *script, void (*onload)(void * before the main loop will be called the first time. */ #if __EMSCRIPTEN__ -extern void emscripten_set_main_loop(void (*func)(void), int fps, int simulate_infinite_loop); -extern void emscripten_set_main_loop_arg(void (*func)(void*), void *arg, int fps, int simulate_infinite_loop); +extern void emscripten_set_main_loop(em_callback_func func, int fps, int simulate_infinite_loop); +extern void emscripten_set_main_loop_arg(em_arg_callback_func func, void *arg, int fps, int simulate_infinite_loop); extern void emscripten_pause_main_loop(void); extern void emscripten_resume_main_loop(void); extern void emscripten_cancel_main_loop(void); @@ -182,6 +189,66 @@ extern void emscripten_cancel_main_loop(void); #define emscripten_cancel_main_loop() exit(1); #endif +/* + * Registers callback functions for receiving socket events. + * These events are analogous to WebSocket events but are emitted + * *after* the internal emscripten socket processing has occurred + * so, for example, the message callback will be triggered after + * the data has been added to the recv_queue. This means that an + * application receiving this callback can simply read/recv the data + * using the file descriptor passed as a parameter to the callback. + * All of the callbacks are passed a file descriptor representing + * the fd that the notified activity took place on. The error + * callback also takes an int representing errno and a char* that + * represents the error message. + * + * Only a single callback function may be registered to handle any + * given Event, so calling a given registration function more than + * once will cause the first callback to be replaced by the second. + * Similarly passing a NULL callback function to any + * emscripten_set_socket_*_callback call will deregister the callback + * registered for that Event. + * + * The userData pointer allows arbitrary data specified during Event + * registration to be passed to the callback, this is particularly + * useful for passing "this" pointers around in Object Oriented code. + * + * In addition to being able to register network callbacks from C + * it is also possible for native JavaScript code to directly use the + * underlying mechanism used to implement the callback registration. + * For example, the following are the simple logging callbacks that + * are registered by default when SOCKET_DEBUG is enabled + * Module['websocket']['on']('error', function(error) {console.log('Socket error ' + error);}); + * Module['websocket']['on']('open', function(fd) {console.log('Socket open fd = ' + fd);}); + * Module['websocket']['on']('listen', function(fd) {console.log('Socket listen fd = ' + fd);}); + * Module['websocket']['on']('connection', function(fd) {console.log('Socket connection fd = ' + fd);}); + * Module['websocket']['on']('message', function(fd) {console.log('Socket message fd = ' + fd);}); + * Module['websocket']['on']('close', function(fd) {console.log('Socket close fd = ' + fd);}); + * + * Most of the JavaScript callback functions above get passed the + * file descriptor of the socket that triggered the callback, the + * on error callback however gets passed an *array* that contains + * the file descriptor, the error code and an error message. + * + * Note that the underlying JavaScript implementation doesn't pass + * userData, this is actually mostly of use to C/C++ code and the + * emscripten_set_socket_*_callback calls actually create a closure + * containing the userData and pass that as the callback to the + * underlying JavaScript Event registration mechanism. + */ +// Triggered by a WebSocket error. +extern void emscripten_set_socket_error_callback(void *userData, void (*func)(int fd, int err, const char* msg, void *userData)); +// Triggered when the WebSocket has actually opened. +extern void emscripten_set_socket_open_callback(void *userData, void (*func)(int fd, void *userData)); +// Triggered when listen has been called (synthetic event). +extern void emscripten_set_socket_listen_callback(void *userData, void (*func)(int fd, void *userData)); +// Triggered when the connection has actually been established. +extern void emscripten_set_socket_connection_callback(void *userData, void (*func)(int fd, void *userData)); +// Triggered when data is available to be read from the socket. +extern void emscripten_set_socket_message_callback(void *userData, void (*func)(int fd, void *userData)); +// Triggered when the WebSocket has actually closed. +extern void emscripten_set_socket_close_callback(void *userData, void (*func)(int fd, void *userData)); + /* * Add a function to a queue of events that will execute * before the main loop will continue. The event is pushed @@ -196,13 +263,13 @@ extern void emscripten_cancel_main_loop(void); * at specific time in the future. */ #if __EMSCRIPTEN__ -extern void _emscripten_push_main_loop_blocker(void (*func)(void *), void *arg, const char *name); -extern void _emscripten_push_uncounted_main_loop_blocker(void (*func)(void *), void *arg, const char *name); +extern void _emscripten_push_main_loop_blocker(em_arg_callback_func func, void *arg, const char *name); +extern void _emscripten_push_uncounted_main_loop_blocker(em_arg_callback_func func, void *arg, const char *name); #else -inline void _emscripten_push_main_loop_blocker(void (*func)(void *), void *arg, const char *name) { +inline void _emscripten_push_main_loop_blocker(em_arg_callback_func func, void *arg, const char *name) { func(arg); } -inline void _emscripten_push_uncounted_main_loop_blocker(void (*func)(void *), void *arg, const char *name) { +inline void _emscripten_push_uncounted_main_loop_blocker(em_arg_callback_func func, void *arg, const char *name) { func(arg); } #endif @@ -233,9 +300,9 @@ inline void emscripten_set_main_loop_expected_blockers(int num) {} * mechanism is used. */ #if __EMSCRIPTEN__ -extern void emscripten_async_call(void (*func)(void *), void *arg, int millis); +extern void emscripten_async_call(em_arg_callback_func func, void *arg, int millis); #else -inline void emscripten_async_call(void (*func)(void *), void *arg, int millis) { +inline void emscripten_async_call(em_arg_callback_func func, void *arg, int millis) { if (millis) SDL_Delay(millis); func(arg); } @@ -312,7 +379,7 @@ float emscripten_random(void); * If any error occurred 'onerror' will called. * The callbacks are called with the file as their argument. */ -void emscripten_async_wget(const char* url, const char* file, void (*onload)(const char*), void (*onerror)(const char*)); +void emscripten_async_wget(const char* url, const char* file, em_str_callback_func onload, em_str_callback_func onerror); /* * Data version of emscripten_async_wget. Instead of writing @@ -336,7 +403,9 @@ void emscripten_async_wget(const char* url, const char* file, void (*onload)(con * @arg that was provided to this function. * */ -void emscripten_async_wget_data(const char* url, void *arg, void (*onload)(void*, void*, int), void (*onerror)(void*)); +typedef void (*em_async_wget_onload_func)(void*, void*, int); + +void emscripten_async_wget_data(const char* url, void *arg, em_async_wget_onload_func onload, em_arg_callback_func onerror); /* * More feature-complete version of emscripten_async_wget. Note: @@ -353,7 +422,10 @@ void emscripten_async_wget_data(const char* url, void *arg, void (*onload)(void* * and file if is a success, the progress value during progress * and http status code if is an error. */ -void emscripten_async_wget2(const char* url, const char* file, const char* requesttype, const char* param, void *arg, void (*onload)(void*, const char*), void (*onerror)(void*, int), void (*onprogress)(void*, int)); +typedef void (*em_async_wget2_onload_func)(void*, const char*); +typedef void (*em_async_wget2_onstatus_func)(void*, int); + +void emscripten_async_wget2(const char* url, const char* file, const char* requesttype, const char* param, void *arg, em_async_wget2_onload_func onload, em_async_wget2_onstatus_func onerror, em_async_wget2_onstatus_func onprogress); /* * More feature-complete version of emscripten_async_wget_data. Note: @@ -375,7 +447,11 @@ void emscripten_async_wget2(const char* url, const char* file, const char* requ * If any error occurred 'onerror' will called with the HTTP status code and a string with the status description. */ -void emscripten_async_wget2_data(const char* url, const char* requesttype, const char* param, void *arg, int free, void (*onload)(void*, void*, unsigned), void (*onerror)(void*, int, const char*), void (*onprogress)(void*, int, int)); +typedef void (*em_async_wget2_data_onload_func)(void*, void *, unsigned*); +typedef void (*em_async_wget2_data_onerror_func)(void*, int, const char*); +typedef void (*em_async_wget2_data_onprogress_func)(void*, int, int); + +void emscripten_async_wget2_data(const char* url, const char* requesttype, const char* param, void *arg, int free, em_async_wget2_data_onload_func onload, em_async_wget2_data_onerror_func onerror, em_async_wget2_data_onprogress_func onprogress); /* * Prepare a file in asynchronous way. This does just the @@ -387,7 +463,7 @@ void emscripten_async_wget2_data(const char* url, const char* requesttype, const * The callbacks are called with the file as their argument. * @return 0 if successful, -1 if the file does not exist */ -int emscripten_async_prepare(const char* file, void (*onload)(const char*), void (*onerror)(const char*)); +int emscripten_async_prepare(const char* file, em_str_callback_func onload, em_str_callback_func onerror); /* * Data version of emscripten_async_prepare, which receives @@ -403,7 +479,9 @@ int emscripten_async_prepare(const char* file, void (*onload)(const char*), void * the fake filename. * @suffix The file suffix, e.g. 'png' or 'jpg'. */ -void emscripten_async_prepare_data(char* data, int size, const char *suffix, void *arg, void (*onload)(void*, const char*), void (*onerror)(void*)); +typedef void (*em_async_prepare_data_onload_func)(void*, const char*); + +void emscripten_async_prepare_data(char* data, int size, const char *suffix, void *arg, em_async_prepare_data_onload_func onload, em_arg_callback_func onerror); /* * Worker API. Basically a wrapper around web workers, lets @@ -452,7 +530,9 @@ void emscripten_destroy_worker(worker_handle worker); * @callback the callback with the response (can be null) * @arg an argument to be passed to the callback */ -void emscripten_call_worker(worker_handle worker, const char *funcname, char *data, int size, void (*callback)(char *, int, void*), void *arg); +typedef void (*em_worker_callback_func)(char*, int, void*); + +void emscripten_call_worker(worker_handle worker, const char *funcname, char *data, int size, em_worker_callback_func callback, void *arg); /* * Sends a response when in a worker call. Both functions post a message @@ -535,52 +615,7 @@ char *emscripten_get_preloaded_image_data(const char *path, int *w, int *h); */ char *emscripten_get_preloaded_image_data_from_FILE(FILE *file, int *w, int *h); - -/* ===================================== */ -/* Internal APIs. Be careful with these. */ -/* ===================================== */ - -/* - * Profiling tools. - * INIT must be called first, with the maximum identifier that - * will be used. BEGIN will add some code that marks - * the beginning of a section of code whose run time you - * want to measure. END will finish such a section. Note: If you - * call begin but not end, you will get invalid data! - * The profiling data will be written out if you call Profile.dump(). - */ -extern void EMSCRIPTEN_PROFILE_INIT(int max); -extern void EMSCRIPTEN_PROFILE_BEGIN(int id); -extern void EMSCRIPTEN_PROFILE_END(int id); - -/* - * jcache-friendly printf. printf in general will receive a string - * literal, which becomes a global constant, which invalidates all - * jcache entries. emscripten_jcache_printf is parsed before - * clang into something without any string literals, so you can - * add such printouts to your code and only the (chunk containing - * the) function you modify will be invalided and recompiled. - * - * Note in particular that you need to already have a call to this - * function in your code *before* you add one and do an incremental - * build, so that adding an external reference does not invalidate - * everything. - * - * This function assumes the first argument is a string literal - * (otherwise you don't need it), and the other arguments, if any, - * are neither strings nor complex expressions (but just simple - * variables). (You can create a variable to store a complex - * expression on the previous line, if necessary.) - */ -#ifdef __cplusplus -void emscripten_jcache_printf(const char *format, ...); -void emscripten_jcache_printf_(...); /* internal use */ -#endif - -/* Helper API for EM_ASM - do not call this yourself */ -void emscripten_asm_const(const char *code); -int emscripten_asm_const_int(const char *code, ...); -double emscripten_asm_const_double(const char *code, ...); +/* Logging utilities */ /* If specified, logs directly to the browser console/inspector * window. If not specified, logs via the application Module. */ @@ -646,6 +681,40 @@ void emscripten_log(int flags, ...); */ int emscripten_get_callstack(int flags, char *out, int maxbytes); + +/* ===================================== */ +/* Internal APIs. Be careful with these. */ +/* ===================================== */ + +/* + * jcache-friendly printf. printf in general will receive a string + * literal, which becomes a global constant, which invalidates all + * jcache entries. emscripten_jcache_printf is parsed before + * clang into something without any string literals, so you can + * add such printouts to your code and only the (chunk containing + * the) function you modify will be invalided and recompiled. + * + * Note in particular that you need to already have a call to this + * function in your code *before* you add one and do an incremental + * build, so that adding an external reference does not invalidate + * everything. + * + * This function assumes the first argument is a string literal + * (otherwise you don't need it), and the other arguments, if any, + * are neither strings nor complex expressions (but just simple + * variables). (You can create a variable to store a complex + * expression on the previous line, if necessary.) + */ +#ifdef __cplusplus +void emscripten_jcache_printf(const char *format, ...); +void emscripten_jcache_printf_(...); /* internal use */ +#endif + +/* Helper API for EM_ASM - do not call this yourself */ +void emscripten_asm_const(const char *code); +int emscripten_asm_const_int(const char *code, ...); +double emscripten_asm_const_double(const char *code, ...); + #ifdef __cplusplus } #endif diff --git a/system/include/emscripten/html5.h b/system/include/emscripten/html5.h index 7aa14060de3ea..55515a07684eb 100644 --- a/system/include/emscripten/html5.h +++ b/system/include/emscripten/html5.h @@ -12,7 +12,7 @@ extern "C" { * - Fullscreen Events for browser canvas fullscreen modes transitioning. See https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html * - Pointer Lock Events for relative-mode mouse motion control. See http://www.w3.org/TR/pointerlock/ * - Vibration API for mobile device haptic vibration feedback control. See http://dev.w3.org/2009/dap/vibration/ - * - Page Visibility Events for power management control. See http://www.w3c-test.org/webperf/specs/PageVisibility/ + * - Page Visibility Events for power management control. See http://www.w3.org/TR/page-visibility/ * - Touch Events. See http://www.w3.org/TR/touch-events/ * - Gamepad API. See http://www.w3.org/TR/gamepad/ * - Beforeunload event. See http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html#beforeunloadevent @@ -168,9 +168,9 @@ typedef struct EmscriptenKeyboardEvent { * See https://developer.mozilla.org/en/DOM/Event/UIEvent/KeyEvent * and http://www.javascriptkit.com/jsref/eventkeyboardmouse.shtml */ -extern EMSCRIPTEN_RESULT emscripten_set_keypress_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_keydown_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_keyup_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_keypress_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_keydown_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_keyup_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenKeyboardEvent *keyEvent, void *userData)); /* * The event structure passed in mouse events click, mousedown, mouseup, dblclick and mousemove. @@ -198,6 +198,7 @@ typedef struct EmscriptenMouseEvent { long movementX; long movementY; // Emscripten-specific extension: These fields give the mouse coordinates mapped to the Emscripten canvas client area. + // If the Emscripten canvas does not exist (Module.canvas element is null), then these fields will contain a value (0, 0). long canvasX; long canvasY; // Pad this struct to multiple of 8 bytes to make WheelEvent unambiguously align to 8 bytes. @@ -208,11 +209,11 @@ typedef struct EmscriptenMouseEvent { * Registers a callback function for receiving browser-generated mouse input events. * See https://developer.mozilla.org/en/DOM/MouseEvent */ -extern EMSCRIPTEN_RESULT emscripten_set_click_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_mousedown_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_mouseup_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_dblclick_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_mousemove_callback(const char *target, void *userData, int useCapture, int (*func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_click_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_mousedown_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_mouseup_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_dblclick_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_mousemove_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenMouseEvent *mouseEvent, void *userData)); /* * Returns the most recently received mouse event state. Note that for this function call to succeed, emscripten_set_xx_callback must have first * been called with one of the mouse event types and a non-zero callback function pointer to enable the Mouse state capture. @@ -242,7 +243,7 @@ typedef struct EmscriptenWheelEvent { * Registers a callback function for receiving browser-generated mouse wheel events. * See http://www.w3.org/TR/DOM-Level-3-Events/#event-type-wheel */ -extern EMSCRIPTEN_RESULT emscripten_set_wheel_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_wheel_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenWheelEvent *wheelEvent, void *userData)); /* * The event structure passed in DOM element resize and scroll events. @@ -272,8 +273,8 @@ typedef struct EmscriptenUiEvent { * requires that the Window object sends resize events. It is valid to register a resize callback to other DOM elements, * but the browser is not required to fire resize events on them. */ -extern EMSCRIPTEN_RESULT emscripten_set_resize_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_scroll_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_resize_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_scroll_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenUiEvent *uiEvent, void *userData)); /* * The event structure passed in DOM element blur, focus, focusin and focusout events. @@ -290,10 +291,10 @@ typedef struct EmscriptenFocusEvent { * Registers a callback function for receiving DOM element blur, focus, focusin and focusout events. * See https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#event-type-blur */ -extern EMSCRIPTEN_RESULT emscripten_set_blur_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_focus_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_focusin_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_focusout_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_blur_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_focus_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_focusin_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_focusout_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenFocusEvent *focusEvent, void *userData)); /* * The event structure passed in the deviceorientation event. @@ -314,7 +315,7 @@ typedef struct EmscriptenDeviceOrientationEvent { * Registers a callback function for receiving the deviceorientation event. * See http://dev.w3.org/geo/api/spec-source-orientation.html */ -extern EMSCRIPTEN_RESULT emscripten_set_deviceorientation_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenDeviceOrientationEvent *orientationEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_deviceorientation_callback(void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenDeviceOrientationEvent *orientationEvent, void *userData)); /* * Returns the most recently received deviceorientation event state. Note that for this function call to succeed, emscripten_set_deviceorientation_callback * must have first been called with one of the mouse event types and a non-zero callback function pointer to enable the Device Orientation state capture. @@ -346,7 +347,7 @@ typedef struct EmscriptenDeviceMotionEvent { * Registers a callback function for receiving the devicemotion event. * See http://dev.w3.org/geo/api/spec-source-orientation.html */ -extern EMSCRIPTEN_RESULT emscripten_set_devicemotion_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenDeviceMotionEvent *motionEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_devicemotion_callback(void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenDeviceMotionEvent *motionEvent, void *userData)); /* * Returns the most recently received deviceomotion event state. Note that for this function call to succeed, emscripten_set_devicemotion_callback * must have first been called with one of the mouse event types and a non-zero callback function pointer to enable the Device Motion state capture. @@ -374,7 +375,7 @@ typedef struct EmscriptenOrientationChangeEvent { * Registers a callback function for receiving the orientationchange event. * https://dvcs.w3.org/hg/screen-orientation/raw-file/tip/Overview.html */ -extern EMSCRIPTEN_RESULT emscripten_set_orientationchange_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenOrientationChangeEvent *orientationChangeEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_orientationchange_callback(void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenOrientationChangeEvent *orientationChangeEvent, void *userData)); /* * Returns the current device orientation state. */ @@ -415,7 +416,7 @@ typedef struct EmscriptenFullscreenChangeEvent { * Registers a callback function for receiving the fullscreenchange event. * https://dvcs.w3.org/hg/screen-orientation/raw-file/tip/Overview.html */ -extern EMSCRIPTEN_RESULT emscripten_set_fullscreenchange_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_fullscreenchange_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenFullscreenChangeEvent *fullscreenChangeEvent, void *userData)); /* * Returns the current page fullscreen state. */ @@ -427,7 +428,7 @@ extern EMSCRIPTEN_RESULT emscripten_get_fullscreen_status(EmscriptenFullscreenCh * be queued to be executed the next time a JS event handler runs. If false, this * function will instead fail if not running inside a JS event handler. */ -extern EMSCRIPTEN_RESULT emscripten_request_fullscreen(const char *target, int deferUntilInEventHandler); +extern EMSCRIPTEN_RESULT emscripten_request_fullscreen(const char *target, EM_BOOL deferUntilInEventHandler); /* * Returns back to windowed browsing mode. */ @@ -451,7 +452,7 @@ typedef struct EmscriptenPointerlockChangeEvent { * Pointer lock hides the mouse cursor and exclusively gives the target element relative mouse movement events via the mousemove event. * http://www.w3.org/TR/pointerlock/ */ -extern EMSCRIPTEN_RESULT emscripten_set_pointerlockchange_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenPointerlockChangeEvent *pointerlockChangeEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_pointerlockchange_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenPointerlockChangeEvent *pointerlockChangeEvent, void *userData)); /* * Returns the current page pointerlock state. */ @@ -463,7 +464,7 @@ extern EMSCRIPTEN_RESULT emscripten_get_pointerlock_status(EmscriptenPointerlock * be queued to be executed the next time a JS event handler runs. If false, this * function will instead fail if not running inside a JS event handler. */ -extern EMSCRIPTEN_RESULT emscripten_request_pointerlock(const char *target, int deferUntilInEventHandler); +extern EMSCRIPTEN_RESULT emscripten_request_pointerlock(const char *target, EM_BOOL deferUntilInEventHandler); /* * Exits pointer lock state and restores the mouse cursor to be visible again. */ @@ -476,7 +477,7 @@ extern EMSCRIPTEN_RESULT emscripten_exit_pointerlock(void); /* * The event structure passed in the visibilitychange event. - * http://www.w3c-test.org/webperf/specs/PageVisibility/ + * http://www.w3.org/TR/page-visibility/ */ typedef struct EmscriptenVisibilityChangeEvent { // If true, the current browser page is now hidden. @@ -487,9 +488,9 @@ typedef struct EmscriptenVisibilityChangeEvent { /* * Registers a callback function for receiving the visibilitychange event. - * http://www.w3c-test.org/webperf/specs/PageVisibility/ + * http://www.w3.org/TR/page-visibility/ */ -extern EMSCRIPTEN_RESULT emscripten_set_visibilitychange_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_visibilitychange_callback(void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenVisibilityChangeEvent *visibilityChangeEvent, void *userData)); /* * Returns the current page visibility state. */ @@ -541,10 +542,10 @@ typedef struct EmscriptenTouchEvent { * Registers a callback function for receiving the touchstart, touchend, touchmove and touchcancel events. * http://www.w3.org/TR/touch-events/ */ -extern EMSCRIPTEN_RESULT emscripten_set_touchstart_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_touchend_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_touchmove_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_touchcancel_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_touchstart_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_touchend_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_touchmove_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_touchcancel_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenTouchEvent *touchEvent, void *userData)); /* * Represents the current snapshot state of a gamepad. @@ -577,8 +578,8 @@ typedef struct EmscriptenGamepadEvent { * Registers a callback function for receiving the gamepadconnected and gamepaddisconnected events. * http://www.w3.org/TR/gamepad/ */ -extern EMSCRIPTEN_RESULT emscripten_set_gamepadconnected_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_gamepaddisconnected_callback(void *userData, int useCapture, EM_BOOL (*func)(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_gamepadconnected_callback(void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_gamepaddisconnected_callback(void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const EmscriptenGamepadEvent *gamepadEvent, void *userData)); /* * Returns the number of gamepads connected to the system or EMSCRIPTEN_RESULT_NOT_SUPPORTED if the current browser does not support gamepads. @@ -636,8 +637,8 @@ extern EMSCRIPTEN_RESULT emscripten_set_beforeunload_callback(void *userData, co * Registers a callback function for the canvas webgl context webglcontextlost and webglcontextrestored events. * See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2 */ -extern EMSCRIPTEN_RESULT emscripten_set_webglcontextlost_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const void *reserved, void *userData)); -extern EMSCRIPTEN_RESULT emscripten_set_webglcontextrestored_callback(const char *target, void *userData, int useCapture, EM_BOOL (*func)(int eventType, const void *reserved, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_webglcontextlost_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const void *reserved, void *userData)); +extern EMSCRIPTEN_RESULT emscripten_set_webglcontextrestored_callback(const char *target, void *userData, EM_BOOL useCapture, EM_BOOL (*func)(int eventType, const void *reserved, void *userData)); /* * Queries the given canvas element for whether its WebGL context is in a lost state. diff --git a/system/lib/libc/musl/src/string/strsignal.c b/system/lib/libc/musl/src/string/strsignal.c new file mode 100644 index 0000000000000..905c0956184e0 --- /dev/null +++ b/system/lib/libc/musl/src/string/strsignal.c @@ -0,0 +1,115 @@ +#include +#include + +#if (SIGHUP == 1) && (SIGINT == 2) && (SIGQUIT == 3) && (SIGILL == 4) \ + && (SIGTRAP == 5) && (SIGABRT == 6) && (SIGBUS == 7) && (SIGFPE == 8) \ + && (SIGKILL == 9) && (SIGUSR1 == 10) && (SIGSEGV == 11) && (SIGUSR2 == 12) \ + && (SIGPIPE == 13) && (SIGALRM == 14) && (SIGTERM == 15) && (SIGSTKFLT == 16) \ + && (SIGCHLD == 17) && (SIGCONT == 18) && (SIGSTOP == 19) && (SIGTSTP == 20) \ + && (SIGTTIN == 21) && (SIGTTOU == 22) && (SIGURG == 23) && (SIGXCPU == 24) \ + && (SIGXFSZ == 25) && (SIGVTALRM == 26) && (SIGPROF == 27) && (SIGWINCH == 28) \ + && (SIGPOLL == 29) && (SIGPWR == 30) && (SIGSYS == 31) + +#define sigmap(x) x + +#else + +static const char map[] = { + [SIGHUP] = 1, + [SIGINT] = 2, + [SIGQUIT] = 3, + [SIGILL] = 4, + [SIGTRAP] = 5, + [SIGABRT] = 6, + [SIGBUS] = 7, + [SIGFPE] = 8, + [SIGKILL] = 9, + [SIGUSR1] = 10, + [SIGSEGV] = 11, + [SIGUSR2] = 12, + [SIGPIPE] = 13, + [SIGALRM] = 14, + [SIGTERM] = 15, + [SIGSTKFLT] = 16, + [SIGCHLD] = 17, + [SIGCONT] = 18, + [SIGSTOP] = 19, + [SIGTSTP] = 20, + [SIGTTIN] = 21, + [SIGTTOU] = 22, + [SIGURG] = 23, + [SIGXCPU] = 24, + [SIGXFSZ] = 25, + [SIGVTALRM] = 26, + [SIGPROF] = 27, + [SIGWINCH] = 28, + [SIGPOLL] = 29, + [SIGPWR] = 30, + [SIGSYS] = 31 +}; + +#define sigmap(x) ((x) >= sizeof map ? (x) : map[(x)]) + +#endif + +static const char strings[] = + "Unknown signal\0" + "Hangup\0" + "Interrupt\0" + "Quit\0" + "Illegal instruction\0" + "Trace/breakpoint trap\0" + "Aborted\0" + "Bus error\0" + "Arithmetic exception\0" + "Killed\0" + "User defined signal 1\0" + "Segmentation fault\0" + "User defined signal 2\0" + "Broken pipe\0" + "Alarm clock\0" + "Terminated\0" + "Stack fault\0" + "Child process status\0" + "Continued\0" + "Stopped (signal)\0" + "Stopped\0" + "Stopped (tty input)\0" + "Stopped (tty output)\0" + "Urgent I/O condition\0" + "CPU time limit exceeded\0" + "File size limit exceeded\0" + "Virtual timer expired\0" + "Profiling timer expired\0" + "Window changed\0" + "I/O possible\0" + "Power failure\0" + "Bad system call\0" + "RT32" + "\0RT33\0RT34\0RT35\0RT36\0RT37\0RT38\0RT39\0RT40" + "\0RT41\0RT42\0RT43\0RT44\0RT45\0RT46\0RT47\0RT48" + "\0RT49\0RT50\0RT51\0RT52\0RT53\0RT54\0RT55\0RT56" + "\0RT57\0RT58\0RT59\0RT60\0RT61\0RT62\0RT63\0RT64" +#if _NSIG > 65 + "\0RT65\0RT66\0RT67\0RT68\0RT69\0RT70\0RT71\0RT72" + "\0RT73\0RT74\0RT75\0RT76\0RT77\0RT78\0RT79\0RT80" + "\0RT81\0RT82\0RT83\0RT84\0RT85\0RT86\0RT87\0RT88" + "\0RT89\0RT90\0RT91\0RT92\0RT93\0RT94\0RT95\0RT96" + "\0RT97\0RT98\0RT99\0RT100\0RT101\0RT102\0RT103\0RT104" + "\0RT105\0RT106\0RT107\0RT108\0RT109\0RT110\0RT111\0RT112" + "\0RT113\0RT114\0RT115\0RT116\0RT117\0RT118\0RT119\0RT120" + "\0RT121\0RT122\0RT123\0RT124\0RT125\0RT126\0RT127\0RT128" +#endif + ""; + +char *strsignal(int signum) +{ + char *s = (char *)strings; + + signum = sigmap(signum); + if (signum - 1U >= _NSIG-1) signum = 0; + + for (; signum--; s++) for (; *s; s++); + + return s; +} diff --git a/system/lib/libcextra.symbols b/system/lib/libcextra.symbols index 1ab849bd26c4c..2c004699556a5 100644 --- a/system/lib/libcextra.symbols +++ b/system/lib/libcextra.symbols @@ -242,3 +242,4 @@ T wmemset T wprintf T fnmatch + T strsignal diff --git a/system/lib/pkgconfig/egl.pc b/system/lib/pkgconfig/egl.pc new file mode 100644 index 0000000000000..7d023da3bb90e --- /dev/null +++ b/system/lib/pkgconfig/egl.pc @@ -0,0 +1,3 @@ +Name: egl +Description: EGL library +Version: 10.2.2 diff --git a/system/lib/pkgconfig/glesv2.pc b/system/lib/pkgconfig/glesv2.pc new file mode 100644 index 0000000000000..97e4732819063 --- /dev/null +++ b/system/lib/pkgconfig/glesv2.pc @@ -0,0 +1,3 @@ +Name: glesv2 +Description: OpenGL ES 2.0 library +Version: 10.2.2 diff --git a/system/lib/pkgconfig/libpng.pc b/system/lib/pkgconfig/libpng.pc new file mode 100644 index 0000000000000..a39371a0c937b --- /dev/null +++ b/system/lib/pkgconfig/libpng.pc @@ -0,0 +1,3 @@ +Name: libpng +Description: Loads and saves PNG files +Version: 1.6.12 diff --git a/system/lib/pkgconfig/sdl.pc b/system/lib/pkgconfig/sdl.pc new file mode 100644 index 0000000000000..5925707ab177c --- /dev/null +++ b/system/lib/pkgconfig/sdl.pc @@ -0,0 +1,4 @@ +Name: sdl +Description: Simple DirectMedia Layer is a cross-platform multimedia library designed to provide low level access to audio, keyboard, mouse, joystick, 3D hardware via OpenGL, and 2D video framebuffer. +Version: 1.2.15 +Cflags: -D_GNU_SOURCE=1 -D_REENTRANT diff --git a/system/lib/pkgconfig/zlib.pc b/system/lib/pkgconfig/zlib.pc new file mode 100644 index 0000000000000..a2a3c80823ed2 --- /dev/null +++ b/system/lib/pkgconfig/zlib.pc @@ -0,0 +1,3 @@ +Name: zlib +Description: zlib compression library +Version: 1.2.8 diff --git a/tests/bullet/CMakeLists.txt b/tests/bullet/CMakeLists.txt index 13f22e7c01d06..55299a0615d15 100644 --- a/tests/bullet/CMakeLists.txt +++ b/tests/bullet/CMakeLists.txt @@ -265,7 +265,7 @@ IF (USE_GLUT) ENDIF (MSVC) ENDIF (GLUT_FOUND) - IF(NOT WIN32) + IF(NOT WIN32 AND NOT CMAKE_CROSSCOMPILING) # This is added for linux. This should always work if everything is installed and working fine. INCLUDE_DIRECTORIES(/usr/include /usr/local/include) ENDIF() diff --git a/tests/cmake/target_html/CMakeLists.txt b/tests/cmake/target_html/CMakeLists.txt index f84ecb42526b8..968afb9397c51 100644 --- a/tests/cmake/target_html/CMakeLists.txt +++ b/tests/cmake/target_html/CMakeLists.txt @@ -55,8 +55,25 @@ if(NOT EMSCRIPTEN_INCLUDE_DIR) message(FATAL_ERROR "emscripten.h could not be found! Is CMAKE_FIND_ROOT_PATH='${CMAKE_FIND_ROOT_PATH}' correct?") endif() +include(CheckIncludeFile) + +check_include_file(stdlib.h HAVE_STDLIB_H) +if (NOT ${HAVE_STDLIB_H}) + message(FATAL_ERROR "CMake script check_include_file failed! Could not find stdlib.h via it!") +endif() + +if (NOT CMAKE_EXECUTABLE_SUFFIX STREQUAL ".js") + message(FATAL_ERROR "The default suffix for building executables should be .js!") +endif() SET(CMAKE_EXECUTABLE_SUFFIX ".html") +# CMake built-in check_include_file() macro interacts with CMAKE_EXECUTABLE_SUFFIX, so make sure it works after user changes that. + +check_include_file(math.h HAVE_MATH_H) +if (NOT ${HAVE_MATH_H}) + message(FATAL_ERROR "CMake script check_include_file failed! Could not find math.h via it!") +endif() + add_executable(hello_world_gles ${sourceFiles}) set_target_properties(hello_world_gles PROPERTIES LINK_FLAGS "${linkFlags}") diff --git a/tests/cmake/target_js/CMakeLists.txt b/tests/cmake/target_js/CMakeLists.txt index a1b44ee19b2c2..1de5d97e2d76f 100644 --- a/tests/cmake/target_js/CMakeLists.txt +++ b/tests/cmake/target_js/CMakeLists.txt @@ -14,7 +14,42 @@ else() # Either MinSizeRel, RelWithDebInfo or Release, all which run with optimi SET(linkFlags "-O2 -s NO_EXIT_RUNTIME=1") endif() -SET(CMAKE_EXECUTABLE_SUFFIX ".js") +# Test that the CMake-provided macro check_function_exists() works. +include(CheckFunctionExists) +check_function_exists("strtod" HAVE_STRTOD) +if (NOT ${HAVE_STRTOD}) + message(FATAL_ERROR "CMake script check_function_exists failed! Could not detect if strtod() is supported!") +endif() + +# Test that the CMake-provided macro check_function_exists() is not actually trivially returning true for everything. +check_function_exists("some_nonexisting_function" HAVE_NONEXISTING_FUNCTION) +if (${HAVE_NONEXISTING_FUNCTION}) + message(FATAL_ERROR "CMake script check_function_exists failed! It erroneously reports that function some_nonexisting_function() would exist!") +endif() + +# Test that the CMake-provided macro check_include_file() works. +include(CheckIncludeFile) +check_include_file(stdlib.h HAVE_STDLIB_H) +if (NOT ${HAVE_STDLIB_H}) + message(FATAL_ERROR "CMake script check_include_file failed! Could not find stdlib.h via it!") +endif() + +# Test that the CMake-provided macro check_include_file() is not actually trivially returning true for everything. +check_include_file(some_nonexisting_include.h HAVE_NONEXISTING_INCLUDE_H) +if (${HAVE_NONEXISTING_INCLUDE_H}) + message(FATAL_ERROR "CMake script check_include_file failed! It erroneously reports that the C header some_nonexisting_include.h would exist!") +endif() + +if (NOT CMAKE_EXECUTABLE_SUFFIX STREQUAL ".js") + message(FATAL_ERROR "The default suffix for building executables should be .js!") +endif() + +# CMake built-in check_include_file() macro interacts with CMAKE_EXECUTABLE_SUFFIX, so make sure it works after user changes that. + +check_include_file(math.h HAVE_MATH_H) +if (NOT ${HAVE_MATH_H}) + message(FATAL_ERROR "CMake script check_include_file failed! Could not find math.h via it!") +endif() if (WIN32) message(FATAL_ERROR "WIN32 should not be defined when cross-compiling!") diff --git a/tests/core/test_ccall.out b/tests/core/test_ccall.out index 526ed80db40d3..b4cddc5e4695f 100644 --- a/tests/core/test_ccall.out +++ b/tests/core/test_ccall.out @@ -15,6 +15,7 @@ number,10 650 number,21 * +5 atr 10 bret diff --git a/tests/dirent/test_readdir.c b/tests/dirent/test_readdir.c index 12f97b73645d8..dc14a1471759f 100644 --- a/tests/dirent/test_readdir.c +++ b/tests/dirent/test_readdir.c @@ -125,6 +125,7 @@ void test() { } int main() { + printf("SIGILL: %s\n", strsignal(SIGILL)); atexit(cleanup); signal(SIGABRT, cleanup); setup(); diff --git a/tests/filesystem/output.txt b/tests/filesystem/output.txt index 06e0a0bb4ba24..1262d1591c842 100644 --- a/tests/filesystem/output.txt +++ b/tests/filesystem/output.txt @@ -1,14 +1,3 @@ - - isRoot: false - exists: true - error: 0 - path: /abc - name: abc - object.contents: ["123","456","deviceA","localLink","rootLink","relativeLink"] - parentExists: true - parentPath: / - parentObject.contents: ["tmp","dev","forbidden","abc","def"] - / isRoot: true exists: true diff --git a/tests/filesystem/src.js b/tests/filesystem/src.js index 91337f5bb7778..7f0395e5756c4 100644 --- a/tests/filesystem/src.js +++ b/tests/filesystem/src.js @@ -31,7 +31,6 @@ function explore(path) { } FS.currentPath = '/abc'; -explore(''); explore('/'); explore('.'); explore('..'); diff --git a/tests/openjpeg/codec/CMakeLists.txt b/tests/openjpeg/codec/CMakeLists.txt index 88b1661f07136..a1ef69f3f44da 100644 --- a/tests/openjpeg/codec/CMakeLists.txt +++ b/tests/openjpeg/codec/CMakeLists.txt @@ -1,14 +1,16 @@ # Build the demo app, small examples # First thing define the common source: -# XXX Emscripten: Force getopt.c SET(common_SRCS convert.c index.c ${OPENJPEG_SOURCE_DIR}/common/color.c - ${OPENJPEG_SOURCE_DIR}/common/getopt.c ) +if (NOT CMAKE_HAVE_GETOPT_H) + SET(common_SRCS ${common_SRCS} ${OPENJPEG_SOURCE_DIR}/common/getopt.c) +endif() + # Headers file are located here: INCLUDE_DIRECTORIES( ${OPENJPEG_SOURCE_DIR}/libopenjpeg diff --git a/tests/runner.py b/tests/runner.py index 93c40e3f41e2d..412f662cfa997 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -735,7 +735,7 @@ def btest(self, filename, expected=None, reference=None, force_c=False, referenc def get_bullet_library(runner_core, use_cmake): if use_cmake: configure_commands = ['cmake', '.'] - configure_args = ['-DBUILD_DEMOS=OFF', '-DBUILD_EXTRAS=OFF'] + configure_args = ['-DBUILD_DEMOS=OFF', '-DBUILD_EXTRAS=OFF', '-DUSE_GLUT=OFF'] # Depending on whether 'configure' or 'cmake' is used to build, Bullet places output files in different directory structures. generated_libs = [os.path.join('src', 'BulletDynamics', 'libBulletDynamics.a'), os.path.join('src', 'BulletCollision', 'libBulletCollision.a'), diff --git a/tests/sockets/test_sockets_echo_client.c b/tests/sockets/test_sockets_echo_client.c index 58d005c499b60..48c031a4c54ef 100644 --- a/tests/sockets/test_sockets_echo_client.c +++ b/tests/sockets/test_sockets_echo_client.c @@ -95,7 +95,9 @@ void main_loop() { assert(!strcmp(server.msg.buffer, MESSAGE)); finish(EXIT_SUCCESS); } - } else { + } + + if (server.state == MSG_WRITE) { if (!FD_ISSET(server.fd, &fdw)) { return; } @@ -117,6 +119,30 @@ void main_loop() { } } +// The callbacks for the async network events have a different signature than from +// emscripten_set_main_loop (they get passed the fd of the socket triggering the event). +// In this test application we want to try and keep as much in common as the timed loop +// version but in a real application the fd can be used instead of needing to select(). +void async_main_loop(int fd, void* userData) { + printf("%s callback\n", userData); + main_loop(); +} + +void error_callback(int fd, int err, const char* msg, void* userData) { + int error; + socklen_t len = sizeof(error); + + int ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len); + printf("%s callback\n", userData); + printf("error message: %s\n", msg); + + if (err == error) { + finish(EXIT_SUCCESS); + } else { + finish(EXIT_FAILURE); + } +} + int main() { struct sockaddr_in addr; int res; @@ -161,7 +187,15 @@ int main() { } #ifdef __EMSCRIPTEN__ - emscripten_set_main_loop(main_loop, 0, 0); +#if TEST_ASYNC + // The first parameter being passed is actually an arbitrary userData pointer + // for simplicity this test just passes a basic char* + emscripten_set_socket_error_callback("error", error_callback); + emscripten_set_socket_open_callback("open", async_main_loop); + emscripten_set_socket_message_callback("message", async_main_loop); +#else + emscripten_set_main_loop(main_loop, 60, 0); +#endif #else while (1) main_loop(); #endif diff --git a/tests/sockets/test_sockets_echo_server.c b/tests/sockets/test_sockets_echo_server.c index 55898add7b069..4b5b75c68c0f5 100644 --- a/tests/sockets/test_sockets_echo_server.c +++ b/tests/sockets/test_sockets_echo_server.c @@ -114,7 +114,9 @@ void main_loop() { client.read = 0; client.state = MSG_WRITE; } - } else { + } + + if (client.state == MSG_WRITE) { if (!FD_ISSET(fd, &fdw)) { return; } @@ -142,6 +144,15 @@ void main_loop() { } } +// The callbacks for the async network events have a different signature than from +// emscripten_set_main_loop (they get passed the fd of the socket triggering the event). +// In this test application we want to try and keep as much in common as the timed loop +// version but in a real application the fd can be used instead of needing to select(). +void async_main_loop(int fd, void* userData) { + printf("%s callback\n", userData); + main_loop(); +} + int main() { struct sockaddr_in addr; int res; @@ -187,7 +198,15 @@ int main() { #endif #ifdef __EMSCRIPTEN__ +#if TEST_ASYNC + // The first parameter being passed is actually an arbitrary userData pointer + // for simplicity this test just passes a basic char* + emscripten_set_socket_connection_callback("connection", async_main_loop); + emscripten_set_socket_message_callback("message", async_main_loop); + emscripten_set_socket_close_callback("close", async_main_loop); +#else emscripten_set_main_loop(main_loop, 60, 0); +#endif #else while (1) main_loop(); #endif diff --git a/tests/test_core.py b/tests/test_core.py index a401766056cbb..a975e1e183dd4 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -2008,10 +2008,11 @@ def process(filename): Settings.EXPORTED_FUNCTIONS = ['_main', '_save_me_aimee'] self.do_run_from_file(src, output, post_build=check) - # test EXPORT_ALL - Settings.EXPORTED_FUNCTIONS = [] - Settings.EXPORT_ALL = 1 - self.do_run_from_file(src, output, post_build=check) + if self.run_name != 's_0_0' and self.run_name != 's_0_1': + # test EXPORT_ALL + Settings.EXPORTED_FUNCTIONS = [] + Settings.EXPORT_ALL = 1 + self.do_run_from_file(src, output, post_build=check) def test_emscripten_get_now(self): if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2') @@ -4197,7 +4198,7 @@ def test_fileno(self): def test_readdir(self): src = open(path_from_root('tests', 'dirent', 'test_readdir.c'), 'r').read() - self.do_run(src, 'success', force_c=True) + self.do_run(src, 'SIGILL: Illegal instruction\nsuccess', force_c=True) def test_readdir_empty(self): src = open(path_from_root('tests', 'dirent', 'test_readdir_empty.c'), 'r').read() @@ -5612,6 +5613,8 @@ def process(filename): ret = ccall('pointer', 'pointer', ['pointer'], [p]); Module.print([typeof ret, getValue(ret, 'i32')]); Module.print('*'); // part 2: cwrap + var noThirdParam = Module['cwrap']('get_int', 'number'); + Module.print(noThirdParam()); var multi = Module['cwrap']('multi', 'number', ['number', 'number', 'number', 'string']); Module.print(multi(2, 1.4, 3, 'atr')); Module.print(multi(8, 5.4, 4, 'bret')); diff --git a/tests/test_egl.c b/tests/test_egl.c index 6eef4aa504efa..fd6285b8662ab 100644 --- a/tests/test_egl.c +++ b/tests/test_egl.c @@ -1,6 +1,8 @@ #include #include +#include + 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) @@ -46,6 +48,43 @@ int main(int argc, char *argv[]) EGLContext context = eglCreateContext(display, config, NULL, contextAttribsOld); assert(eglGetError() != EGL_SUCCESS); + //Test for invalid attribs + EGLint contextInvalidAttribs[] = + { + EGL_CONTEXT_CLIENT_VERSION, 2, + 0xFFFF, -1, + EGL_NONE + }; + context = eglCreateContext(display, config, NULL, contextInvalidAttribs); + assert(eglGetError() != EGL_SUCCESS); + assert(context == 0); + //Test for missing terminator + EGLint contextAttribsMissingTerm[] = + { + EGL_CONTEXT_CLIENT_VERSION, 2, + }; + context = eglCreateContext(display, config, NULL, contextAttribsMissingTerm); + assert(eglGetError() != EGL_SUCCESS); + assert(context == 0); + //Test for null terminator + EGLint contextAttribsNullTerm[] = + { + EGL_CONTEXT_CLIENT_VERSION, 2, + 0 + }; + context = eglCreateContext(display, config, NULL, contextAttribsNullTerm); + assert(eglGetError() != EGL_SUCCESS); + assert(context == 0); + //Test for invalid and null terminator + EGLint contextAttribsNullTermInvalid[] = + { + 0, + }; + context = eglCreateContext(display, config, NULL, contextAttribsNullTermInvalid); + assert(eglGetError() != EGL_SUCCESS); + assert(context == 0); + + // The correct attributes, should create a good EGL context EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, @@ -79,6 +118,9 @@ int main(int argc, char *argv[]) assert(eglGetProcAddress("glClear") != 0); assert(eglGetProcAddress("glWakaWaka") == 0); + glClearColor(1.0,0.0,0.0,0.5); + glClear(GL_COLOR_BUFFER_BIT); + #ifdef REPORT_RESULT REPORT_RESULT(); #endif diff --git a/tests/test_other.py b/tests/test_other.py index d982145f1d99f..f877d15ed0d34 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -380,7 +380,7 @@ def check_makefile(configuration, dirname): # Run Cmake if invoke_method == 'cmake': # Test invoking cmake directly. - cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+path_from_root('cmake', 'Platform', 'Emscripten.cmake'), + cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+path_from_root('cmake', 'Modules', 'Platform', 'Emscripten.cmake'), '-DCMAKE_BUILD_TYPE=' + configuration, cmake_arguments[i], '-G', generator, cmakelistsdir] else: # Test invoking via 'emconfigure cmake' @@ -398,7 +398,9 @@ def check_makefile(configuration, dirname): prebuild(configuration, tempdirname) # Build - cmd = make + (['VERBOSE=1'] if verbose_level >= 3 else []) + cmd = make + if verbose_level >= 3 and 'Ninja' not in generator: + cmd += ['VERBOSE=1'] ret = Popen(cmd, stdout=None if verbose_level >= 2 else PIPE).communicate() if len(ret) > 1 and ret[1] != None and len(ret[1].strip()) > 0: logging.error(ret[1]) # If there were any errors, print them directly to console for diagnostics. @@ -921,7 +923,9 @@ def measure_funcs(filename): Popen([PYTHON, EMCC, src] + libs + ['-o', 'test.js', '-O2'] + debug + ['-s', 'OUTLINING_LIMIT=%d' % outlining_limit] + args).communicate() assert os.path.exists('test.js') shutil.copyfile('test.js', '%d_test.js' % outlining_limit) + assert len(JS_ENGINES) > 1 for engine in JS_ENGINES: + if engine == V8_ENGINE: continue # ban v8, weird failures out = run_js('test.js', engine=engine, stderr=PIPE, full_output=True) self.assertContained(expected, out) if engine == SPIDERMONKEY_ENGINE: self.validate_asmjs(out) @@ -1944,7 +1948,7 @@ def test_scons(self): # also incidentally tests c++11 integration in llvm 3.1 shutil.copytree(path_from_root('tools', 'scons', 'site_scons'), os.path.join(self.get_dir(), 'test', 'site_scons')) os.chdir(os.path.join(self.get_dir(), 'test')) Popen(['scons']).communicate() - output = run_js('scons_integration.js') + output = run_js('scons_integration.js', assert_returncode=5) assert 'If you see this - the world is all right!' in output def test_embind(self): @@ -2930,3 +2934,151 @@ def test_returncode(self): output = process.communicate() assert process.returncode == 123, process.returncode + def test_mkdir_silly(self): + open('src.cpp', 'w').write(r''' +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + printf("\n"); + for (int i = 1; i < argc; i++) { + printf("%d:\n", i); + int ok = mkdir(argv[i], S_IRWXU|S_IRWXG|S_IRWXO); + printf(" make %s: %d\n", argv[i], ok); + DIR *dir = opendir(argv[i]); + printf(" open %s: %d\n", argv[i], dir != NULL); + if (dir) { + struct dirent *entry; + while ((entry = readdir(dir))) { + printf(" %s, %d\n", entry->d_name, entry->d_type); + } + } + } +} + ''') + Popen([PYTHON, EMCC, 'src.cpp']).communicate() + + # cannot create /, can open + self.assertContained(r''' +1: + make /: -1 + open /: 1 + ., 4 + .., 4 + tmp, 4 + dev, 4 +''', run_js('a.out.js', args=['/'])) + # cannot create empty name, cannot open + self.assertContained(r''' +1: + make : -1 + open : 0 +''', run_js('a.out.js', args=[''])) + # can create unnormalized path, can open + self.assertContained(r''' +1: + make /a//: 0 + open /a//: 1 + ., 4 + .., 4 +''', run_js('a.out.js', args=['/a//'])) + # can create child unnormalized + self.assertContained(r''' +1: + make /a: 0 + open /a: 1 + ., 4 + .., 4 +2: + make /a//b//: 0 + open /a//b//: 1 + ., 4 + .., 4 +''', run_js('a.out.js', args=['/a', '/a//b//'])) + + def test_stat_silly(self): + open('src.cpp', 'w').write(r''' +#include +#include +#include + +int main(int argc, char **argv) { + for (int i = 1; i < argc; i++) { + const char *path = argv[i]; + struct stat path_stat; + if (stat(path, &path_stat) != 0) { + printf("Failed to stat path: %s; errno=%d\n", path, errno); + } else { + printf("ok on %s\n", path); + } + } +} + ''') + Popen([PYTHON, EMCC, 'src.cpp']).communicate() + + # cannot stat "" + self.assertContained(r'''Failed to stat path: /a; errno=2 +Failed to stat path: ; errno=2 +''', run_js('a.out.js', args=['/a', ''])) + + def test_symlink_silly(self): + open('src.cpp', 'w').write(r''' +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + if (symlink(argv[1], argv[2]) != 0) { + printf("Failed to symlink paths: %s, %s; errno=%d\n", argv[1], argv[2], errno); + } else { + printf("ok\n"); + } +} + ''') + Popen([PYTHON, EMCC, 'src.cpp']).communicate() + + # cannot symlink nonexistents + self.assertContained(r'''Failed to symlink paths: , abc; errno=2''', run_js('a.out.js', args=['', 'abc'])) + self.assertContained(r'''Failed to symlink paths: , ; errno=2''', run_js('a.out.js', args=['', ''])) + self.assertContained(r'''ok''', run_js('a.out.js', args=['123', 'abc'])) + self.assertContained(r'''Failed to symlink paths: abc, ; errno=2''', run_js('a.out.js', args=['abc', ''])) + + def test_emversion(self): + open('src.cpp', 'w').write(r''' + #include + int main() { + printf("major: %d\n", __EMSCRIPTEN_major__); + printf("minor: %d\n", __EMSCRIPTEN_minor__); + printf("tiny: %d\n", __EMSCRIPTEN_tiny__); + } + ''') + Popen([PYTHON, EMCC, 'src.cpp']).communicate() + self.assertContained(r'''major: %d +minor: %d +tiny: %d +''' % (EMSCRIPTEN_VERSION_MAJOR, EMSCRIPTEN_VERSION_MINOR, EMSCRIPTEN_VERSION_TINY), run_js('a.out.js')) + + def test_malloc_implicit(self): + open('src.cpp', 'w').write(r''' +#include +#include +#include +int main() { + const char *home = getenv("HOME"); + for(unsigned int i = 0; i < 5; ++i) { + const char *curr = getenv("HOME"); + assert(curr == home); + } + printf("ok\n"); +} + ''') + Popen([PYTHON, EMCC, 'src.cpp']).communicate() + self.assertContained('ok', run_js('a.out.js')) + diff --git a/tests/test_sockets.py b/tests/test_sockets.py index 8c2889df2b0a9..4de8d14500ff5 100644 --- a/tests/test_sockets.py +++ b/tests/test_sockets.py @@ -248,6 +248,26 @@ def test_sockets_echo(self): with harness: self.btest(os.path.join('sockets', 'test_sockets_echo_client.c'), expected='0', args=['-DSOCKK=%d' % harness.listen_port, '-DTEST_DGRAM=%d' % datagram, sockets_include]) + def test_sockets_async_echo(self): + # Run with ./runner.py sockets.test_sockets_async_echo + sockets_include = '-I'+path_from_root('tests', 'sockets') + + # Websockify-proxied servers can't run dgram tests + harnesses = [ + (WebsockifyServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_ASYNC=1'], 49165), 0), + (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=0', '-DTEST_ASYNC=1'], 49166), 0), + (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=1', '-DTEST_ASYNC=1'], 49167), 1), + # The following forces non-NULL addr and addlen parameters for the accept call + (CompiledServerHarness(os.path.join('sockets', 'test_sockets_echo_server.c'), [sockets_include, '-DTEST_DGRAM=0', '-DTEST_ACCEPT_ADDR=1', '-DTEST_ASYNC=1'], 49168), 0) + ] + + for harness, datagram in harnesses: + with harness: + self.btest(os.path.join('sockets', 'test_sockets_echo_client.c'), expected='0', args=['-DSOCKK=%d' % harness.listen_port, '-DTEST_DGRAM=%d' % datagram, '-DTEST_ASYNC=1', sockets_include]) + + # Deliberately attempt a connection on a port that will fail to test the error callback and getsockopt + self.btest(os.path.join('sockets', 'test_sockets_echo_client.c'), expected='0', args=['-DSOCKK=49169', '-DTEST_ASYNC=1', sockets_include]) + def test_sockets_echo_bigdata(self): sockets_include = '-I'+path_from_root('tests', 'sockets') diff --git a/tools/ffdb.py b/tools/ffdb.py index a948c70032b72..93fae51859f89 100755 --- a/tools/ffdb.py +++ b/tools/ffdb.py @@ -562,7 +562,7 @@ def main(): try: b2g_socket.connect((HOST, PORT)) except Exception, e: - if e[0] == 61: # Connection refused + if e[0] == 61 or e[0] == 107 or e[0] == 111: # 61 == Connection refused and 107+111 == Transport endpoint is not connected if (HOST == 'localhost' or HOST == '127.0.0.1') and not connect_to_simulator: cmd = [ADB, 'forward', 'tcp:'+str(PORT), 'localfilesystem:/data/local/debugger-socket'] print 'Connection to ' + HOST + ':' + str(PORT) + ' refused, attempting to forward device debugger-socket to local address by calling ' + str(cmd) + ':' @@ -660,6 +660,9 @@ def main(): else: print 'Web browser is not running!' elif sys.argv[1] == 'log': + if len(sys.argv) < 3: + print 'Error! No application name given! Usage: ' + sys.argv[0] + ' ' + sys.argv[1] + ' ' + return 1 clear = '-c' in sys.argv or '-clear' in sys.argv or '--clear' in sys.argv b2g_log(sys.argv[2], clear) elif sys.argv[1] == 'memory': diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index e06c2d2f57fe3..2fad08b3f4a08 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -220,10 +220,6 @@ def split_funcs(js): funcs = split_funcs(js) js = None - if 'last' in passes and len(funcs) > 0: - if max([len(func[1]) for func in funcs]) > 200000: - print >> sys.stderr, 'warning: Output contains some very large functions, consider using OUTLINING_LIMIT to break them up (see settings.js)' - # if we are making source maps, we want our debug numbering to start from the # top of the file, so avoid breaking the JS into chunks cores = 1 if source_map else int(os.environ.get('EMCC_CORES') or multiprocessing.cpu_count()) @@ -343,6 +339,12 @@ def sorter(x, y): elif x[0] > y[0]: return -1 return 0 funcs.sort(sorter) + + if 'last' in passes and len(funcs) > 0: + count = funcs[0][1].count('\n') + if count > 3000: + print >> sys.stderr, 'warning: Output contains some very large functions (%s lines in %s), consider building source files with -Os or -Oz, and/or trying OUTLINING_LIMIT to break them up (see settings.js; note that the parameter there affects AST nodes, while we measure lines here, so the two may not match up)' % (count, funcs[0][0]) + for func in funcs: f.write(func[1]) funcs = None diff --git a/tools/jsrun.py b/tools/jsrun.py index e2ec5439730e4..6b7e295bd60f0 100644 --- a/tools/jsrun.py +++ b/tools/jsrun.py @@ -17,7 +17,7 @@ def timeout_run(proc, timeout=None, note='unnamed process', full_output=False): logging.info('Process ' + str(proc.pid) + ' finished after ' + str(time.time() - start) + ' seconds. Exit code: ' + str(proc.returncode)) return '\n'.join(out) if full_output else out[0] -def run_js(filename, engine=None, args=[], check_timeout=False, stdin=None, stdout=PIPE, stderr=None, cwd=None, full_output=False, assert_returncode=0): +def run_js(filename, engine=None, args=[], check_timeout=False, stdin=None, stdout=PIPE, stderr=None, cwd=None, full_output=False, assert_returncode=0, error_limit=-1): if type(engine) is not list: engine = [engine] command = engine + [filename] + (['--'] if 'd8' in engine[0] or 'jsc' in engine[0] else []) + args @@ -36,5 +36,6 @@ def run_js(filename, engine=None, args=[], check_timeout=False, stdin=None, stdo 'Execution', full_output=full_output) if assert_returncode is not None and proc.returncode is not assert_returncode: - raise Exception('Expected the command ' + str(command) + ' to finish with return code ' + str(assert_returncode) + ', but it returned with code ' + str(proc.returncode) + ' instead! Output: ' + str(ret)) + raise Exception('Expected the command ' + str(command) + ' to finish with return code ' + str(assert_returncode) + ', but it returned with code ' + str(proc.returncode) + ' instead! Output: ' + str(ret)[:error_limit]) return ret + diff --git a/tools/shared.py b/tools/shared.py index 10c76d422e4df..0570d0a04c1f4 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -366,6 +366,17 @@ def find_temp_directory(): try: EMSCRIPTEN_VERSION = open(path_from_root('emscripten-version.txt')).read().strip() + try: + parts = map(int, EMSCRIPTEN_VERSION.split('.')) + EMSCRIPTEN_VERSION_MAJOR = parts[0] + EMSCRIPTEN_VERSION_MINOR = parts[1] + EMSCRIPTEN_VERSION_TINY = parts[2] + except Exception, e: + logging.warning('emscripten version ' + EMSCRIPTEN_VERSION + ' lacks standard parts') + EMSCRIPTEN_VERSION_MAJOR = 0 + EMSCRIPTEN_VERSION_MINOR = 0 + EMSCRIPTEN_VERSION_TINY = 0 + raise e except Exception, e: logging.error('cannot find emscripten version ' + str(e)) EMSCRIPTEN_VERSION = 'unknown' @@ -662,7 +673,10 @@ def get_llvm_target(): except: COMPILER_OPTS = [] COMPILER_OPTS = COMPILER_OPTS + [#'-fno-threadsafe-statics', # disabled due to issue 1289 - '-target', LLVM_TARGET] + '-target', LLVM_TARGET, + '-D__EMSCRIPTEN_major__=' + str(EMSCRIPTEN_VERSION_MAJOR), + '-D__EMSCRIPTEN_minor__=' + str(EMSCRIPTEN_VERSION_MINOR), + '-D__EMSCRIPTEN_tiny__=' + str(EMSCRIPTEN_VERSION_TINY)] # COMPILER_STANDARDIZATION_OPTS: Options to correct various predefined macro options. COMPILER_STANDARDIZATION_OPTS = [] @@ -999,7 +1013,7 @@ def has_substr(array, substr): # Append the Emscripten toolchain file if the user didn't specify one. if not has_substr(args, '-DCMAKE_TOOLCHAIN_FILE'): - args.append('-DCMAKE_TOOLCHAIN_FILE=' + path_from_root('cmake', 'Platform', 'Emscripten.cmake')) + args.append('-DCMAKE_TOOLCHAIN_FILE=' + path_from_root('cmake', 'Modules', 'Platform', 'Emscripten.cmake')) # On Windows specify MinGW Makefiles if we have MinGW and no other toolchain was specified, to avoid CMake # pulling in a native Visual Studio, or Unix Makefiles. @@ -1014,16 +1028,21 @@ def configure(args, stdout=None, stderr=None, env=None): return if env is None: env = Building.get_building_env() - env['EMMAKEN_JUST_CONFIGURE'] = '1' if 'cmake' in args[0]: + # Note: EMMAKEN_JUST_CONFIGURE shall not be enabled when configuring with CMake. This is because CMake + # does expect to be able to do config-time builds with emcc. args = Building.handle_CMake_toolchain(args, env) + else: + # When we configure via a ./configure script, don't do config-time compilation with emcc, but instead + # do builds natively with Clang. This is a heuristic emulation that may or may not work. + env['EMMAKEN_JUST_CONFIGURE'] = '1' try: process = Popen(args, stdout=stdout, stderr=stderr, env=env) process.communicate() except Exception, e: logging.error('Exception thrown when invoking Popen in configure with args: "%s"!' % ' '.join(args)) raise - del env['EMMAKEN_JUST_CONFIGURE'] + if 'EMMAKEN_JUST_CONFIGURE' in env: del env['EMMAKEN_JUST_CONFIGURE'] if process.returncode is not 0: logging.error('Configure step failed with non-zero return code ' + str(process.returncode) + '! Command line: ' + str(args)) raise subprocess.CalledProcessError(cmd=args, returncode=process.returncode) diff --git a/tools/system_libs.py b/tools/system_libs.py index 9e904b80d0e41..0cfa7d1a9c933 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -340,6 +340,7 @@ def create_libcextra(): 'strpbrk.c', 'strrchr.c', 'strsep.c', + 'strsignal.c', 'strspn.c', 'strstr.c', 'strtok.c', diff --git a/tools/validate_asmjs.py b/tools/validate_asmjs.py index 4136af93230e1..02ff506da7833 100644 --- a/tools/validate_asmjs.py +++ b/tools/validate_asmjs.py @@ -16,7 +16,7 @@ # Looks up SpiderMonkey engine using the variable SPIDERMONKEY_ENGINE in ~/.emscripten, and if not set up there, via PATH. def find_spidermonkey_engine(): - sm_engine = shared.SPIDERMONKEY_ENGINE if hasattr(shared, 'SPIDERMONKEY_ENGINE') else [''] + sm_engine = shared.listify(shared.SPIDERMONKEY_ENGINE) if hasattr(shared, 'SPIDERMONKEY_ENGINE') else [''] if not sm_engine or len(sm_engine[0]) == 0 or not os.path.exists(sm_engine[0]): sm_engine[0] = shared.Building.which('js') if sm_engine[0] == None: @@ -25,17 +25,25 @@ def find_spidermonkey_engine(): # Given a .js file, returns True/False depending on if that file is valid asm.js def validate_asmjs_jsfile(filename, muteOutput): - process = subprocess.Popen(find_spidermonkey_engine() + ['-c', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) + cmd = find_spidermonkey_engine() + ['-c', filename] + if cmd[0] == 'js-not-found': + print >> sys.stderr, 'Could not find SpiderMonkey engine! Please set tis location to SPIDERMONKEY_ENGINE in your ~/.emscripten configuration file!' + return False + try: + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) + except Exception, e: + print >> sys.stderr, 'Executing command ' + str(cmd) + ' failed due to an exception: ' + str(e) + '!' + return False (stdout, stderr) = process.communicate() if not muteOutput: if len(stdout.strip()) > 0: print stdout.strip() if len(stderr.strip()) > 0: # Pretty-print the output not to contain a spurious warning. - stderr = stderr.replace('warning: successfully compiled asm.js', ' successfully compiled asm.js') - + warning_re = re.compile(re.escape('warning: successfully compiled asm.js'), re.IGNORECASE) + stderr = warning_re.sub(' successfully compiled asm.js', stderr) print >> sys.stderr, stderr.strip() - if 'successfully compiled asm.js' in stderr: + if 'successfully compiled asm.js' in stderr.lower(): return True else: return False