diff options
-rwxr-xr-x | emar | 4 | ||||
-rwxr-xr-x | emcc | 26 | ||||
-rw-r--r-- | tests/openjpeg/CMakeLists.txt | 2 | ||||
-rwxr-xr-x | tests/runner.py | 80 | ||||
-rw-r--r-- | tools/shared.py | 47 |
5 files changed, 123 insertions, 36 deletions
@@ -12,11 +12,11 @@ from tools import shared DEBUG = os.environ.get('EMCC_DEBUG') -newargs = [shared.LLVM_LINK] + sys.argv[3:] + ['-o='+sys.argv[2]] +newargs = [shared.LLVM_AR] + sys.argv[1:] if DEBUG: print >> sys.stderr, 'emar:', sys.argv, ' ==> ', newargs if len(newargs) > 2: - os.execvp(shared.LLVM_LINK, newargs) + os.execvp(shared.LLVM_AR, newargs) @@ -239,7 +239,8 @@ if EMMAKEN_CFLAGS: CC_ADDITIONAL_ARGS += EMMAKEN_CFLAGS.split(' ') # ---------------- Utilities --------------- SOURCE_SUFFIXES = ('.c', '.cpp', '.cxx', '.cc') -BITCODE_SUFFIXES = ('.bc', '.o', '.a', '.dylib', '.so', '.dll') +BITCODE_SUFFIXES = ('.bc', '.o') +SHAREDLIB_SUFFIXES = ('.dylib', '.so', '.dll') ASSEMBLY_SUFFIXES = ('.ll',) def unsuffixed(name): @@ -377,7 +378,7 @@ try: for i in range(len(newargs)): # find input files XXX this a simple heuristic. we should really analyze based on a full understanding of gcc params, # right now we just assume that what is left contains no more |-x OPT| things arg = newargs[i] - if arg.endswith(SOURCE_SUFFIXES + BITCODE_SUFFIXES + ASSEMBLY_SUFFIXES): # we already removed -o <target>, so all these should be inputs + if arg.endswith(SOURCE_SUFFIXES + BITCODE_SUFFIXES + SHAREDLIB_SUFFIXES + ASSEMBLY_SUFFIXES) or shared.Building.is_ar(arg): # we already removed -o <target>, so all these should be inputs newargs[i] = '' if os.path.exists(arg): if arg.endswith(SOURCE_SUFFIXES): @@ -425,11 +426,14 @@ try: if DEBUG: print >> sys.stderr, 'emcc: compiling to bitcode' + temp_files = [] + # First, generate LLVM bitcode. For each input file, we get base.o with bitcode for input_file in input_files: if input_file.endswith(SOURCE_SUFFIXES): if DEBUG: print >> sys.stderr, 'emcc: compiling source file: ', input_file output_file = in_temp(unsuffixed_basename(input_file) + '.o') + temp_files.append(output_file) args = newargs + ['-emit-llvm', '-c', input_file, '-o', output_file] if DEBUG: print >> sys.stderr, "emcc running:", call, ' '.join(args) Popen([call] + args).communicate() # let compiler frontend print directly, so colors are saved (PIPE kills that) @@ -439,13 +443,22 @@ try: else: # bitcode if input_file.endswith(BITCODE_SUFFIXES): if DEBUG: print >> sys.stderr, 'emcc: copying bitcode file: ', input_file - shutil.copyfile(input_file, in_temp(unsuffixed_basename(input_file) + '.o')) + temp_file = in_temp(unsuffixed_basename(input_file) + '.o') + shutil.copyfile(input_file, temp_file) + temp_files.append(temp_file) + elif input_file.endswith(SHAREDLIB_SUFFIXES) or shared.Building.is_ar(input_file): + if DEBUG: print >> sys.stderr, 'emcc: copying library file: ', input_file + temp_file = in_temp(os.path.basename(input_file)) + shutil.copyfile(input_file, temp_file) + temp_files.append(temp_file) else: #.ll 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 if DEBUG: print >> sys.stderr, 'emcc: assembling assembly file: ', input_file - shared.Building.llvm_as(input_file, in_temp(unsuffixed_basename(input_file) + '.o')) + temp_file = in_temp(unsuffixed_basename(input_file) + '.o') + shared.Building.llvm_as(input_file, temp_file) + temp_files.append(temp_file) # If we were just asked to generate bitcode, stop there if final_suffix not in ['js', 'html']: @@ -461,11 +474,10 @@ try: assert not has_dash_c, 'fatal error: cannot specify -o with -c with multiple files' + str(sys.argv) # We have a specified target (-o <target>), which is not JavaScript or HTML, and # we have multiple files: Link them TODO: llvm link-time opts? - ld_args = map(lambda input_file: in_temp(unsuffixed_basename(input_file) + '.o'), input_files) + \ - ['-o', specified_target] + ld_args = temp_files + ['-b', specified_target] #[arg.split('-Wl,')[1] for arg in filter(lambda arg: arg.startswith('-Wl,'), sys.argv)] if DEBUG: print >> sys.stderr, 'emcc: link: ' + str(ld_args) - Popen([shared.LLVM_LINK] + ld_args).communicate() + Popen([shared.LLVM_LD, '-disable-opt'] + ld_args).communicate() exit(0) ## Continue on to create JavaScript diff --git a/tests/openjpeg/CMakeLists.txt b/tests/openjpeg/CMakeLists.txt index 52150f5f..d8671fed 100644 --- a/tests/openjpeg/CMakeLists.txt +++ b/tests/openjpeg/CMakeLists.txt @@ -22,6 +22,8 @@ STRING(TOLOWER ${OPENJPEG_NAMESPACE} OPENJPEG_LIBRARY_NAME) PROJECT(${OPENJPEG_NAMESPACE} C) +include(CMakeDetermineSystem) + # Do full dependency headers. INCLUDE_REGULAR_EXPRESSION("^.*$") diff --git a/tests/runner.py b/tests/runner.py index ae46634c..069598d1 100755 --- a/tests/runner.py +++ b/tests/runner.py @@ -260,11 +260,13 @@ process(sys.argv[1]) if self.library_cache is not None: if cache and self.library_cache.get(cache_name): print >> sys.stderr, '<load build from cache> ', - bc_file = os.path.join(output_dir, 'lib' + name + '.bc') - f = open(bc_file, 'wb') - f.write(self.library_cache[cache_name]) - f.close() - return bc_file + generated_libs = [] + for bc_file in self.library_cache[cache_name]: + f = open(bc_file, 'wb') + f.write(self.library_cache[cache_name][bc_file]) + f.close() + generated_libs.append(bc_file) + return generated_libs print >> sys.stderr, '<building and saving into cache> ', @@ -917,6 +919,46 @@ if 'benchmark' not in str(sys.argv) and 'sanity' not in str(sys.argv): ''' self.do_run(src, '*1 2*') + def test_multiply_defined_symbols(self): + a1 = "int f() { return 1; }" + a1_name = os.path.join(self.get_dir(), 'a1.c') + open(a1_name, 'w').write(a1) + a2 = "void x() {}" + a2_name = os.path.join(self.get_dir(), 'a2.c') + open(a2_name, 'w').write(a2) + b1 = "int f() { return 2; }" + b1_name = os.path.join(self.get_dir(), 'b1.c') + open(b1_name, 'w').write(b1) + b2 = "void y() {}" + b2_name = os.path.join(self.get_dir(), 'b2.c') + open(b2_name, 'w').write(b2) + main = r''' + #include <stdio.h> + int f(); + int main() { + printf("result: %d\n", f()); + return 0; + } + ''' + main_name = os.path.join(self.get_dir(), 'main.c') + open(main_name, 'w').write(main) + + Building.emcc(a1_name) + Building.emcc(a2_name) + Building.emcc(b1_name) + Building.emcc(b2_name) + Building.emcc(main_name) + + liba_name = os.path.join(self.get_dir(), 'liba.a') + Building.emar('cr', liba_name, [a1_name + '.o', a2_name + '.o']) + libb_name = os.path.join(self.get_dir(), 'libb.a') + Building.emar('cr', libb_name, [b1_name + '.o', b2_name + '.o']) + + all_name = os.path.join(self.get_dir(), 'all.bc') + Building.link([main_name + '.o', liba_name, libb_name], all_name) + + self.do_ll_run(all_name, 'result: 1') + def test_if(self): src = ''' #include <stdio.h> @@ -4320,7 +4362,7 @@ def process(filename): self.do_run(open(path_from_root('tests', 'freetype', 'main.c'), 'r').read(), open(path_from_root('tests', 'freetype', 'ref.txt'), 'r').read(), ['font.ttf', 'test!', '150', '120', '25'], - libraries=[self.get_freetype()], + libraries=self.get_freetype(), includes=[path_from_root('tests', 'freetype', 'include')], post_build=post) #build_ll_hook=self.do_autodebug) @@ -4361,7 +4403,7 @@ def process(filename): self.do_run(open(path_from_root('tests', 'zlib', 'example.c'), 'r').read(), open(path_from_root('tests', 'zlib', 'ref.txt'), 'r').read(), - libraries=[self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a'])], + libraries=self.get_library('zlib', os.path.join('libz.a'), make_args=['libz.a']), includes=[path_from_root('tests', 'zlib')], force_c=True) @@ -4378,10 +4420,10 @@ def process(filename): self.do_run(open(path_from_root('tests', 'bullet', 'Demos', 'HelloWorld', 'HelloWorld.cpp'), 'r').read(), [open(path_from_root('tests', 'bullet', 'output.txt'), 'r').read(), # different roundings open(path_from_root('tests', 'bullet', 'output2.txt'), 'r').read()], - libraries=[self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletCollision.a'), - os.path.join('src', '.libs', 'libBulletDynamics.a'), + libraries=self.get_library('bullet', [os.path.join('src', '.libs', 'libBulletDynamics.a'), + os.path.join('src', '.libs', 'libBulletCollision.a'), os.path.join('src', '.libs', 'libLinearMath.a')], - configure_args=['--disable-demos','--disable-dependency-tracking'])], + configure_args=['--disable-demos','--disable-dependency-tracking']), includes=[path_from_root('tests', 'bullet', 'src')], js_engines=[SPIDERMONKEY_ENGINE]) # V8 issue 1407 @@ -4422,15 +4464,15 @@ def process(filename): freetype = self.get_freetype() poppler = self.get_library('poppler', - [os.path.join('poppler', '.libs', self.get_shared_library_name('libpoppler.so.13')), - os.path.join('utils', 'pdftoppm.o'), - os.path.join('utils', 'parseargs.o')], - configure_args=['--disable-libjpeg', '--disable-libpng', '--disable-poppler-qt', '--disable-poppler-qt4', '--disable-cms']) + [os.path.join('utils', 'pdftoppm.o'), + os.path.join('utils', 'parseargs.o'), + os.path.join('poppler', '.libs', 'libpoppler.a')], + configure_args=['--disable-libjpeg', '--disable-libpng', '--disable-poppler-qt', '--disable-poppler-qt4', '--disable-cms', '--disable-cairo-output', '--disable-abiword-output', '--enable-shared=no']) # Combine libraries combined = os.path.join(self.get_dir(), 'poppler-combined.bc') - Building.link([freetype, poppler], combined) + Building.link(poppler + freetype, combined) self.do_ll_run(combined, map(ord, open(path_from_root('tests', 'poppler', 'ref.ppm'), 'r').read()).__str__().replace(' ', ''), @@ -4464,11 +4506,11 @@ def process(filename): shutil.copy(path_from_root('tests', 'openjpeg', 'opj_config.h'), self.get_dir()) lib = self.get_library('openjpeg', - [os.path.join('bin', self.get_shared_library_name('libopenjpeg.so.1.4.0')), - os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/index.c.o'.split('/')), + [os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/index.c.o'.split('/')), os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/convert.c.o'.split('/')), os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/__/common/color.c.o'.split('/')), - os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/__/common/getopt.c.o'.split('/'))], + os.path.sep.join('codec/CMakeFiles/j2k_to_image.dir/__/common/getopt.c.o'.split('/')), + os.path.join('bin', self.get_shared_library_name('libopenjpeg.so.1.4.0'))], configure=['cmake', '.'], #configure_args=['--enable-tiff=no', '--enable-jp3d=no', '--enable-png=no'], make_args=[]) # no -j 2, since parallel builds can fail @@ -4512,7 +4554,7 @@ def process(filename): self.do_run(open(path_from_root('tests', 'openjpeg', 'codec', 'j2k_to_image.c'), 'r').read(), 'Successfully generated', # The real test for valid output is in image_compare '-i image.j2k -o image.raw'.split(' '), - libraries=[lib], + libraries=lib, includes=[path_from_root('tests', 'openjpeg', 'libopenjpeg'), path_from_root('tests', 'openjpeg', 'codec'), path_from_root('tests', 'openjpeg', 'common'), diff --git a/tools/shared.py b/tools/shared.py index 7f633318..ba953e19 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -90,6 +90,7 @@ CLANG_CPP=os.path.expanduser(os.path.join(LLVM_ROOT, 'clang++')) CLANG=CLANG_CPP LLVM_LINK=os.path.join(LLVM_ROOT, 'llvm-link') LLVM_LD=os.path.join(LLVM_ROOT, 'llvm-ld') +LLVM_AR=os.path.join(LLVM_ROOT, 'llvm-ar') LLVM_OPT=os.path.expanduser(os.path.join(LLVM_ROOT, 'opt')) LLVM_AS=os.path.expanduser(os.path.join(LLVM_ROOT, 'llvm-as')) LLVM_DIS=os.path.expanduser(os.path.join(LLVM_ROOT, 'llvm-dis')) @@ -450,18 +451,18 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' \ stderr=open(os.path.join(project_dir, 'configure_err'), 'w'), env=env) Building.make(make + make_args, stdout=open(os.path.join(project_dir, 'make_'), 'w'), stderr=open(os.path.join(project_dir, 'make_err'), 'w'), env=env) - bc_file = os.path.join(project_dir, 'bc.bc') - Building.link(generated_libs, bc_file) if cache is not None: - cache[cache_name] = open(bc_file, 'rb').read() + cache[cache_name] = {} + for f in generated_libs: + cache[cache_name][f] = open(f, 'rb').read() if old_dir: os.chdir(old_dir) - return bc_file + return generated_libs @staticmethod def link(files, target): try_delete(target) - output = Popen([LLVM_LINK] + files + ['-o', target], stdout=PIPE).communicate()[0] + output = Popen([LLVM_LD, '-disable-opt'] + files + ['-b', target], stdout=PIPE).communicate()[0] assert os.path.exists(target) and (output is None or 'Could not open input file' not in output), 'Linking error: ' + output # Emscripten optimizations that we run on the .ll file @@ -553,6 +554,13 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' \ assert os.path.exists(output_filename), 'emcc could not create output file' @staticmethod + def emar(action, output_filename, filenames, stdout=None, stderr=None, env=None): + try_delete(output_filename) + Popen([EMAR, action, output_filename] + filenames, stdout=stdout, stderr=stderr, env=env).communicate() + if 'c' in action: + assert os.path.exists(output_filename), 'emar could not create output file' + + @staticmethod def emscripten(filename, append_ext=True, extra_args=[]): # Allow usage of emscripten.py without warning os.environ['EMSCRIPTEN_SUPPRESS_USAGE_WARNING'] = '1' @@ -732,6 +740,22 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' \ return filename + '.cc.js' + _is_ar_cache = {} + @staticmethod + def is_ar(filename): + try: + if Building._is_ar_cache.get(filename): + return Building._is_ar_cache[filename] + b = open(filename, 'r').read(8) + sigcheck = b[0] == '!' and b[1] == '<' and \ + b[2] == 'a' and b[3] == 'r' and \ + b[4] == 'c' and b[5] == 'h' and \ + b[6] == '>' and ord(b[7]) == 10 + Building._is_ar_cache[filename] = sigcheck + return sigcheck + except: + return False + @staticmethod def is_bitcode(filename): # checks if a file contains LLVM bitcode @@ -740,9 +764,13 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' \ defs = Building.llvm_nm(filename, stderr=PIPE) # If no symbols found, it might just be an empty bitcode file, try to dis it if len(defs.defs) + len(defs.undefs) + len(defs.commons) == 0: - test_ll = os.path.join(EMSCRIPTEN_TEMP_DIR, 'test.ll') - Building.llvm_dis(filename, test_ll) - assert os.path.exists(test_ll) + # llvm-nm 3.0 has a bug when reading symbols from ar files + # so try to see if we're dealing with an ar file, in which + # case we should try to dis it. + if not Building.is_ar(filename): + test_ll = os.path.join(EMSCRIPTEN_TEMP_DIR, 'test.ll') + Building.llvm_dis(filename, test_ll) + assert os.path.exists(test_ll) except: return False @@ -750,6 +778,9 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)''' \ b = open(filename, 'r').read(4) if b[0] == 'B' and b[1] == 'C': return True + # look for ar signature + elif Building.is_ar(filename): + return True # on OS X, there is a 20-byte prefix elif ord(b[0]) == 222 and ord(b[1]) == 192 and ord(b[2]) == 23 and ord(b[3]) == 11: b = open(filename, 'r').read(24) |