Skip to content

Commit

Permalink
Merge branch 'incoming'
Browse files Browse the repository at this point in the history
  • Loading branch information
kripken committed Sep 12, 2013
2 parents 3889020 + f9dff9b commit 6010666
Show file tree
Hide file tree
Showing 35 changed files with 1,391 additions and 372 deletions.
110 changes: 95 additions & 15 deletions cmake/Platform/Emscripten.cmake
Original file line number Diff line number Diff line change
@@ -1,48 +1,124 @@
# This file is a 'toolchain description file' for CMake.
# It teaches CMake about the Emscripten compiler, so that CMake can generate Unix Makefiles
# It teaches CMake about the Emscripten compiler, so that CMake can generate makefiles
# from CMakeLists.txt that invoke emcc.

# To use this toolchain file with CMake, invoke CMake with the following command line parameters
# cmake -DEMSCRIPTEN=1
# -DCMAKE_TOOLCHAIN_FILE=<EmscriptenRoot>/cmake/Platform/Emscripten.cmake
# -DCMAKE_MODULE_PATH=<EmscriptenRoot>/cmake
# cmake -DCMAKE_TOOLCHAIN_FILE=<EmscriptenRoot>/cmake/Platform/Emscripten.cmake
# -DCMAKE_BUILD_TYPE=<Debug|RelWithDebInfo|Release|MinSizeRel>
# -G "Unix Makefiles"
# -G "Unix Makefiles" (Linux and OSX)
# -G "MinGW Makefiles" (Windows)
# <path/to/CMakeLists.txt> # Note, pass in here ONLY the path to the file, not the filename 'CMakeLists.txt' itself.

# After that, build the generated Makefile with the command 'make'. On Windows, you may download and use 'mingw32-make' instead.

# the name of the target operating system
set(CMAKE_SYSTEM_NAME Emscripten)
# 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_VERSION 1)

set(CMAKE_CROSSCOMPILING TRUE)

# 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()

# 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)
if (EXISTS "${GUESS_EMSCRIPTEN_ROOT_PATH}/emranlib")
set(EMSCRIPTEN_ROOT_PATH "${GUESS_EMSCRIPTEN_ROOT_PATH}")
endif()
endif()

# If not found by above search, locate using the EMSCRIPTEN environment variable.
if ("${EMSCRIPTEN_ROOT_PATH}" STREQUAL "")
set(EMSCRIPTEN_ROOT_PATH "$ENV{EMSCRIPTEN}")
endif()

# Abort if not found.
if ("${EMSCRIPTEN_ROOT_PATH}" STREQUAL "")
set(CMAKE_FIND_ROOT_PATH "$ENV{EMSCRIPTEN}")
message(FATAL_ERROR "Could not locate the Emscripten compiler toolchain directory! Either set the EMSCRIPTEN environment variable, or pass -DEMSCRIPTEN_ROOT_PATH=xxx to CMake to explicitly specify the location of the compiler!")
endif()

# Normalize, convert Windows backslashes to forward slashes or CMake will crash.
get_filename_component(EMSCRIPTEN_ROOT_PATH "${EMSCRIPTEN_ROOT_PATH}" ABSOLUTE)

if ("${CMAKE_MODULE_PATH}" STREQUAL "")
set(CMAKE_MODULE_PATH "${EMSCRIPTEN_ROOT_PATH}/cmake")
endif()

set(CMAKE_FIND_ROOT_PATH "${EMSCRIPTEN_ROOT_PATH}/cmake")

if (CMAKE_HOST_WIN32)
set(EMCC_SUFFIX ".bat")
else()
set(CMAKE_FIND_ROOT_PATH "${EMSCRIPTEN_ROOT_PATH}")
set(EMCC_SUFFIX "")
endif()

# Specify the compilers to use for C and C++
if ("${CMAKE_C_COMPILER}" STREQUAL "")
set(CMAKE_C_COMPILER "emcc.bat")
set(CMAKE_CXX_COMPILER "em++.bat")
set(CMAKE_AR "emar.bat")
set(CMAKE_RANLIB "emranlib.bat")
set(CMAKE_C_COMPILER "${EMSCRIPTEN_ROOT_PATH}/emcc${EMCC_SUFFIX}")
endif()
if ("${CMAKE_CXX_COMPILER}" STREQUAL "")
set(CMAKE_CXX_COMPILER "${EMSCRIPTEN_ROOT_PATH}/em++${EMCC_SUFFIX}")
endif()

if ("${CMAKE_AR}" STREQUAL "")
set(CMAKE_AR "${EMSCRIPTEN_ROOT_PATH}/emar${EMCC_SUFFIX}")
endif()

if ("${CMAKE_RANLIB}" STREQUAL "")
set(CMAKE_RANLIB "${EMSCRIPTEN_ROOT_PATH}/emranlib${EMCC_SUFFIX}")
endif()

# Don't do compiler autodetection, since we are cross-compiling.
include(CMakeForceCompiler)
CMAKE_FORCE_C_COMPILER("${CMAKE_C_COMPILER}" Clang)
CMAKE_FORCE_CXX_COMPILER("${CMAKE_CXX_COMPILER}" Clang)

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

# We would prefer to specify a standard set of Clang+Emscripten-friendly common convention for suffix files, especially for CMake executable files,
# but if these are adjusted, ${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake will fail, since it depends on being able to compile output files with predefined names.
#SET(CMAKE_LINK_LIBRARY_SUFFIX "")
#SET(CMAKE_STATIC_LIBRARY_PREFIX "")
#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_FIND_LIBRARY_PREFIXES "")
#SET(CMAKE_FIND_LIBRARY_SUFFIXES ".bc")

SET(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1)
SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1)
SET(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1)
SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1)

set(CMAKE_C_RESPONSE_FILE_LINK_FLAG "@")
set(CMAKE_CXX_RESPONSE_FILE_LINK_FLAG "@")

# Specify the program to use when building static libraries. Force Emscripten-related command line options to clang.
set(CMAKE_CXX_ARCHIVE_CREATE "${CMAKE_CXX_COMPILER} -o <TARGET> -emit-llvm <LINK_FLAGS> <OBJECTS>")
set(CMAKE_C_ARCHIVE_CREATE "${CMAKE_C_COMPILER} -o <TARGET> -emit-llvm <LINK_FLAGS> <OBJECTS>")
set(CMAKE_CXX_ARCHIVE_CREATE "${CMAKE_CXX_COMPILER} ${CMAKE_START_TEMP_FILE} -o <TARGET> -emit-llvm <LINK_FLAGS> <OBJECTS>${CMAKE_END_TEMP_FILE}")
set(CMAKE_C_ARCHIVE_CREATE "${CMAKE_C_COMPILER} ${CMAKE_START_TEMP_FILE} -o <TARGET> -emit-llvm <LINK_FLAGS> <OBJECTS>${CMAKE_END_TEMP_FILE}")

# Set a global EMSCRIPTEN variable that can be used in client CMakeLists.txt to detect when building using Emscripten.
# There seems to be some kind of bug with CMake, so you might need to define this manually on the command line with "-DEMSCRIPTEN=1".
set(EMSCRIPTEN 1)

# We are cross-compiling, so unset the common CMake variables that represent the target platform. Leave UNIX define enabled, since Emscripten
# mimics a Linux environment.
SET(WIN32)
SET(APPLE)

set(CMAKE_C_SIZEOF_DATA_PTR 4)
set(CMAKE_CXX_SIZEOF_DATA_PTR 4)

set(CMAKE_C_FLAGS_RELEASE "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELEASE")
set(CMAKE_C_FLAGS_MINSIZEREL "-DNDEBUG" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_MINSIZEREL")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "" CACHE STRING "Emscripten-overridden CMAKE_C_FLAGS_RELWITHDEBINFO")
Expand All @@ -59,3 +135,7 @@ set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-over
set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_RELEASE")
set(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL")
set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "-O2" CACHE STRING "Emscripten-overridden CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO")

function(em_validate_asmjs_after_build target)
add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo Validating build output for asm.js... COMMAND "python" ARGS "${EMSCRIPTEN_ROOT_PATH}/tools/validate_asmjs.py" "$<TARGET_FILE:${target}>")
endfunction()
24 changes: 0 additions & 24 deletions cmake/Platform/Emscripten_unix.cmake

This file was deleted.

29 changes: 21 additions & 8 deletions emcc
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,9 @@ Options that are modified or new in %s include:
to hide these warnings and acknowledge that the
explicit use of absolute paths is intentional.
--proxy-to-worker Generates both html and js files. The main
program is in js, and the html proxies to/from it.
The target file, if specified (-o <target>), defines what will
be generated:
Expand Down Expand Up @@ -740,6 +743,7 @@ try:
save_bc = False
memory_init_file = False
use_preload_cache = False
proxy_to_worker = False

if use_cxx:
default_cxx_std = '-std=c++03' # Enforce a consistent C++ standard when compiling .cpp files, if user does not specify one on the cmdline.
Expand Down Expand Up @@ -903,6 +907,9 @@ try:
memory_init_file = int(newargs[i+1])
newargs[i] = ''
newargs[i+1] = ''
elif newargs[i] == '--proxy-to-worker':
proxy_to_worker = True
newargs[i] = ''
elif newargs[i].startswith(('-I', '-L')):
path_name = newargs[i][2:]
if not absolute_warning_shown and os.path.isabs(path_name):
Expand Down Expand Up @@ -1128,6 +1135,9 @@ try:
if shared.Settings.ASM_JS and shared.Settings.DLOPEN_SUPPORT:
assert shared.Settings.DISABLE_EXCEPTION_CATCHING, 'no exceptions support with dlopen in asm yet'

if proxy_to_worker:
shared.Settings.PROXY_TO_WORKER = 1

## Compile source code to bitcode

logging.debug('compiling to bitcode')
Expand All @@ -1144,7 +1154,7 @@ try:
args = newargs + ['-emit-llvm', '-c', input_file, '-o', output_file]
if input_file.endswith(CXX_SUFFIXES):
args += shared.EMSDK_CXX_OPTS
logging.debug("running:" + call + ' ' + ' '.join(args))
logging.debug("running: " + call + ' ' + ' '.join(args))
execute([call] + args) # let compiler frontend print directly, so colors are saved (PIPE kills that)
if not os.path.exists(output_file):
logging.error('compiler frontend failed to generate LLVM bitcode, halting')
Expand Down Expand Up @@ -1709,7 +1719,11 @@ try:
logging.debug('generating HTML')
shell = open(shell_path).read()
html = open(target, 'w')
if not Compression.on:
if proxy_to_worker:
html.write(shell.replace('{{{ SCRIPT_CODE }}}', open(shared.path_from_root('src', 'proxyClient.js')).read().replace('{{{ filename }}}', target_basename)))
js_target = unsuffixed(target) + '.js'
shutil.copyfile(final, js_target)
elif not Compression.on:
if debug_level >= 4:
match = re.match('.*?<script[^>]*>{{{ SCRIPT_CODE }}}</script>', shell,
re.DOTALL)
Expand Down Expand Up @@ -1783,13 +1797,12 @@ try:
html.close()
else:
if split_js_file:
from tools.split import split_javascript_file
split_javascript_file(final, unsuffixed(target), split_js_file)
from tools.split import split_javascript_file
split_javascript_file(final, unsuffixed(target), split_js_file)
else:
if debug_level >= 4: generate_source_map(target)

# copy final JS to output
shutil.move(final, target)
if debug_level >= 4: generate_source_map(target)
# copy final JS to output
shutil.move(final, target)

if DEBUG: logging.debug('total time: %.2f seconds' % (time.time() - start_time))

Expand Down
16 changes: 12 additions & 4 deletions emscripten.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ def scan(ll, settings):
MIN_CHUNK_SIZE = 1024*1024
MAX_CHUNK_SIZE = float(os.environ.get('EMSCRIPT_MAX_CHUNK_SIZE') or 'inf') # configuring this is just for debugging purposes

STDERR_FILE = os.environ.get('EMCC_STDERR_FILE')
if STDERR_FILE:
STDERR_FILE = os.path.abspath(STDERR_FILE)
print >> sys.stderr, 'logging stderr in js compiler phase into %s' % STDERR_FILE
STDERR_FILE = open(STDERR_FILE, 'w')

def process_funcs((i, funcs, meta, settings_file, compiler, forwarded_file, libraries, compiler_engine, temp_files, DEBUG)):
try:
funcs_file = temp_files.get('.func_%d.ll' % i).name
Expand All @@ -57,6 +63,7 @@ def process_funcs((i, funcs, meta, settings_file, compiler, forwarded_file, libr
engine=compiler_engine,
args=[settings_file, funcs_file, 'funcs', forwarded_file] + libraries,
stdout=subprocess.PIPE,
stderr=STDERR_FILE,
cwd=path_from_root('src'))
except KeyboardInterrupt:
# Python 2.7 seems to lock up when a child process throws KeyboardInterrupt
Expand Down Expand Up @@ -179,7 +186,7 @@ def save_settings():
if out and DEBUG: print >> sys.stderr, ' loading pre from jcache'
if not out:
open(pre_file, 'w').write(pre_input)
out = jsrun.run_js(compiler, compiler_engine, [settings_file, pre_file, 'pre'] + libraries, stdout=subprocess.PIPE,
out = jsrun.run_js(compiler, compiler_engine, [settings_file, pre_file, 'pre'] + libraries, stdout=subprocess.PIPE, stderr=STDERR_FILE,
cwd=path_from_root('src'))
assert '//FORWARDED_DATA:' in out, 'Did not receive forwarded data in pre output - process failed?'
if jcache:
Expand Down Expand Up @@ -287,6 +294,7 @@ def load_from_cache(chunk):
exported_implemented_functions = set()
for func_js, curr_forwarded_data in outputs:
curr_forwarded_json = json.loads(curr_forwarded_data)
forwarded_json['Types']['hasInlineJS'] = forwarded_json['Types']['hasInlineJS'] or curr_forwarded_json['Types']['hasInlineJS']
forwarded_json['Types']['preciseI64MathUsed'] = forwarded_json['Types']['preciseI64MathUsed'] or curr_forwarded_json['Types']['preciseI64MathUsed']
for key, value in curr_forwarded_json['Functions']['blockAddresses'].iteritems():
forwarded_json['Functions']['blockAddresses'][key] = value
Expand Down Expand Up @@ -376,7 +384,7 @@ def handle_post_sets(m):
if DEBUG: t = time.time()
post_file = temp_files.get('.post.ll').name
open(post_file, 'w').write('\n') # no input, just processing of forwarded data
out = jsrun.run_js(compiler, compiler_engine, [settings_file, post_file, 'post', forwarded_file] + libraries, stdout=subprocess.PIPE,
out = jsrun.run_js(compiler, compiler_engine, [settings_file, post_file, 'post', forwarded_file] + libraries, stdout=subprocess.PIPE, stderr=STDERR_FILE,
cwd=path_from_root('src'))
post, last_forwarded_data = out.split('//FORWARDED_DATA:') # if this fails, perhaps the process failed prior to printing forwarded data?
last_forwarded_json = json.loads(last_forwarded_data)
Expand Down Expand Up @@ -543,7 +551,7 @@ def math_fix(g):
}
// EMSCRIPTEN_START_ASM
var asm = (function(global, env, buffer) {
'use asm';
%s
var HEAP8 = new global.Int8Array(buffer);
var HEAP16 = new global.Int16Array(buffer);
var HEAP32 = new global.Int32Array(buffer);
Expand All @@ -552,7 +560,7 @@ def math_fix(g):
var HEAPU32 = new global.Uint32Array(buffer);
var HEAPF32 = new global.Float32Array(buffer);
var HEAPF64 = new global.Float64Array(buffer);
''' % (asm_setup,) + '\n' + asm_global_vars + '''
''' % (asm_setup, "'use asm';" if not forwarded_json['Types']['hasInlineJS'] and not settings['SIDE_MODULE'] else "'almost asm';") + '\n' + asm_global_vars + '''
var __THREW__ = 0;
var threwValue = 0;
var setjmpId = 0;
Expand Down
4 changes: 3 additions & 1 deletion src/intertyper.js
Original file line number Diff line number Diff line change
Expand Up @@ -708,13 +708,15 @@ function intertyper(data, sidePass, baseLineNums) {
item.ident = eatLLVMIdent(tokensLeft);
if (item.ident == 'asm') {
if (ASM_JS) {
warnOnce('inline JS in asm.js mode can cause the code to no longer fall in the asm.js subset of JavaScript');
Types.hasInlineJS = true;
warnOnce('inline JavaScript (asm, EM_ASM) will cause the code to no longer fall in the asm.js subset of JavaScript, which can reduce performance - consider using emscripten_run_script');
}
assert(TARGET_LE32, 'inline js is only supported in le32');
// Inline assembly is just JavaScript that we paste into the code
item.intertype = 'value';
if (tokensLeft[0].text == 'sideeffect') tokensLeft.splice(0, 1);
item.ident = tokensLeft[0].text.substr(1, tokensLeft[0].text.length-2) || ';'; // use ; for empty inline assembly
assert((item.tokens[5].text.match(/=/g) || []).length <= 1, 'we only support at most 1 exported variable from inline js: ' + item.ident);
var i = 0;
var params = [], args = [];
splitTokenList(tokensLeft[3].item.tokens).map(function(element) {
Expand Down
9 changes: 7 additions & 2 deletions src/jsifier.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,11 +324,13 @@ function JSify(data, functionsOnly, givenFunctions) {
assert(typeof constant === 'object');//, [typeof constant, JSON.stringify(constant), item.external]);

// This is a flattened object. We need to find its idents, so they can be assigned to later
var structTypes = null;
constant.forEach(function(value, i) {
if (needsPostSet(value)) { // ident, or expression containing an ident
if (!structTypes) structTypes = generateStructTypes(item.type);
ret.push({
intertype: 'GlobalVariablePostSet',
JS: makeSetValue(makeGlobalUse(item.ident), i, value, 'i32', false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors
JS: makeSetValue(makeGlobalUse(item.ident), i, value, structTypes[i], false, true) + ';' // ignore=true, since e.g. rtti and statics cause lots of safe_heap errors
});
constant[i] = '0';
}
Expand Down Expand Up @@ -1831,7 +1833,7 @@ function JSify(data, functionsOnly, givenFunctions) {
}

if (CORRUPTION_CHECK) {
assert(!ASM_JS); // cannot monkeypatch asm!
assert(!ASM_JS, 'corruption checker is not compatible with asm.js');
print(processMacros(read('corruptionCheck.js')));
}
if (HEADLESS) {
Expand All @@ -1841,6 +1843,9 @@ function JSify(data, functionsOnly, givenFunctions) {
print(read('headless.js').replace("'%s'", "'http://emscripten.org'").replace("'?%s'", "''").replace("'?%s'", "'/'").replace('%s,', 'null,').replace('%d', '0'));
print('}');
}
if (PROXY_TO_WORKER) {
print(read('proxyWorker.js'));
}
if (RUNTIME_TYPE_INFO) {
Types.cleanForRuntime();
print('Runtime.typeInfo = ' + JSON.stringify(Types.types));
Expand Down
10 changes: 9 additions & 1 deletion src/library_browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,15 @@ mergeInto(LibraryManager.library, {
Module['preMainLoop']();
}

Runtime.dynCall('v', func);
try {
Runtime.dynCall('v', func);
} catch (e) {
if (e instanceof ExitStatus) {
return;
} else {
throw e;
}
}

if (Module['postMainLoop']) {
Module['postMainLoop']();
Expand Down
Loading

0 comments on commit 6010666

Please sign in to comment.