diff --git a/emcc.py b/emcc.py index 94f655878337f..66e58c65bfcae 100755 --- a/emcc.py +++ b/emcc.py @@ -974,12 +974,22 @@ def optimizing(opts): newargs = [a for a in newargs if a is not ''] - # -c means do not link in gcc, and for us, the parallel is to not go all the way to JS, but stop at bitcode has_dash_c = '-c' in newargs - if has_dash_c: - assert has_source_inputs or has_header_inputs, 'Must have source code or header inputs to use -c' - target = target_basename + '.o' - final_suffix = '.o' + has_dash_S = '-S' in newargs + if has_dash_c or has_dash_S: + assert has_source_inputs or has_header_inputs, 'Must have source code or header inputs to use -c or -S' + if has_dash_c: + if '-emit-llvm' in newargs: + final_suffix = '.bc' + else: + final_suffix = '.o' + elif has_dash_S: + if '-emit-llvm' in newargs: + final_suffix = '.ll' + else: + final_suffix = '.s' + target = target_basename + final_suffix + if '-E' in newargs: final_suffix = '.eout' # not bitcode, not js; but just result from preprocessing stage of the input file if '-M' in newargs or '-MM' in newargs: @@ -1787,7 +1797,8 @@ def compile_source_file(i, input_file): logger.debug("running: " + ' '.join(shared.Building.doublequote_spaces(args))) # NOTE: Printing this line here in this specific format is important, it is parsed to implement the "emcc --cflags" command if run_process(args, check=False).returncode != 0: exit_with_error('compiler frontend failed to generate LLVM bitcode, halting') - assert(os.path.exists(output_file)) + if output_file != '-': + assert(os.path.exists(output_file)) # First, generate LLVM bitcode. For each input file, we get base.o with bitcode for i, input_file in input_files: @@ -1839,9 +1850,9 @@ def compile_source_file(i, input_file): # Decide what we will link executable_endings = JS_CONTAINING_ENDINGS + ('.wasm',) - stop_at_bitcode = final_suffix not in executable_endings + compile_only = final_suffix not in executable_endings or has_dash_c or has_dash_S - if stop_at_bitcode or not shared.Settings.WASM_BACKEND: + if compile_only or not shared.Settings.WASM_BACKEND: # Filter link flags, keeping only those that shared.Building.link knows # how to deal with. We currently can't handle flags with options (like # -Wl,-rpath,/bin:/lib, where /bin:/lib is an option for the -rpath @@ -1855,8 +1866,8 @@ def supported(f): linker_inputs = [val for _, val in sorted(temp_files + link_flags)] - # If we were just asked to generate bitcode, stop there - if stop_at_bitcode: + # If we were just compiling stop here + if compile_only: if not specified_target: assert len(temp_files) == len(input_files) for tempf, inputf in zip(temp_files, input_files): @@ -1885,7 +1896,7 @@ def supported(f): # we have multiple files: Link them logger.debug('link: ' + str(linker_inputs) + specified_target) shared.Building.link_to_object(linker_inputs, specified_target) - logger.debug('stopping at object file') + logger.debug('stopping after compile phase') if shared.Settings.SIDE_MODULE: exit_with_error('SIDE_MODULE must only be used when compiling to an executable shared library, and not when emitting an object file. That is, you should be emitting a .wasm file (for wasm) or a .js file (for asm.js). Note that when compiling to a typical native suffix for a shared library (.so, .dylib, .dll; which many build systems do) then Emscripten emits an object file, which you should then compile to .wasm or .js with SIDE_MODULE.') if final_suffix.lower() in ('.so', '.dylib', '.dll'): diff --git a/tests/test_other.py b/tests/test_other.py index 2ff2defc11ce5..d38ed3ba77d26 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -4480,6 +4480,28 @@ def test_syscall_without_filesystem(self): }''') run_process([PYTHON, EMCC, 'src.c', '-s', 'NO_FILESYSTEM=1']) + def test_dashS(self): + run_process([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-S']) + self.assertExists('hello_world.s') + + def test_dashS_stdout(self): + stdout = run_process([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-S', '-o', '-'], stdout=PIPE).stdout + self.assertEqual(os.listdir('.'), []) + self.assertContained('hello_world.c', stdout) + + def test_emit_llvm(self): + # TODO(https://github.com/emscripten-core/emscripten/issues/9016): + # We shouldn't need to copy the file here but if we don't then emcc will + # internally clobber the hello_world.ll in tests. + shutil.copyfile(path_from_root('tests', 'hello_world.c'), 'hello_world.c') + run_process([PYTHON, EMCC, 'hello_world.c', '-S', '-emit-llvm']) + self.assertExists('hello_world.ll') + bitcode = open('hello_world.ll').read() + self.assertContained('target triple = "', bitcode) + + run_process([PYTHON, EMCC, path_from_root('tests', 'hello_world.c'), '-c', '-emit-llvm']) + self.assertTrue(Building.is_bitcode('hello_world.bc')) + def test_dashE(self): create_test_file('src.cpp', r'''#include __EMSCRIPTEN_major__ __EMSCRIPTEN_minor__ __EMSCRIPTEN_tiny__ EMSCRIPTEN_KEEPALIVE