summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xemcc70
-rw-r--r--tests/test_core.py2
-rw-r--r--tests/test_other.py97
-rw-r--r--tools/js-optimizer.js3
4 files changed, 92 insertions, 80 deletions
diff --git a/emcc b/emcc
index cbbbb747..111093e2 100755
--- a/emcc
+++ b/emcc
@@ -53,14 +53,17 @@ from tools import shared, jsrun
from tools.shared import Compression, execute, suffix, unsuffixed, unsuffixed_basename, WINDOWS
from tools.response_file import read_response_file
-C_SUFFIXES = ('.c', '.C')
-CXX_SUFFIXES = ('.cpp', '.cxx', '.cc', '.CPP', '.CXX', '.CC')
-SOURCE_SUFFIXES = C_SUFFIXES + CXX_SUFFIXES + ('.m', '.mm')
-BITCODE_SUFFIXES = ('.bc', '.o', '.obj')
-DYNAMICLIB_SUFFIXES = ('.dylib', '.so', '.dll')
-STATICLIB_SUFFIXES = ('.a',)
-ASSEMBLY_SUFFIXES = ('.ll',)
+# endings = dot + a suffix, safe to test by filename.endswith(endings)
+C_ENDINGS = ('.c', '.C')
+CXX_ENDINGS = ('.cpp', '.cxx', '.cc', '.CPP', '.CXX', '.CC')
+SOURCE_ENDINGS = C_ENDINGS + CXX_ENDINGS + ('.m', '.mm')
+BITCODE_ENDINGS = ('.bc', '.o', '.obj')
+DYNAMICLIB_ENDINGS = ('.dylib', '.so', '.dll')
+STATICLIB_ENDINGS = ('.a',)
+ASSEMBLY_ENDINGS = ('.ll',)
+
LIB_PREFIXES = ('', 'lib')
+
JS_CONTAINING_SUFFIXES = ('js', 'html')
# Mapping of emcc opt levels to llvm opt levels. We use llvm opt level 3 in emcc opt
@@ -762,9 +765,13 @@ def in_temp(name):
def filename_type_suffix(filename):
for i in reversed(filename.split('.')[1:]):
if not i.isdigit():
- return '.' + i
+ return i
return ''
+def filename_type_ending(filename):
+ suffix = filename_type_suffix(filename)
+ return '' if not suffix else ('.' + suffix)
+
try:
call = CXX if use_cxx else CC
@@ -1053,7 +1060,7 @@ try:
prev = newargs[i-1]
if prev in ['-MT', '-MF', '-MQ', '-D', '-U', '-o', '-x', '-Xpreprocessor', '-include', '-imacros', '-idirafter', '-iprefix', '-iwithprefix', '-iwithprefixbefore', '-isysroot', '-imultilib', '-A', '-isystem', '-iquote', '-install_name', '-compatibility_version', '-current_version', '-I', '-L']: continue # ignore this gcc-style argument
- if (os.path.islink(arg) and os.path.realpath(arg).endswith(SOURCE_SUFFIXES + BITCODE_SUFFIXES + DYNAMICLIB_SUFFIXES + ASSEMBLY_SUFFIXES)):
+ if (os.path.islink(arg) and os.path.realpath(arg).endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS)):
arg = os.path.realpath(arg)
if not arg.startswith('-'):
@@ -1061,15 +1068,15 @@ try:
logging.error(arg + ': No such file or directory')
exit(1)
- arg_suffix = filename_type_suffix(arg)
- if arg_suffix.endswith(SOURCE_SUFFIXES + BITCODE_SUFFIXES + DYNAMICLIB_SUFFIXES + ASSEMBLY_SUFFIXES) or shared.Building.is_ar(arg): # we already removed -o <target>, so all these should be inputs
+ arg_ending = filename_type_ending(arg)
+ if arg_ending.endswith(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + ASSEMBLY_ENDINGS) or shared.Building.is_ar(arg): # we already removed -o <target>, so all these should be inputs
newargs[i] = ''
- if arg_suffix.endswith(SOURCE_SUFFIXES):
+ if arg_ending.endswith(SOURCE_ENDINGS):
input_files.append(arg)
has_source_inputs = True
- elif arg_suffix.endswith(ASSEMBLY_SUFFIXES) or shared.Building.is_bitcode(arg): # this should be bitcode, make sure it is valid
+ elif arg_ending.endswith(ASSEMBLY_ENDINGS) or shared.Building.is_bitcode(arg): # this should be bitcode, make sure it is valid
input_files.append(arg)
- elif arg_suffix.endswith(STATICLIB_SUFFIXES + DYNAMICLIB_SUFFIXES):
+ elif arg_ending.endswith(STATICLIB_ENDINGS + DYNAMICLIB_ENDINGS):
# if it's not, and it's a library, just add it to libs to find later
l = unsuffixed_basename(arg)
for prefix in LIB_PREFIXES:
@@ -1081,10 +1088,10 @@ try:
newargs[i] = ''
else:
logging.warning(arg + ' is not valid LLVM bitcode')
- elif arg_suffix.endswith(STATICLIB_SUFFIXES):
+ elif arg_ending.endswith(STATICLIB_ENDINGS):
if not shared.Building.is_ar(arg):
if shared.Building.is_bitcode(arg):
- logging.error(arg + ': File has a suffix of a static library ' + str(STATICLIB_SUFFIXES) + ', but instead is an LLVM bitcode file! When linking LLVM bitcode files, use one of the suffixes ' + str(BITCODE_SUFFIXES))
+ logging.error(arg + ': File has a suffix of a static library ' + str(STATICLIB_ENDINGS) + ', but instead is an LLVM bitcode file! When linking LLVM bitcode files, use one of the suffixes ' + str(BITCODE_ENDINGS))
else:
logging.error(arg + ': Unknown format, not a static library!')
exit(1)
@@ -1114,7 +1121,7 @@ try:
logging.debug('looking for library "%s"' % lib)
found = False
for prefix in LIB_PREFIXES:
- for suff in STATICLIB_SUFFIXES + DYNAMICLIB_SUFFIXES:
+ for suff in STATICLIB_ENDINGS + DYNAMICLIB_ENDINGS:
name = prefix + lib + suff
for lib_dir in lib_dirs:
path = os.path.join(lib_dir, name)
@@ -1125,12 +1132,13 @@ try:
break
if found: break
if found: break
+ if not found: logging.warning('emcc: cannot find library "%s"' % lib)
# If not compiling to JS, then we are compiling to an intermediate bitcode objects or library, so
# ignore dynamic linking, since multiple dynamic linkings can interfere with each other
- if not filename_type_suffix(target)[1:] in JS_CONTAINING_SUFFIXES or ignore_dynamic_linking:
+ if not filename_type_suffix(target) in JS_CONTAINING_SUFFIXES or ignore_dynamic_linking:
def check(input_file):
- if input_file.endswith(DYNAMICLIB_SUFFIXES):
+ if filename_type_ending(input_file) in DYNAMICLIB_ENDINGS:
if not ignore_dynamic_linking: logging.warning('ignoring dynamic library %s because not compiling to JS or HTML, remember to link it when compiling to JS or HTML at the end' % os.path.basename(input_file))
return False
else:
@@ -1138,7 +1146,7 @@ try:
input_files = filter(lambda input_file: check(input_file), input_files)
if len(input_files) == 0:
- logging.error('no input files\nnote that input files without a known suffix are ignored, make sure your input files end with one of: ' + str(SOURCE_SUFFIXES + BITCODE_SUFFIXES + DYNAMICLIB_SUFFIXES + STATICLIB_SUFFIXES + ASSEMBLY_SUFFIXES))
+ logging.error('no input files\nnote that input files without a known suffix are ignored, make sure your input files end with one of: ' + str(SOURCE_ENDINGS + BITCODE_ENDINGS + DYNAMICLIB_ENDINGS + STATICLIB_ENDINGS + ASSEMBLY_ENDINGS))
exit(0)
newargs = CC_ADDITIONAL_ARGS + newargs
@@ -1275,14 +1283,14 @@ try:
# First, generate LLVM bitcode. For each input file, we get base.o with bitcode
for input_file in input_files:
- file_suffix = filename_type_suffix(input_file)
- if file_suffix.endswith(SOURCE_SUFFIXES):
+ file_ending = filename_type_ending(input_file)
+ if file_ending.endswith(SOURCE_ENDINGS):
logging.debug('compiling source file: ' + input_file)
input_file = shared.Building.preprocess(input_file, in_temp(uniquename(input_file)))
output_file = in_temp(unsuffixed(uniquename(input_file)) + '.o')
temp_files.append(output_file)
args = newargs + ['-emit-llvm', '-c', input_file, '-o', output_file]
- if file_suffix.endswith(CXX_SUFFIXES):
+ if file_ending.endswith(CXX_ENDINGS):
args += shared.EMSDK_CXX_OPTS
logging.debug("running: " + call + ' ' + ' '.join(args))
execute([call] + args) # let compiler frontend print directly, so colors are saved (PIPE kills that)
@@ -1290,17 +1298,17 @@ try:
logging.error('compiler frontend failed to generate LLVM bitcode, halting')
sys.exit(1)
else: # bitcode
- if file_suffix.endswith(BITCODE_SUFFIXES):
+ if file_ending.endswith(BITCODE_ENDINGS):
logging.debug('copying bitcode file: ' + input_file)
temp_file = in_temp(unsuffixed(uniquename(input_file)) + '.o')
shutil.copyfile(input_file, temp_file)
temp_files.append(temp_file)
- elif file_suffix.endswith(DYNAMICLIB_SUFFIXES) or shared.Building.is_ar(input_file):
+ elif file_ending.endswith(DYNAMICLIB_ENDINGS) or shared.Building.is_ar(input_file):
logging.debug('copying library file: ' + input_file)
temp_file = in_temp(uniquename(input_file))
shutil.copyfile(input_file, temp_file)
temp_files.append(temp_file)
- elif file_suffix.endswith(ASSEMBLY_SUFFIXES):
+ elif file_ending.endswith(ASSEMBLY_ENDINGS):
if not LEAVE_INPUTS_RAW:
# Note that by assembling the .ll file, then disassembling it later, we will
# remove annotations which is a good thing for compilation time
@@ -1318,8 +1326,8 @@ try:
# Optimize source files
if llvm_opts > 0:
for i, input_file in enumerate(input_files):
- file_suffix = filename_type_suffix(input_file)
- if file_suffix.endswith(SOURCE_SUFFIXES):
+ file_ending = filename_type_ending(input_file)
+ if file_ending.endswith(SOURCE_ENDINGS):
temp_file = temp_files[i]
logging.debug('optimizing %s with -O%s' % (input_file, llvm_opts))
shared.Building.llvm_opt(temp_file, llvm_opts)
@@ -1664,11 +1672,11 @@ try:
# First, combine the bitcode files if there are several. We must also link if we have a singleton .a
if len(input_files) + len(extra_files_to_link) > 1 or \
- (not LEAVE_INPUTS_RAW and not (suffix(temp_files[0]) in BITCODE_SUFFIXES or suffix(temp_files[0]) in DYNAMICLIB_SUFFIXES) and shared.Building.is_ar(temp_files[0])):
+ (not LEAVE_INPUTS_RAW and not (suffix(temp_files[0]) in BITCODE_ENDINGS or suffix(temp_files[0]) in DYNAMICLIB_ENDINGS) and shared.Building.is_ar(temp_files[0])):
linker_inputs = temp_files + extra_files_to_link
logging.debug('linking: ' + str(linker_inputs))
t0 = time.time()
- shared.Building.link(linker_inputs, in_temp(target_basename + '.bc'), force_archive_contents = len(filter(lambda temp: not temp.endswith(STATICLIB_SUFFIXES), temp_files)) == 0)
+ shared.Building.link(linker_inputs, in_temp(target_basename + '.bc'), force_archive_contents = len(filter(lambda temp: not temp.endswith(STATICLIB_ENDINGS), temp_files)) == 0)
t1 = time.time()
logging.debug(' linking took %.2f seconds' % (t1 - t0))
final = in_temp(target_basename + '.bc')
@@ -1746,7 +1754,7 @@ try:
if DEBUG: save_intermediate('autodebug', 'll')
# Simplify bitcode after autodebug
- if os.environ.get('EMCC_FAST_COMPILER') and AUTODEBUG:
+ if os.environ.get('EMCC_FAST_COMPILER') and (AUTODEBUG or LEAVE_INPUTS_RAW):
shared.Building.llvm_opt(final, ['-pnacl-abi-simplify-preopt', '-pnacl-abi-simplify-postopt'], final + '.adsimp.bc')
final += '.adsimp.bc'
if DEBUG: save_intermediate('adsimp', 'bc')
diff --git a/tests/test_core.py b/tests/test_core.py
index 5a19ef0c..e61f5c35 100644
--- a/tests/test_core.py
+++ b/tests/test_core.py
@@ -5033,7 +5033,7 @@ def process(filename):
'2xi40', # pnacl limitations in ExpandGetElementPtr
'legalizer_ta2', '514_ta2', # pnacl limitation in not legalizing i104, i96, etc.
'longjmp_tiny', 'longjmp_tiny_invoke', 'longjmp_tiny_phi', 'longjmp_tiny_phi2', 'indirectbrphi', 'ptrtoint_blockaddr', 'quoted', # current fastcomp limitations FIXME
- 'sillyfuncast', 'sillyfuncast2', 'sillybitcast', # TODO very very soon XXX
+ 'sillyfuncast', 'sillyfuncast2', 'sillybitcast', 'atomicrmw_unaligned' # TODO XXX
]: continue
if '_ta2' in shortname and not Settings.USE_TYPED_ARRAYS == 2:
print self.skip('case "%s" only relevant for ta2' % shortname)
diff --git a/tests/test_other.py b/tests/test_other.py
index c26052a3..0c325c74 100644
--- a/tests/test_other.py
+++ b/tests/test_other.py
@@ -1374,59 +1374,66 @@ f.close()
assert output == ''
def test_multidynamic_link(self):
- # Linking the same dynamic library in will error, normally, since we statically link it, causing dupe symbols
- # A workaround is to use --ignore-dynamic-linking, see emcc --help for details
+ # Linking the same dynamic library in statically will error, normally, since we statically link it, causing dupe symbols
- open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
- #include <stdio.h>
- extern void printey();
- extern void printother();
- int main() {
- printf("*");
- printey();
- printf("\n");
- printother();
- printf("\n");
- printf("*");
- return 0;
- }
- ''')
+ def test(link_cmd, lib_suffix=''):
+ print link_cmd, lib_suffix
- try:
- os.makedirs(os.path.join(self.get_dir(), 'libdir'));
- except:
- pass
+ self.clear()
- open(os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), 'w').write('''
- #include <stdio.h>
- void printey() {
- printf("hello from lib");
- }
- ''')
+ open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write(r'''
+ #include <stdio.h>
+ extern void printey();
+ extern void printother();
+ int main() {
+ printf("*");
+ printey();
+ printf("\n");
+ printother();
+ printf("\n");
+ printf("*");
+ return 0;
+ }
+ ''')
- open(os.path.join(self.get_dir(), 'libdir', 'libother.cpp'), 'w').write('''
- #include <stdio.h>
- extern void printey();
- void printother() {
- printf("|");
- printey();
- printf("|");
- }
- ''')
+ try:
+ os.makedirs(os.path.join(self.get_dir(), 'libdir'));
+ except:
+ pass
+
+ open(os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), 'w').write('''
+ #include <stdio.h>
+ void printey() {
+ printf("hello from lib");
+ }
+ ''')
+
+ open(os.path.join(self.get_dir(), 'libdir', 'libother.cpp'), 'w').write('''
+ #include <stdio.h>
+ extern void printey();
+ void printother() {
+ printf("|");
+ printey();
+ printf("|");
+ }
+ ''')
- compiler = [PYTHON, EMCC]
+ compiler = [PYTHON, EMCC]
- # Build libfile normally into an .so
- Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), '-o', os.path.join(self.get_dir(), 'libdir', 'libfile.so')]).communicate()
- # Build libother and dynamically link it to libfile
- Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libother.cpp'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-o', os.path.join(self.get_dir(), 'libdir', 'libother.so')]).communicate()
- # Build the main file, linking in both the libs
- Popen(compiler + [os.path.join(self.get_dir(), 'main.cpp'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-lother', '-c']).communicate()
+ # Build libfile normally into an .so
+ Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libfile.cpp'), '-o', os.path.join(self.get_dir(), 'libdir', 'libfile.so' + lib_suffix)]).communicate()
+ # Build libother and dynamically link it to libfile
+ Popen(compiler + [os.path.join(self.get_dir(), 'libdir', 'libother.cpp')] + link_cmd + ['-o', os.path.join(self.get_dir(), 'libdir', 'libother.so')]).communicate()
+ # Build the main file, linking in both the libs
+ Popen(compiler + [os.path.join(self.get_dir(), 'main.cpp')] + link_cmd + ['-lother', '-c']).communicate()
+ print '...'
+ # The normal build system is over. We need to do an additional step to link in the dynamic libraries, since we ignored them before
+ Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.o')] + link_cmd + ['-lother']).communicate()
- # The normal build system is over. We need to do an additional step to link in the dynamic libraries, since we ignored them before
- Popen([PYTHON, EMCC, os.path.join(self.get_dir(), 'main.o'), '-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile', '-lother']).communicate()
+ self.assertContained('*hello from lib\n|hello from lib|\n*', run_js(os.path.join(self.get_dir(), 'a.out.js')))
- self.assertContained('*hello from lib\n|hello from lib|\n*', run_js(os.path.join(self.get_dir(), 'a.out.js')))
+ test(['-L' + os.path.join(self.get_dir(), 'libdir'), '-lfile']) # -l, auto detection from library path
+ test(['-L' + os.path.join(self.get_dir(), 'libdir'), os.path.join(self.get_dir(), 'libdir', 'libfile.so.3.1.4.1.5.9')], '.3.1.4.1.5.9') # handle libX.so.1.2.3 as well
def test_js_link(self):
open(os.path.join(self.get_dir(), 'main.cpp'), 'w').write('''
diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js
index 296a5cae..c63cb36a 100644
--- a/tools/js-optimizer.js
+++ b/tools/js-optimizer.js
@@ -2149,9 +2149,6 @@ var IGNORABLE_ELIMINATOR_SCAN_NODES = set('num', 'toplevel', 'string', 'break',
var ABORTING_ELIMINATOR_SCAN_NODES = set('new', 'object', 'function', 'defun', 'for', 'while', 'array', 'throw'); // we could handle some of these, TODO, but nontrivial (e.g. for while, the condition is hit multiple times after the body)
function isTempDoublePtrAccess(node) { // these are used in bitcasts; they are not really affecting memory, and should cause no invalidation
- // XXX note that we assume they have no effect. this is only true due to the compiler emitting (write, read)
- // using the comma operator, so they are not split up. Otherwise, we would need to invalidate
- // tempDoublePtr when it is used, so write; read; write; read; would not become write; write; read; read;
assert(node[0] === 'sub');
return (node[2][0] === 'name' && node[2][1] === 'tempDoublePtr') ||
(node[2][0] === 'binary' && ((node[2][2][0] === 'name' && node[2][2][1] === 'tempDoublePtr') ||