Skip to content

Add --force-output-type option #5575

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 30 additions & 11 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@
JS_CONTAINING_SUFFIXES = ('js', 'html')
EXECUTABLE_SUFFIXES = JS_CONTAINING_SUFFIXES + ('wasm',)

EXPLICIT_OUTPUT_TYPES = ('js', 'html', 'bc')

DEFERRED_REPONSE_FILES = ('EMTERPRETIFY_BLACKLIST', 'EMTERPRETIFY_WHITELIST')

# Mapping of emcc opt levels to llvm opt levels. We use llvm opt level 3 in emcc opt
Expand Down Expand Up @@ -165,6 +167,7 @@ def __init__(self):
# Specifies the line ending format to use for all generated text files.
# Defaults to using the native EOL on each platform (\r\n on Windows, \n on Linux&OSX)
self.output_eol = os.linesep
self.force_output_type = None


class JSOptimizer(object):
Expand Down Expand Up @@ -542,11 +545,6 @@ def uniquename(name):
target = specified_target if specified_target is not None else 'a.out.js' # specified_target is the user-specified one, target is what we will generate
target_basename = unsuffixed_basename(target)

if '.' in target:
final_suffix = target.split('.')[-1]
else:
final_suffix = ''

if TEMP_DIR:
temp_dir = TEMP_DIR
if os.path.exists(temp_dir):
Expand Down Expand Up @@ -777,24 +775,37 @@ def detect_fixed_language_mode(args):

newargs = [arg for arg in newargs if arg is not '']

final_suffix = None
# -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'
if specified_target == None:
target = target_basename + '.o'
final_suffix = 'o'
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:
final_suffix = 'mout' # not bitcode, not js; but just dependency rule of the input file

if final_suffix == None:
if options.force_output_type != None:
final_suffix = options.force_output_type
else:
final_suffix = suffix(target)
if final_suffix == None:
final_suffix = '' # generate bitcode by default

final_ending = ('.' + final_suffix) if len(final_suffix) > 0 else ''

target_unsuffixed = unsuffixed(target)

# target is now finalized, can finalize other _target s
js_target = unsuffixed(target) + '.js'
js_target = target if options.force_output_type == 'js' else target_unsuffixed + '.js'

asm_target = unsuffixed(js_target) + '.asm.js' # might not be used, but if it is, this is the name
wasm_text_target = asm_target.replace('.asm.js', '.wast') # ditto, might not be used
wasm_binary_target = asm_target.replace('.asm.js', '.wasm') # ditto, might not be used
asm_target = target_unsuffixed + '.asm.js' # might not be used, but if it is, this is the name
wasm_text_target = target_unsuffixed + '.wast' # ditto, might not be used
wasm_binary_target = target_unsuffixed + '.wasm' # ditto, might not be used

if final_suffix == 'html' and not options.separate_asm and ('PRECISE_F32=2' in settings_changes or 'USE_PTHREADS=2' in settings_changes):
options.separate_asm = True
Expand Down Expand Up @@ -827,7 +838,7 @@ def get_last_setting_change(setting):

# 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 filename_type_suffix(target) not in JS_CONTAINING_SUFFIXES or options.ignore_dynamic_linking:
if final_suffix not in JS_CONTAINING_SUFFIXES or options.ignore_dynamic_linking:
def check(input_file):
if filename_type_ending(input_file) in DYNAMICLIB_ENDINGS:
if not options.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))
Expand Down Expand Up @@ -2102,6 +2113,14 @@ def parse_args(newargs):
exit(1)
newargs[i] = ''
newargs[i+1] = ''
elif newargs[i] == '--force-output-type':
if newargs[i+1] in EXPLICIT_OUTPUT_TYPES:
options.force_output_type = newargs[i+1]
else:
logging.error('Invalid value "' + newargs[i+1] + '" to --force-output-type')
exit(1)
newargs[i] = ''
newargs[i+1] = ''

if should_exit:
sys.exit(0)
Expand Down
41 changes: 41 additions & 0 deletions tests/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -7890,3 +7890,44 @@ def test_include_system_header_in_c(self):
print inc
open('a.c', 'w').write(inc)
subprocess.check_call([PYTHON, EMCC, 'a.c'])

def test_force_output_type(self):
test_file = os.path.join(self.get_dir(), 'test.cpp')
fout = open(test_file, 'w')
fout.write('int main() { return 0; }')
fout.close()

def assert_is_bc(filepath):
fin = open(filepath, 'rb')
try:
magic = fin.read(2)
finally:
fin.close()
assert magic[0] == 'B' and magic[1] == 'C'

def assert_is_js(filepath):
fin = open(filepath, 'r')
try:
content = fin.read()
finally:
fin.close()
self.assertContained('function', content)

def assert_is_html(filepath):
fin = open(filepath, 'r')
try:
content = fin.read()
finally:
fin.close()
assert content.lstrip().lower().startswith('<!doctype')

output_types = [ ('bc', assert_is_bc),
('js', assert_is_js),
('html', assert_is_html),
]

for output_type, verifier in output_types:
for output_suffix in ['', '.o', '.js', '.html', '.somesuffix']:
output_path = os.path.join(self.get_dir(), 'output' + output_suffix)
subprocess.check_call([PYTHON, EMCC, '--force-output-type', output_type, test_file, '-o', output_path])
verifier(output_path)