Skip to content

Commit 1cd7599

Browse files
committed
When compiling, use a single clang command for all input sources. NFC
For folks that compiler a bunch of source files at once which should help by reducing the number of clang subprocesses that we spawn. This includes the new system library build process that we use internally. See #20577. Do the same for PCH compilation and pre-processing (-E).
1 parent 5022542 commit 1cd7599

File tree

2 files changed

+62
-49
lines changed

2 files changed

+62
-49
lines changed

emcc.py

Lines changed: 58 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,9 +1332,6 @@ def run(args):
13321332
logger.debug('stopping after compile phase')
13331333
for flag in state.link_flags:
13341334
diagnostics.warning('unused-command-line-argument', "argument unused during compilation: '%s'" % flag[1])
1335-
for f in linker_inputs:
1336-
diagnostics.warning('unused-command-line-argument', "%s: linker input file unused because linking not done" % f[1])
1337-
13381335
return 0
13391336

13401337
# We have now passed the compile phase, allow reading/writing of all settings.
@@ -1627,8 +1624,6 @@ def phase_setup(options, state, newargs):
16271624
elif '-M' in newargs or '-MM' in newargs:
16281625
options.default_object_extension = '.mout' # not bitcode, not js; but just dependency rule of the input file
16291626

1630-
if options.output_file and len(input_files) > 1:
1631-
exit_with_error('cannot specify -o with -c/-S/-E/-M and multiple source files')
16321627
else:
16331628
for arg in state.orig_args:
16341629
if any(arg.startswith(f) for f in COMPILE_ONLY_FLAGS):
@@ -3064,40 +3059,68 @@ def get_language_mode(args):
30643059
language_mode = get_language_mode(newargs)
30653060
use_cxx = 'c++' in language_mode or run_via_emxx
30663061

3067-
def get_clang_command(src_file):
3068-
return compiler + get_cflags(state.orig_args, use_cxx) + compile_args + [src_file]
3062+
def get_clang_command():
3063+
return compiler + get_cflags(state.orig_args, use_cxx) + compile_args
30693064

3070-
def get_clang_command_preprocessed(src_file):
3071-
return compiler + get_clang_flags(state.orig_args) + compile_args + [src_file]
3065+
def get_clang_command_preprocessed():
3066+
return compiler + get_clang_flags(state.orig_args) + compile_args
30723067

3073-
def get_clang_command_asm(src_file):
3074-
return compiler + get_target_flags() + compile_args + [src_file]
3068+
def get_clang_command_asm():
3069+
return compiler + get_target_flags() + compile_args
30753070

30763071
# preprocessor-only (-E) support
30773072
if state.mode == Mode.PREPROCESS_ONLY:
3078-
for input_file in [x[1] for x in input_files]:
3079-
cmd = get_clang_command(input_file)
3080-
if options.output_file:
3081-
cmd += ['-o', options.output_file]
3082-
# Do not compile, but just output the result from preprocessing stage or
3083-
# output the dependency rule. Warning: clang and gcc behave differently
3084-
# with -MF! (clang seems to not recognize it)
3085-
logger.debug(('just preprocessor ' if state.has_dash_E else 'just dependencies: ') + ' '.join(cmd))
3086-
shared.check_call(cmd)
3073+
inputs = [i[1] for i in input_files]
3074+
cmd = get_clang_command() + inputs
3075+
if options.output_file:
3076+
cmd += ['-o', options.output_file]
3077+
# Do not compile, but just output the result from preprocessing stage or
3078+
# output the dependency rule. Warning: clang and gcc behave differently
3079+
# with -MF! (clang seems to not recognize it)
3080+
logger.debug(('just preprocessor ' if state.has_dash_E else 'just dependencies: ') + ' '.join(cmd))
3081+
shared.check_call(cmd)
30873082
return []
30883083

30893084
# Precompiled headers support
30903085
if state.mode == Mode.PCH:
3091-
headers = [header for _, header in input_files]
3092-
for header in headers:
3086+
inputs = [i[1] for i in input_files]
3087+
for header in inputs:
30933088
if not shared.suffix(header) in HEADER_ENDINGS:
3094-
exit_with_error(f'cannot mix precompiled headers with non-header inputs: {headers} : {header}')
3095-
cmd = get_clang_command(header)
3096-
if options.output_file:
3097-
cmd += ['-o', options.output_file]
3098-
logger.debug(f"running (for precompiled headers): {cmd[0]} {' '.join(cmd[1:])}")
3099-
shared.check_call(cmd)
3100-
return []
3089+
exit_with_error(f'cannot mix precompiled headers with non-header inputs: {inputs} : {header}')
3090+
cmd = get_clang_command() + inputs
3091+
if options.output_file:
3092+
cmd += ['-o', options.output_file]
3093+
logger.debug(f"running (for precompiled headers): {cmd[0]} {' '.join(cmd[1:])}")
3094+
shared.check_call(cmd)
3095+
return []
3096+
3097+
if state.mode == Mode.COMPILE_ONLY:
3098+
inputs = [i[1] for i in input_files]
3099+
if all(get_file_suffix(i) in ASSEMBLY_ENDINGS for i in inputs):
3100+
cmd = get_clang_command_asm() + inputs
3101+
else:
3102+
cmd = get_clang_command() + inputs
3103+
if options.output_file:
3104+
cmd += ['-o', options.output_file]
3105+
if get_file_suffix(options.output_file) == '.bc' and not settings.LTO and '-emit-llvm' not in state.orig_args:
3106+
diagnostics.warning('emcc', '.bc output file suffix used without -flto or -emit-llvm. Consider using .o extension since emcc will output an object file, not a bitcode file')
3107+
shared.check_call(cmd)
3108+
if not options.output_file:
3109+
# Rename object files to match --default-obj-ext
3110+
# TODO: Remove '--default-obj-ext' to reduce this complexity
3111+
if '-emit-llvm' in state.orig_args:
3112+
if state.has_dash_S:
3113+
clang_object_extension = '.ll'
3114+
else:
3115+
clang_object_extension = '.bc'
3116+
else:
3117+
clang_object_extension = '.o'
3118+
if options.default_object_extension != clang_object_extension:
3119+
for i in inputs:
3120+
output = unsuffixed_basename(i) + clang_object_extension
3121+
new_output = unsuffixed_basename(i) + options.default_object_extension
3122+
move_file(output, new_output)
3123+
return []
31013124

31023125
linker_inputs = []
31033126
seen_names = {}
@@ -3108,32 +3131,21 @@ def uniquename(name):
31083131
return unsuffixed(name) + '_' + seen_names[name] + shared.suffix(name)
31093132

31103133
def get_object_filename(input_file):
3111-
if state.mode == Mode.COMPILE_ONLY:
3112-
# In compile-only mode we don't use any temp file. The object files
3113-
# are written directly to their final output locations.
3114-
if options.output_file:
3115-
assert len(input_files) == 1
3116-
if get_file_suffix(options.output_file) == '.bc' and not settings.LTO and '-emit-llvm' not in state.orig_args:
3117-
diagnostics.warning('emcc', '.bc output file suffix used without -flto or -emit-llvm. Consider using .o extension since emcc will output an object file, not a bitcode file')
3118-
return options.output_file
3119-
else:
3120-
return unsuffixed_basename(input_file) + options.default_object_extension
3121-
else:
3122-
return in_temp(unsuffixed(uniquename(input_file)) + options.default_object_extension)
3134+
return in_temp(unsuffixed(uniquename(input_file)) + options.default_object_extension)
31233135

31243136
def compile_source_file(i, input_file):
31253137
logger.debug(f'compiling source file: {input_file}')
31263138
output_file = get_object_filename(input_file)
3127-
if state.mode not in (Mode.COMPILE_ONLY, Mode.PREPROCESS_ONLY):
3128-
linker_inputs.append((i, output_file))
3139+
linker_inputs.append((i, output_file))
31293140
if get_file_suffix(input_file) in ASSEMBLY_ENDINGS:
3130-
cmd = get_clang_command_asm(input_file)
3141+
cmd = get_clang_command_asm()
31313142
elif get_file_suffix(input_file) in PREPROCESSED_ENDINGS:
3132-
cmd = get_clang_command_preprocessed(input_file)
3143+
cmd = get_clang_command_preprocessed()
31333144
else:
3134-
cmd = get_clang_command(input_file)
3145+
cmd = get_clang_command()
31353146
if get_file_suffix(input_file) in ['.pcm']:
31363147
cmd = [c for c in cmd if not c.startswith('-fprebuilt-module-path=')]
3148+
cmd += [input_file]
31373149
if not state.has_dash_c:
31383150
cmd += ['-c']
31393151
cmd += ['-o', output_file]

test/test_other.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -589,7 +589,7 @@ def test_multiple_sources(self):
589589
self.clear()
590590
err = self.expect_fail(cmd + ['-o', 'out.o'])
591591

592-
self.assertContained('cannot specify -o with -c/-S/-E/-M and multiple source files', err)
592+
self.assertContained('clang: error: cannot specify -o when generating multiple output files', err)
593593
self.assertNotExists('twopart_main.o')
594594
self.assertNotExists('twopart_side.o')
595595
self.assertNotExists(test_file('twopart_main.o'))
@@ -5280,10 +5280,11 @@ def test_dashS_stdout(self):
52805280
self.assertEqual(os.listdir('.'), [])
52815281
self.assertContained('hello_world.c', stdout)
52825282

5283-
def test_emit_llvm(self):
5283+
def test_emit_llvm_asm(self):
52845284
self.run_process([EMCC, test_file('hello_world.c'), '-S', '-emit-llvm'])
52855285
self.assertIsLLVMAsm('hello_world.ll')
52865286

5287+
def test_emit_llvm(self):
52875288
self.run_process([EMCC, test_file('hello_world.c'), '-c', '-emit-llvm'])
52885289
self.assertTrue(building.is_bitcode('hello_world.bc'))
52895290

@@ -11414,7 +11415,7 @@ def test_linker_flags_unused(self):
1141411415
def test_linker_input_unused(self):
1141511416
self.run_process([EMXX, '-c', test_file('hello_world.cpp')])
1141611417
err = self.run_process([EMCC, 'hello_world.o', '-c', '-o', 'out.o'], stderr=PIPE).stderr
11417-
self.assertContained("warning: hello_world.o: linker input file unused because linking not done [-Wunused-command-line-argument", err)
11418+
self.assertContained("clang: warning: hello_world.o: 'linker' input unused [-Wunused-command-line-argument]", err)
1141811419
# In this case the compiler does not produce any output file.
1141911420
self.assertNotExists('out.o')
1142011421

0 commit comments

Comments
 (0)