Skip to content

Commit bad2600

Browse files
authored
Make -gsource-map independent of name sections and JS minification (#25238)
Previously, The `-gsource-map` flag (in addition to generating a source map) caused a name section to be generated in the wasm binary, and also suppressed minification of the JS glue. This PR makes -gsource-map independent of name sections and minification, so it no longer does either of those. This allows source maps to be used with fully-optimized release builds, for use cases such as symbolizing stack traces from production. To get the old behavior, the `-g2` flag can be added to `-gsource-map`. Fixes #20462 Fixes #24626
1 parent a264a9e commit bad2600

File tree

6 files changed

+43
-23
lines changed

6 files changed

+43
-23
lines changed

ChangeLog.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ See docs/process.md for more on how version tagging works.
2020

2121
4.0.15 (in development)
2222
-----------------------
23+
- The `-gsource-map` flag has been updated to be independent of other types of
24+
debugging effects (in particular it no longer causes the wasm binary to have
25+
a name section, and it no longer suppresses minification of the JS output).
26+
To get the previous behavior, add `-g2` along with `-gsource-map`.
27+
See also the newly updated
28+
[documentation](https://emscripten.org/docs/porting/Debugging.html) which
29+
covers debugging flags and use cases (#25238).
2330

2431
4.0.14 - 09/02/25
2532
-----------------

test/test_browser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@ def test_sdl1_es6(self):
280280
self.reftest('hello_world_sdl.c', 'htmltest.png', cflags=['-sUSE_SDL', '-lGL', '-sEXPORT_ES6'])
281281

282282
def test_emscripten_log(self):
283-
self.btest_exit('test_emscripten_log.cpp', cflags=['-Wno-deprecated-pragma', '-gsource-map'])
283+
self.btest_exit('test_emscripten_log.cpp', cflags=['-Wno-deprecated-pragma', '-gsource-map', '-g2'])
284284

285285
@also_with_wasmfs
286286
def test_preload_file(self):

test/test_core.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8978,28 +8978,38 @@ def test_sanitize_vptr(self):
89788978
"which does not point to an object of type 'R'",
89798979
])
89808980

8981+
# The sanitizer runtime can symbolize based on dwarf, a name section, a sourcemap,
8982+
# or a combination.
89818983
@parameterized({
8982-
'g': ('-g', [
8984+
'g': (['-g'], [
89838985
".cpp:3:12: runtime error: reference binding to null pointer of type 'int'",
89848986
'in main',
89858987
]),
8986-
'g4': ('-gsource-map', [
8988+
'g2': (['-g2'], [
8989+
".cpp:3:12: runtime error: reference binding to null pointer of type 'int'",
8990+
'in main',
8991+
]),
8992+
'gsource_map': (['-gsource-map'], [
8993+
".cpp:3:12: runtime error: reference binding to null pointer of type 'int'",
8994+
'.cpp:3:8',
8995+
]),
8996+
'g4': (['-gsource-map', '-g2'], [
89878997
".cpp:3:12: runtime error: reference binding to null pointer of type 'int'",
89888998
'in main ',
89898999
'.cpp:3:8',
89909000
]),
89919001
})
89929002
@no_wasm2js('TODO: sanitizers in wasm2js')
89939003
@no_esm_integration('sanitizers do not support WASM_ESM_INTEGRATION')
8994-
def test_ubsan_full_stack_trace(self, g_flag, expected_output):
8995-
if g_flag == '-gsource-map':
9004+
def test_ubsan_full_stack_trace(self, g_flags, expected_output):
9005+
if '-gsource-map' in g_flags:
89969006
if self.is_wasm2js():
89979007
self.skipTest('wasm2js has no source map support')
89989008
elif self.get_setting('EVAL_CTORS'):
89999009
self.skipTest('EVAL_CTORS does not support source maps')
90009010

90019011
create_file('pre.js', 'Module.UBSAN_OPTIONS = "print_stacktrace=1";')
9002-
self.cflags += ['-fsanitize=null', g_flag, '--pre-js=pre.js']
9012+
self.cflags += ['-fsanitize=null', '--pre-js=pre.js'] + g_flags
90039013
self.set_setting('ALLOW_MEMORY_GROWTH')
90049014
self.do_runf('core/test_ubsan_full_null_ref.cpp',
90059015
assert_all=True, expected_output=expected_output)

test/test_other.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3145,21 +3145,23 @@ def test_dwarf_sourcemap_names(self):
31453145
(['-O1', '-g'], True, False, True),
31463146
(['-O3', '-g'], True, False, True),
31473147
(['-gsplit-dwarf'], True, False, True),
3148-
# TODO: It seems odd that -gsource-map leaves behind a name section. Should it?
3149-
(['-gsource-map'], False, True, True),
3150-
(['-g1', '-Oz', '-gsource-map'], False, True, True),
3148+
(['-gsource-map'], False, True, False),
3149+
(['-g2', '-gsource-map'], False, True, True),
3150+
(['-g1', '-Oz', '-gsource-map'], False, True, False),
31513151
(['-gsource-map', '-g0'], False, False, False),
31523152
# --emit-symbol-map should not affect the results
3153-
(['--emit-symbol-map', '-gsource-map'], False, True, True),
3153+
(['--emit-symbol-map', '-gsource-map'], False, True, False),
31543154
(['--emit-symbol-map'], False, False, False),
31553155
(['--emit-symbol-map', '-Oz'], False, False, False),
31563156
(['-sASYNCIFY=1', '-g0'], False, False, False),
3157-
(['-sASYNCIFY=1', '-gsource-map'], False, True, True),
3157+
(['-sASYNCIFY=1', '-gsource-map'], False, True, False),
3158+
(['-sASYNCIFY=1', '-gsource-map', '-g2'], False, True, True),
31583159
(['-g', '-gsource-map'], True, True, True),
31593160
(['-g2', '-gsource-map'], False, True, True),
31603161
(['-gsplit-dwarf', '-gsource-map'], True, True, True),
3161-
(['-gsource-map', '-sERROR_ON_WASM_CHANGES_AFTER_LINK'], False, True, True),
3162-
(['-Oz', '-gsource-map'], False, True, True),
3162+
(['-Oz', '-gsource-map'], False, True, False),
3163+
(['-gsource-map', '-sERROR_ON_WASM_CHANGES_AFTER_LINK'], False, True, False),
3164+
(['-gsource-map', '-Og', '-sERROR_ON_WASM_CHANGES_AFTER_LINK'], False, True, False),
31633165
]:
31643166
print(flags, expect_dwarf, expect_sourcemap, expect_names)
31653167
self.emcc(test_file(source_file), flags, js_file)
@@ -9250,19 +9252,22 @@ def test_binaryen_debug(self):
92509252
for args, expect_clean_js, expect_whitespace_js, expect_closured in [
92519253
(['-O0'], False, True, False),
92529254
(['-O0', '-g1'], False, True, False),
9253-
(['-O0', '-g2'], False, True, False), # in -g2+, we emit -g to asm2wasm so function names are saved
9255+
(['-O0', '-g2'], False, True, False),
92549256
(['-O0', '-g'], False, True, False),
92559257
(['-O0', '--profiling-funcs'], False, True, False),
92569258
(['-O0', '-gline-tables-only'], False, True, False),
92579259
(['-O1'], False, True, False),
92589260
(['-O3'], True, False, False),
9259-
(['-Oz', '-gsource-map'], False, True, False), # TODO: fix this (#20462)
9261+
(['-Oz', '-gsource-map'], True, False, False),
92609262
(['-O2'], True, False, False),
92619263
(['-O2', '-gz'], True, False, False), # -gz means debug compression, it should not enable debugging
92629264
(['-O2', '-g1'], False, True, False),
92639265
(['-O2', '-g'], False, True, False),
92649266
(['-O2', '--closure=1'], True, False, True),
92659267
(['-O2', '--closure=1', '-g1'], True, True, True),
9268+
(['-O2', '--minify=0'], False, True, False),
9269+
(['-O2', '--profiling-funcs'], True, False, False),
9270+
(['-O2', '--profiling'], False, True, False),
92669271
]:
92679272
print(args, expect_clean_js, expect_whitespace_js, expect_closured)
92689273
delete_file('a.out.wat')
@@ -12383,7 +12388,7 @@ def test_lsan_leaks(self, ext, args):
1238312388
def test_lsan_stack_trace(self, ext, regexes):
1238412389
self.do_runf(
1238512390
'other/test_lsan_leaks.' + ext,
12386-
cflags=['-fsanitize=leak', '-gsource-map'],
12391+
cflags=['-fsanitize=leak', '-gsource-map', '-g2'],
1238712392
regex=True,
1238812393
assert_all=True,
1238912394
assert_returncode=NON_ZERO,

tools/building.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1232,7 +1232,7 @@ def run_binaryen_command(tool, infile, outfile=None, args=None, debug=False, std
12321232
# we must tell binaryen to update it
12331233
# TODO: all tools should support source maps; wasm-ctor-eval does not atm,
12341234
# for example
1235-
if settings.GENERATE_SOURCE_MAP and outfile and tool in ['wasm-opt', 'wasm-emscripten-finalize']:
1235+
if settings.GENERATE_SOURCE_MAP and outfile and tool in ['wasm-opt', 'wasm-emscripten-finalize', 'wasm-metadce']:
12361236
cmd += [f'--input-source-map={infile}.map']
12371237
cmd += [f'--output-source-map={outfile}.map']
12381238
shared.print_compiler_stage(cmd)

tools/cmdline.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,8 @@ def consume_arg_file():
368368
settings.EMIT_NAME_SECTION = 1
369369
# if we don't need to preserve LLVM debug info, do not keep this flag
370370
# for clang
371-
if settings.DEBUG_LEVEL < 3:
371+
if (settings.DEBUG_LEVEL < 3 and not
372+
(settings.GENERATE_SOURCE_MAP or settings.SEPARATE_DWARF)):
372373
newargs[i] = '-g0'
373374
else:
374375
# for 3+, report -g3 to clang as -g4 etc. are not accepted
@@ -394,9 +395,9 @@ def consume_arg_file():
394395
else:
395396
settings.SEPARATE_DWARF = True
396397
settings.GENERATE_DWARF = 1
398+
settings.DEBUG_LEVEL = 3
397399
elif requested_level in ['source-map', 'source-map=inline']:
398400
settings.GENERATE_SOURCE_MAP = 1 if requested_level == 'source-map' else 2
399-
settings.EMIT_NAME_SECTION = 1
400401
newargs[i] = '-g'
401402
elif requested_level == 'z':
402403
# Ignore `-gz`. We don't support debug info compression.
@@ -407,10 +408,7 @@ def consume_arg_file():
407408
# clang and make the emscripten code treat it like any other DWARF.
408409
settings.GENERATE_DWARF = 1
409410
settings.EMIT_NAME_SECTION = 1
410-
# In all cases set the emscripten debug level to 3 so that we do not
411-
# strip during link (during compile, this does not make a difference).
412-
# TODO: possibly decouple some of these flags from the final debug level (#20462)
413-
settings.DEBUG_LEVEL = 3
411+
settings.DEBUG_LEVEL = 3
414412
elif check_flag('-profiling') or check_flag('--profiling'):
415413
settings.DEBUG_LEVEL = max(settings.DEBUG_LEVEL, 2)
416414
settings.EMIT_NAME_SECTION = 1

0 commit comments

Comments
 (0)