Skip to content

Simplify clang vs clang++ selection process when compiling sources #20712

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

Merged
merged 1 commit into from
Nov 14, 2023
Merged
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
7 changes: 7 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ See docs/process.md for more on how version tagging works.

3.1.50 (in development)
-----------------------
- When compiling, Emscripten will now invoke `clang` or `clang++` depending only
on whether `emcc` or `em++` was run. Previously it would determine which to
run based on individual file extensions. One side effect of this is that you
may now see a clang warning when building `.c` source files using `em++`:
`warning: treating 'c' input as 'c++' when in C++ mode`. This also means that
the `DEFAULT_TO_CXX` setting now only applies when linking and not when
compiling. (#20712)

3.1.49 - 11/14/23
-----------------
Expand Down
45 changes: 11 additions & 34 deletions emcc.py
Original file line number Diff line number Diff line change
Expand Up @@ -1494,9 +1494,6 @@ def phase_setup(options, state, newargs):
diagnostics.warning('deprecated', 'RUNTIME_LINKED_LIBS is deprecated; you can simply list the libraries directly on the commandline now')
newargs += settings.RUNTIME_LINKED_LIBS

if settings.STRICT:
default_setting('DEFAULT_TO_CXX', 0)

# Find input files

# These three arrays are used to store arguments of different types for
Expand Down Expand Up @@ -2067,6 +2064,7 @@ def phase_linker_setup(options, state, newargs):
if settings.STRICT:
if not settings.MODULARIZE and not settings.EXPORT_ES6:
default_setting('STRICT_JS', 1)
default_setting('DEFAULT_TO_CXX', 0)
default_setting('AUTO_JS_LIBRARIES', 0)
default_setting('AUTO_NATIVE_LIBRARIES', 0)
default_setting('AUTO_ARCHIVE_INDEXES', 0)
Expand Down Expand Up @@ -3039,12 +3037,14 @@ def is_link_flag(flag):
return True
return flag.startswith(('-l', '-L', '-Wl,'))

CXX = [shared.CLANG_CXX]
CC = [shared.CLANG_CC]
if run_via_emxx:
compiler = [shared.CLANG_CXX]
else:
compiler = [shared.CLANG_CC]

if config.COMPILER_WRAPPER:
logger.debug('using compiler wrapper: %s', config.COMPILER_WRAPPER)
CXX.insert(0, config.COMPILER_WRAPPER)
CC.insert(0, config.COMPILER_WRAPPER)
compiler.insert(0, config.COMPILER_WRAPPER)

compile_args = [a for a in newargs if a and not is_link_flag(a)]
system_libs.ensure_sysroot()
Expand All @@ -3062,39 +3062,16 @@ def get_language_mode(args):
return ''

language_mode = get_language_mode(newargs)

def use_cxx(src):
if 'c++' in language_mode or run_via_emxx:
return True
suffix = shared.suffix(src)
# Next consider the filename
if suffix in C_ENDINGS + OBJC_ENDINGS:
return False
if suffix in CXX_ENDINGS:
return True
# Finally fall back to the default
if settings.DEFAULT_TO_CXX:
# Default to using C++ even when run as `emcc`.
# This means that emcc will act as a C++ linker when no source files are
# specified.
# This differs to clang and gcc where the default is always C unless run as
# clang++/g++.
return True
return False

def get_compiler(src_file):
if use_cxx(src_file):
return CXX
return CC
use_cxx = 'c++' in language_mode or run_via_emxx

def get_clang_command(src_file):
return get_compiler(src_file) + get_cflags(state.orig_args, use_cxx(src_file)) + compile_args + [src_file]
return compiler + get_cflags(state.orig_args, use_cxx) + compile_args + [src_file]

def get_clang_command_preprocessed(src_file):
return get_compiler(src_file) + get_clang_flags(state.orig_args) + compile_args + [src_file]
return compiler + get_clang_flags(state.orig_args) + compile_args + [src_file]

def get_clang_command_asm(src_file):
return get_compiler(src_file) + get_target_flags() + compile_args + [src_file]
return compiler + get_target_flags() + compile_args + [src_file]

# preprocessor-only (-E) support
if state.mode == Mode.PREPROCESS_ONLY:
Expand Down
6 changes: 3 additions & 3 deletions src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -1944,9 +1944,9 @@ var USE_OFFSET_CONVERTER = false;
var LOAD_SOURCE_MAP = false;

// Default to c++ mode even when run as `emcc` rather then `emc++`.
// When this is disabled `em++` is required when compiling and linking C++
// programs. This which matches the behaviour of gcc/g++ and clang/clang++.
// [compile+link]
// When this is disabled `em++` is required linking C++ programs. Disabling
// this will match the behaviour of gcc/g++ and clang/clang++.
// [link]
var DEFAULT_TO_CXX = true;

// While LLVM's wasm32 has long double = float128, we don't support printing
Expand Down
25 changes: 6 additions & 19 deletions test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -11720,29 +11720,16 @@ def test_default_to_cxx(self):
create_file('foo.h', '#include <string.h>')
create_file('cxxfoo.h', '#include <string>')

# The default bahviour is to default to C++, which means the C++ header can be compiled even
# with emcc.
self.run_process([EMCC, '-c', 'cxxfoo.h'])
# Compiling a C++ header using `em++` works.
self.run_process([EMXX, '-c', 'cxxfoo.h'])

# But this means that C flags can't be passed (since we are assuming C++)
err = self.expect_fail([EMCC, '-std=gnu11', '-c', 'foo.h'])
self.assertContained("'-std=gnu11' not allowed with 'C++'", err)

# If we disable DEFAULT_TO_CXX the emcc can be used with C-only flags (e.g. -std=gnu11),
self.run_process([EMCC, '-std=gnu11', '-c', 'foo.h', '-sDEFAULT_TO_CXX=0'])

# But can't be used to build C++ headers
err = self.expect_fail([EMCC, '-c', 'cxxfoo.h', '-sDEFAULT_TO_CXX=0'])
self.assertContained("'string' file not found", err)

# Check that STRICT also disables DEFAULT_TO_CXX
# Compiling the same header using `emcc` fails, just like `clang`
err = self.expect_fail([EMCC, '-c', 'cxxfoo.h', '-sSTRICT'])
self.assertContained("'string' file not found", err)

# Using em++ should alwasy work for C++ headers
self.run_process([EMXX, '-c', 'cxxfoo.h', '-sDEFAULT_TO_CXX=0'])
# Or using emcc with `-x c++`
self.run_process([EMCC, '-c', 'cxxfoo.h', '-sDEFAULT_TO_CXX=0', '-x', 'c++-header'])
# But it works if we pass and explicit language mode.
self.run_process([EMCC, '-c', 'cxxfoo.h', '-x', 'c++-header'])
self.run_process([EMCC, '-c', 'cxxfoo.h', '-x', 'c++'])

@parameterized({
'': ([],),
Expand Down
1 change: 0 additions & 1 deletion tools/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@
'USE_PTHREADS', # legacy name of PTHREADS setting
'SHARED_MEMORY',
'SUPPORT_LONGJMP',
'DEFAULT_TO_CXX',
'WASM_OBJECT_FILES',
'WASM_WORKERS',
'BULK_MEMORY',
Expand Down