diff --git a/AUTHORS b/AUTHORS index 266badc3fd8ff..f6850afb7d9d5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -209,4 +209,5 @@ a license to everyone to use it as detailed in LICENSE.) * Louis Lagrange * Ying-Ruei Liang * Stuart Geipel +* Yeonjun Lim diff --git a/cmake/Modules/Platform/Emscripten.cmake b/cmake/Modules/Platform/Emscripten.cmake index 01b75b23ce392..19f9438f3ef14 100644 --- a/cmake/Modules/Platform/Emscripten.cmake +++ b/cmake/Modules/Platform/Emscripten.cmake @@ -186,18 +186,11 @@ set(link_js_counter 1) # Internal function: Do not call from user CMakeLists.txt files. Use one of em_link_js_library()/em_link_pre_js()/em_link_post_js() instead. function(em_add_tracked_link_flag target flagname) - get_target_property(props ${target} LINK_FLAGS) - if(NOT props) - set(props "") - endif() # User can input list of JS files either as a single list, or as variable arguments to this function, so iterate over varargs, and treat each # item in varargs as a list itself, to support both syntax forms. foreach(jsFileList ${ARGN}) foreach(jsfile ${jsFileList}) - # Add link command to the given JS file. - set(props "${props} ${flagname} \"${jsfile}\"") - # If the user edits the JS file, we want to relink the emscripten application, but unfortunately it is not possible to make a link step # depend directly on a source file. Instead, we must make a dummy no-op build target on that source file, and make the project depend on # that target. @@ -215,10 +208,16 @@ function(em_add_tracked_link_flag target flagname) add_custom_command(OUTPUT ${dummy_c_name} COMMAND ${CMAKE_COMMAND} -E touch ${dummy_c_name} DEPENDS ${jsfile}) target_link_libraries(${target} ${dummy_lib_name}) + # Link the js-library to the target + # When a linked library starts with a "-" cmake will just add it to the linker command line as it is. + # The advantage of doing it this way is that the js-library will also be automatically linked to targets + # that depend on this target. + get_filename_component(js_file_absolute_path "${jsfile}" ABSOLUTE ) + target_link_libraries(${target} "${flagname} \"${js_file_absolute_path}\"") + math(EXPR link_js_counter "${link_js_counter} + 1") endforeach() endforeach() - set_target_properties(${target} PROPERTIES LINK_FLAGS "${props}") endfunction() # This function links a (list of ) .js library file(s) to the given CMake project. diff --git a/emcc b/emcc index 60534fb75d442..b6245ce6c81cc 100755 --- a/emcc +++ b/emcc @@ -446,8 +446,11 @@ try: if newargs[i] == '-Wwarn-absolute-paths': newargs[i] = '' absolute_warning_shown = False - # Scan for individual -l/-L/-I arguments and concatenate the next arg on if there is no suffix - if newargs[i] in ['-l', '-L', '-I']: + elif newargs[i] == '-Wno-warn-absolute-paths': + newargs[i] = '' + absolute_warning_shown = True + elif newargs[i] in ['-l', '-L', '-I']: + # Scan for individual -l/-L/-I arguments and concatenate the next arg on if there is no suffix newargs[i] += newargs[i+1] newargs[i+1] = '' diff --git a/emscripten-version.txt b/emscripten-version.txt index 731351294780e..3a4a1b8deeebb 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1,2 +1,2 @@ -1.35.2 +"1.35.3" diff --git a/site/source/conf.py b/site/source/conf.py index 340087e8c4cb2..8fe15034c7667 100644 --- a/site/source/conf.py +++ b/site/source/conf.py @@ -90,7 +90,7 @@ # built documents. # -emscripten_version = open(os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'emscripten-version.txt'))).read().strip() +emscripten_version = open(os.path.abspath(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'emscripten-version.txt'))).read().strip().replace('"', '') # The short X.Y version. version = emscripten_version[:emscripten_version.rindex('.')] diff --git a/site/source/docs/api_reference/preamble.js.rst b/site/source/docs/api_reference/preamble.js.rst index 654027bc464af..fe1d58fd8a43a 100644 --- a/site/source/docs/api_reference/preamble.js.rst +++ b/site/source/docs/api_reference/preamble.js.rst @@ -359,12 +359,7 @@ The :ref:`emscripten-memory-model` uses a typed array buffer (``ArrayBuffer``) t .. js:data:: HEAPU8 - View for 32-bit unsigned memory. - - -.. js:data:: HEAPU8 - - View for 32-bit unsigned memory. + View for 8-bit unsigned memory. .. js:data:: HEAPU16 diff --git a/site/source/docs/porting/Debugging.rst b/site/source/docs/porting/Debugging.rst index 31f3c22ab4a5b..f6b4f24710fa1 100644 --- a/site/source/docs/porting/Debugging.rst +++ b/site/source/docs/porting/Debugging.rst @@ -105,9 +105,9 @@ Manual print debugging You can also manually instrument the source code with ``printf()`` statements, then compile and run the code to investigate issues. -If you have a good idea of the problem line you can add ``print(new Error().stack)`` to the JavaScript to get a stack trace at that point. Also available is :js:func:`stackTrace`, which emits a stack trace and tries to demangle C++ function names. Debug printouts can even execute arbitrary JavaScript. +If you have a good idea of the problem line you can add ``print(new Error().stack)`` to the JavaScript to get a stack trace at that point. Also available is :js:func:`stackTrace`, which emits a stack trace and tries to demangle C++ function names (if you don't want or need C++ demangling, you can call :js:func:`jsStackTrace`). -For example: +Debug printouts can even execute arbitrary JavaScript. For example: .. code-block:: cpp diff --git a/src/library_nodefs.js b/src/library_nodefs.js index 502c5dbef83ff..28d1c5f0692fe 100644 --- a/src/library_nodefs.js +++ b/src/library_nodefs.js @@ -74,6 +74,7 @@ mergeInto(LibraryManager.library, { }, flagsToPermissionString: function(flags) { flags &= ~0100000 /*O_LARGEFILE*/; // Ignore this flag from musl, otherwise node.js fails to open the file. + flags &= ~02000000 /*O_CLOEXEC*/; // Some applications may pass it; it makes no sense for a single process. if (flags in NODEFS.flagsToPermissionStringMap) { return NODEFS.flagsToPermissionStringMap[flags]; } else { diff --git a/tests/cmake/cpp_lib/CMakeLists.txt b/tests/cmake/cpp_lib/CMakeLists.txt new file mode 100644 index 0000000000000..94a89f3f727a3 --- /dev/null +++ b/tests/cmake/cpp_lib/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 2.8) + +project(cpp_library) + +SET(CPP_LIBRARY_TYPE "SHARED" CACHE STRING "Library type to build") +SET_PROPERTY(CACHE CPP_LIBRARY_TYPE PROPERTY STRINGS STATIC SHARED) + +add_library( cpp_lib ${CPP_LIBRARY_TYPE} lib.cpp) +em_link_js_library(cpp_lib "lib.js") diff --git a/tests/cmake/cpp_lib/lib.cpp b/tests/cmake/cpp_lib/lib.cpp new file mode 100644 index 0000000000000..bc801037bd74b --- /dev/null +++ b/tests/cmake/cpp_lib/lib.cpp @@ -0,0 +1,8 @@ +extern "C" { + int js_library_function(); +} + +int cpp_library_function() +{ + return js_library_function(); +} diff --git a/tests/cmake/cpp_lib/lib.js b/tests/cmake/cpp_lib/lib.js new file mode 100644 index 0000000000000..4d14c97d4f4a9 --- /dev/null +++ b/tests/cmake/cpp_lib/lib.js @@ -0,0 +1,6 @@ +mergeInto(LibraryManager.library, { + js_library_function: function() { + return 0; + } +} +); diff --git a/tests/cmake/target_html/CMakeLists.txt b/tests/cmake/target_html/CMakeLists.txt index 5a84344bff31c..a4a8c9ed191ba 100644 --- a/tests/cmake/target_html/CMakeLists.txt +++ b/tests/cmake/target_html/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 2.8) project(hello_world_gles) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../cpp_lib ${CMAKE_CURRENT_BINARY_DIR}/cpp_lib) + file(GLOB sourceFiles ../../hello_world_gles.c) if (CMAKE_BUILD_TYPE STREQUAL Debug) @@ -84,6 +86,7 @@ if (NOT HAVE_MATH_H) endif() add_executable(hello_world_gles ${sourceFiles}) +target_link_libraries(hello_world_gles cpp_lib) set_target_properties(hello_world_gles PROPERTIES LINK_FLAGS "${linkFlags}") # Validating asm.js requires SpiderMonkey JS VM - detect its presence via the SPIDERMONKEY environment variable. diff --git a/tests/cmake/target_js/CMakeLists.txt b/tests/cmake/target_js/CMakeLists.txt index d2ea2c104f2b6..a5c0b1273a2a0 100644 --- a/tests/cmake/target_js/CMakeLists.txt +++ b/tests/cmake/target_js/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 2.8) project(test_cmake) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../cpp_lib ${CMAKE_CURRENT_BINARY_DIR}/cpp_lib) + file(GLOB sourceFiles main.cpp) file(GLOB preJsFiles pre*.js) @@ -83,6 +85,7 @@ if(${CMAKE_VERSION} VERSION_GREATER 3.2.20150502) endif() add_executable(test_cmake ${sourceFiles}) +target_link_libraries( test_cmake cpp_lib) # GOTCHA: If your project has custom link flags, these must be set *before* calling any of the em_link_xxx functions! set_target_properties(test_cmake PROPERTIES LINK_FLAGS "${linkFlags}") diff --git a/tests/cmake/target_js/main.cpp b/tests/cmake/target_js/main.cpp index 4b61dbf76a7d0..5aff9d20b591e 100644 --- a/tests/cmake/target_js/main.cpp +++ b/tests/cmake/target_js/main.cpp @@ -3,8 +3,11 @@ extern "C" { void lib_function2(); } +int cpp_library_function(); + int main() { lib_function(); lib_function2(); + cpp_library_function(); } diff --git a/tests/cmake/target_library/CMakeLists.txt b/tests/cmake/target_library/CMakeLists.txt index c70231922cdea..4aee575326f20 100644 --- a/tests/cmake/target_library/CMakeLists.txt +++ b/tests/cmake/target_library/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 2.8) project(test_cmake) +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../cpp_lib ${CMAKE_CURRENT_BINARY_DIR}/cpp_lib) + option(BUILD_SHARED_LIBS "Build with shared libraries." OFF) if (CMAKE_BUILD_TYPE STREQUAL Debug) @@ -22,6 +24,7 @@ foreach(i RANGE ${MAX_SRC_FILE_INDEX}) endforeach() add_library(test_cmake ${TEST_SOURCES}) +target_link_libraries(test_cmake cpp_lib) if (WIN32) message(FATAL_ERROR "WIN32 should not be defined when cross-compiling!") diff --git a/tests/fs/test_nodefs_cloexec.c b/tests/fs/test_nodefs_cloexec.c new file mode 100644 index 0000000000000..0785ac9550544 --- /dev/null +++ b/tests/fs/test_nodefs_cloexec.c @@ -0,0 +1,17 @@ +#include +#include +#include +#include +#include + +int main(void) +{ + EM_ASM( + FS.mkdir('/working'); + FS.mount(NODEFS, {root: '.'}, '/working'); + FS.close(FS.open('/working/test.txt', 'w')); + ); + assert(open("/working/test.txt", O_RDONLY | O_CLOEXEC) != -1); + printf("success\n"); + return 0; +} diff --git a/tests/test_core.py b/tests/test_core.py index 5496e85b54cd3..e7af34041ea7b 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5180,6 +5180,10 @@ def test_fs_nodefs_rw(self): self.emcc_args += ['--closure', '1'] self.do_run(src, 'success', force_c=True, js_engines=[NODE_JS]) + def test_fs_nodefs_cloexec(self): + src = open(path_from_root('tests', 'fs', 'test_nodefs_cloexec.c'), 'r').read() + self.do_run(src, 'success', force_c=True, js_engines=[NODE_JS]) + def test_fs_trackingdelegate(self): src = path_from_root('tests', 'fs', 'test_trackingdelegate.c') out = path_from_root('tests', 'fs', 'test_trackingdelegate.out') diff --git a/tests/test_other.py b/tests/test_other.py index 21ae0307b877f..b1247b725639d 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -21,8 +21,10 @@ def test_emcc(self): # -v, without input files output = Popen([PYTHON, compiler, '-v'], stdout=PIPE, stderr=PIPE).communicate() - self.assertContained('''clang version''', output[1].replace('\r', ''), output[1].replace('\r', '')) + self.assertContained('''clang version %s.0 ''' % '.'.join(map(str, EXPECTED_LLVM_VERSION)), output[1].replace('\r', ''), output[1].replace('\r', '')) self.assertContained('''GNU''', output[0]) + self.assertNotContained('this is dangerous', output[0]) + self.assertNotContained('this is dangerous', output[1]) # --help output = Popen([PYTHON, compiler, '--help'], stdout=PIPE, stderr=PIPE).communicate() @@ -415,60 +417,66 @@ def check_makefile(configuration, dirname): # CMake can be invoked in two ways, using 'emconfigure cmake', or by directly running 'cmake'. # Test both methods. for invoke_method in ['cmake', 'emconfigure']: - - # Create a temp workspace folder - cmakelistsdir = path_from_root('tests', 'cmake', cmake_cases[i]) - tempdirname = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=TEMP_DIR) - try: - os.chdir(tempdirname) - - # Run Cmake - if invoke_method == 'cmake': - # Test invoking cmake directly. - cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+path_from_root('cmake', 'Modules', 'Platform', 'Emscripten.cmake'), - '-DCMAKE_CROSSCOMPILING_EMULATOR="' + ' '.join(NODE_JS) + '"', - '-DCMAKE_BUILD_TYPE=' + configuration, cmake_arguments[i], '-G', generator, cmakelistsdir] - env = tools.shared.Building.remove_sh_exe_from_path(os.environ) - else: - # Test invoking via 'emconfigure cmake' - cmd = [emconfigure, 'cmake', '-DCMAKE_BUILD_TYPE=' + configuration, cmake_arguments[i], '-G', generator, cmakelistsdir] - env = os.environ.copy() - - print str(cmd) - ret = Popen(cmd, stdout=None if EM_BUILD_VERBOSE_LEVEL >= 2 else PIPE, stderr=None if EM_BUILD_VERBOSE_LEVEL >= 1 else PIPE, env=env).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. - if len(ret) > 1 and ret[1] != None and 'error' in ret[1].lower(): - logging.error('Failed command: ' + ' '.join(cmd)) - logging.error('Result:\n' + ret[1]) - raise Exception('cmake call failed!') - - if prebuild: - prebuild(configuration, tempdirname) - - # Build - cmd = make - if EM_BUILD_VERBOSE_LEVEL >= 3 and 'Ninja' not in generator: - cmd += ['VERBOSE=1'] - ret = Popen(cmd, stdout=None if EM_BUILD_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. - if len(ret) > 0 and ret[0] != None and 'error' in ret[0].lower() and not '0 error(s)' in ret[0].lower(): - logging.error('Failed command: ' + ' '.join(cmd)) - logging.error('Result:\n' + ret[0]) - raise Exception('make failed!') - assert os.path.exists(tempdirname + '/' + cmake_outputs[i]), 'Building a cmake-generated Makefile failed to produce an output file %s!' % tempdirname + '/' + cmake_outputs[i] - - if postbuild: - postbuild(configuration, tempdirname) - - # Run through node, if CMake produced a .js file. - if cmake_outputs[i].endswith('.js'): - ret = Popen(NODE_JS + [tempdirname + '/' + cmake_outputs[i]], stdout=PIPE).communicate()[0] - self.assertTextDataIdentical(open(cmakelistsdir + '/out.txt', 'r').read().strip(), ret.strip()) - finally: - os.chdir(path_from_root('tests')) # Move away from the directory we are about to remove. - shutil.rmtree(tempdirname) + for cpp_lib_type in ['STATIC', 'SHARED']: + # Create a temp workspace folder + cmakelistsdir = path_from_root('tests', 'cmake', cmake_cases[i]) + tempdirname = tempfile.mkdtemp(prefix='emscripten_test_' + self.__class__.__name__ + '_', dir=TEMP_DIR) + try: + os.chdir(tempdirname) + + # Run Cmake + if invoke_method == 'cmake': + # Test invoking cmake directly. + cmd = ['cmake', '-DCMAKE_TOOLCHAIN_FILE='+path_from_root('cmake', 'Modules', 'Platform', 'Emscripten.cmake'), + '-DCPP_LIBRARY_TYPE='+cpp_lib_type, + '-DCMAKE_CROSSCOMPILING_EMULATOR="' + ' '.join(NODE_JS) + '"', + '-DCMAKE_BUILD_TYPE=' + configuration, cmake_arguments[i], '-G', generator, cmakelistsdir] + env = tools.shared.Building.remove_sh_exe_from_path(os.environ) + else: + # Test invoking via 'emconfigure cmake' + cmd = [emconfigure, 'cmake', '-DCMAKE_BUILD_TYPE=' + configuration, cmake_arguments[i], '-G', generator, cmakelistsdir] + env = os.environ.copy() + + print str(cmd) + ret = Popen(cmd, stdout=None if EM_BUILD_VERBOSE_LEVEL >= 2 else PIPE, stderr=None if EM_BUILD_VERBOSE_LEVEL >= 1 else PIPE, env=env).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. + if len(ret) > 1 and ret[1] != None and 'error' in ret[1].lower(): + logging.error('Failed command: ' + ' '.join(cmd)) + logging.error('Result:\n' + ret[1]) + raise Exception('cmake call failed!') + + if prebuild: + prebuild(configuration, tempdirname) + + # Build + cmd = make + if EM_BUILD_VERBOSE_LEVEL >= 3 and 'Ninja' not in generator: + cmd += ['VERBOSE=1'] + ret = Popen(cmd, stdout=None if EM_BUILD_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. + if len(ret) > 0 and ret[0] != None and 'error' in ret[0].lower() and not '0 error(s)' in ret[0].lower(): + logging.error('Failed command: ' + ' '.join(cmd)) + logging.error('Result:\n' + ret[0]) + raise Exception('make failed!') + assert os.path.exists(tempdirname + '/' + cmake_outputs[i]), 'Building a cmake-generated Makefile failed to produce an output file %s!' % tempdirname + '/' + cmake_outputs[i] + + if postbuild: + postbuild(configuration, tempdirname) + + # Run through node, if CMake produced a .js file. + if cmake_outputs[i].endswith('.js'): + ret = Popen(NODE_JS + [tempdirname + '/' + cmake_outputs[i]], stdout=PIPE).communicate()[0] + self.assertTextDataIdentical(open(cmakelistsdir + '/out.txt', 'r').read().strip(), ret.strip()) + finally: + os.chdir(path_from_root('tests')) # Move away from the directory we are about to remove. + #there is a race condition under windows here causing an exception in shutil.rmtree because the directory is not empty yet + try: + shutil.rmtree(tempdirname) + except: + time.sleep(0.1) + shutil.rmtree(tempdirname) def test_failure_error_code(self): for compiler in [EMCC, EMXX]: @@ -1032,11 +1040,18 @@ def test_abspaths(self): (['-L/usr/something', '-Wwarn-absolute-paths'], True), (['-I/usr/something'], False), (['-L/usr/something'], False), + (['-I/usr/something', '-Wno-warn-absolute-paths'], False), + (['-L/usr/something', '-Wno-warn-absolute-paths'], False), (['-Isubdir/something', '-Wwarn-absolute-paths'], False), (['-Lsubdir/something', '-Wwarn-absolute-paths'], False), ([], False)]: - err = Popen([PYTHON, EMCC, 'main.c'] + args, stderr=PIPE).communicate()[1] + print args, expected + proc = Popen([PYTHON, EMCC, 'main.c'] + args, stderr=PIPE) + err = proc.communicate()[1] + assert proc.returncode is 0 assert ('encountered. If this is to a local system header/library, it may cause problems (local system files make sense for compiling natively on your system, but not necessarily to JavaScript)' in err) == expected, err + if not expected: + assert err == '', err def test_local_link(self): # Linking a local library directly, like /usr/lib/libsomething.so, cannot work of course since it diff --git a/tests/test_sanity.py b/tests/test_sanity.py index 14c3e7ecd2887..ab44a45f25a58 100644 --- a/tests/test_sanity.py +++ b/tests/test_sanity.py @@ -241,7 +241,8 @@ def test_llvm_fastcomp(self): try_delete(SANITY_FILE) output = self.check_working(EMCC, 'did not see a source tree above or next to the LLVM root directory') - VERSION_WARNING = 'Emscripten, llvm and clang versions do not match, this is dangerous' + VERSION_WARNING = 'Emscripten, llvm and clang repo versions do not match, this is dangerous' + BUILD_VERSION_WARNING = 'Emscripten, llvm and clang build versions do not match, this is dangerous' # add version number open(path_from_root('tests', 'fake', 'emscripten-version.txt'), 'w').write('waka') @@ -263,6 +264,23 @@ def test_llvm_fastcomp(self): try_delete(SANITY_FILE) output = self.check_working(EMCC, VERSION_WARNING) + # restore clang version to ok, and fake the *build* versions + open(path_from_root('tests', 'fake', 'tools', 'clang', 'emscripten-version.txt'), 'w').write(EMSCRIPTEN_VERSION) + output = self.check_working(EMCC) + assert VERSION_WARNING not in output + fake = '#!/bin/sh\necho "clang version %s (blah blah) (emscripten waka : waka)"\necho "..."\n' % '.'.join(map(str, EXPECTED_LLVM_VERSION)) + open(path_from_root('tests', 'fake', 'bin', 'clang'), 'w').write(fake) + open(path_from_root('tests', 'fake', 'bin', 'clang++'), 'w').write(fake) + os.chmod(path_from_root('tests', 'fake', 'bin', 'clang'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) + os.chmod(path_from_root('tests', 'fake', 'bin', 'clang++'), stat.S_IREAD | stat.S_IWRITE | stat.S_IEXEC) + try_delete(SANITY_FILE) + output = self.check_working(EMCC, BUILD_VERSION_WARNING) + assert VERSION_WARNING not in output + # break clang repo version again, see it hides the build warning + open(path_from_root('tests', 'fake', 'tools', 'clang', 'emscripten-version.txt'), 'w').write('waka') + output = self.check_working(EMCC, VERSION_WARNING) + assert BUILD_VERSION_WARNING not in output + restore() self.check_working([EMCC, 'tests/hello_world.cpp', '-s', 'ASM_JS=0'], '''Compiler settings are incompatible with fastcomp. You can fall back to the older compiler core, although that is not recommended''') diff --git a/tools/shared.py b/tools/shared.py index 76c2737f461c7..e11e77b8bf002 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -370,20 +370,32 @@ def check_fastcomp(): logging.critical('you can fall back to the older (pre-fastcomp) compiler core, although that is not recommended, see http://kripken.github.io/emscripten-site/docs/building_from_source/LLVM-Backend.html') return False + # check repo versions d = get_fastcomp_src_dir() + shown_repo_version_error = False if d is not None: - llvm_version = open(os.path.join(d, 'emscripten-version.txt')).read().strip() + llvm_version = get_emscripten_version(os.path.join(d, 'emscripten-version.txt')) if os.path.exists(os.path.join(d, 'tools', 'clang', 'emscripten-version.txt')): - clang_version = open(os.path.join(d, 'tools', 'clang', 'emscripten-version.txt')).read().strip() + clang_version = get_emscripten_version(os.path.join(d, 'tools', 'clang', 'emscripten-version.txt')) elif os.path.exists(os.path.join(d, 'tools', 'clang')): clang_version = '?' # Looks like the LLVM compiler tree has an old checkout from the time before it contained a version.txt: Should update! else: clang_version = llvm_version # This LLVM compiler tree does not have a tools/clang, so it's probably an out-of-source build directory. No need for separate versioning. if EMSCRIPTEN_VERSION != llvm_version or EMSCRIPTEN_VERSION != clang_version: - logging.error('Emscripten, llvm and clang versions do not match, this is dangerous (%s, %s, %s)', EMSCRIPTEN_VERSION, llvm_version, clang_version) + logging.error('Emscripten, llvm and clang repo versions do not match, this is dangerous (%s, %s, %s)', EMSCRIPTEN_VERSION, llvm_version, clang_version) logging.error('Make sure to use the same branch in each repo, and to be up-to-date on each. See http://kripken.github.io/emscripten-site/docs/building_from_source/LLVM-Backend.html') + shown_repo_version_error = True else: logging.warning('did not see a source tree above or next to the LLVM root directory (guessing based on directory of %s), could not verify version numbers match' % LLVM_COMPILER) + + # check build versions. don't show it if the repos are wrong, user should fix that first + if not shown_repo_version_error: + clang_v = Popen([CLANG, '--version'], stdout=PIPE).communicate()[0] + llvm_build_version, clang_build_version = clang_v.split('(emscripten ')[1].split(')')[0].split(' : ') + if EMSCRIPTEN_VERSION != llvm_build_version or EMSCRIPTEN_VERSION != clang_build_version: + logging.error('Emscripten, llvm and clang build versions do not match, this is dangerous (%s, %s, %s)', EMSCRIPTEN_VERSION, llvm_build_version, clang_build_version) + logging.error('Make sure to rebuild llvm and clang after updating repos') + return True except Exception, e: logging.warning('could not check fastcomp: %s' % str(e)) @@ -428,6 +440,9 @@ def find_temp_directory(): else: return '/tmp' +def get_emscripten_version(path): + return open(path).read().strip().replace('"', '') + # Check that basic stuff we need (a JS engine to compile, Node.js, and Clang and LLVM) # exists. # The test runner always does this check (through |force|). emcc does this less frequently, @@ -436,7 +451,7 @@ def find_temp_directory(): # We also re-check sanity and clear the cache when the version changes try: - EMSCRIPTEN_VERSION = open(path_from_root('emscripten-version.txt')).read().strip() + EMSCRIPTEN_VERSION = get_emscripten_version(path_from_root('emscripten-version.txt')) try: parts = map(int, EMSCRIPTEN_VERSION.split('.')) EMSCRIPTEN_VERSION_MAJOR = parts[0]