Skip to content

Commit 0331e82

Browse files
authored
Move clang flags handling to new compile.py file. NFC (#24880)
This mirrors the existing `link.py` file. My plan is to make use of these functions to call clang directly when building the system libs.
1 parent 174dca8 commit 0331e82

File tree

3 files changed

+157
-131
lines changed

3 files changed

+157
-131
lines changed

emcc.py

Lines changed: 8 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,18 @@
3333
from subprocess import PIPE
3434

3535

36-
from tools import shared, system_libs, utils, ports, cmdline
37-
from tools import diagnostics, building
36+
from tools import shared, system_libs, utils, cmdline
37+
from tools import diagnostics, building, compile
3838
from tools.shared import unsuffixed, unsuffixed_basename, get_file_suffix
3939
from tools.shared import run_process, exit_with_error, DEBUG
4040
from tools.shared import in_temp
4141
from tools.shared import DYLIB_EXTENSIONS
42-
from tools.cmdline import SIMD_INTEL_FEATURE_TOWER, SIMD_NEON_FLAGS, CLANG_FLAGS_WITH_ARGS
42+
from tools.cmdline import CLANG_FLAGS_WITH_ARGS
4343
from tools.response_file import substitute_response_files
4444
from tools import config
4545
from tools import cache
4646
from tools.settings import default_setting, user_settings, settings, COMPILE_TIME_SETTINGS
47-
from tools.utils import read_file, memoize
47+
from tools.utils import read_file
4848

4949
logger = logging.getLogger('emcc')
5050

@@ -171,126 +171,6 @@ def cxx_to_c_compiler(cxx):
171171
return os.path.join(dirname, basename)
172172

173173

174-
def get_target_flags():
175-
return ['-target', shared.get_llvm_target()]
176-
177-
178-
def get_clang_flags(user_args):
179-
flags = get_target_flags()
180-
181-
# if exception catching is disabled, we can prevent that code from being
182-
# generated in the frontend
183-
if settings.DISABLE_EXCEPTION_CATCHING and not settings.WASM_EXCEPTIONS:
184-
flags.append('-fignore-exceptions')
185-
186-
if settings.INLINING_LIMIT:
187-
flags.append('-fno-inline-functions')
188-
189-
if settings.PTHREADS:
190-
if '-pthread' not in user_args:
191-
flags.append('-pthread')
192-
elif settings.SHARED_MEMORY:
193-
if '-matomics' not in user_args:
194-
flags.append('-matomics')
195-
if '-mbulk-memory' not in user_args:
196-
flags.append('-mbulk-memory')
197-
198-
if settings.RELOCATABLE and '-fPIC' not in user_args:
199-
flags.append('-fPIC')
200-
201-
if settings.RELOCATABLE or settings.LINKABLE or '-fPIC' in user_args:
202-
if not any(a.startswith('-fvisibility') for a in user_args):
203-
# For relocatable code we default to visibility=default in emscripten even
204-
# though the upstream backend defaults visibility=hidden. This matches the
205-
# expectations of C/C++ code in the wild which expects undecorated symbols
206-
# to be exported to other DSO's by default.
207-
flags.append('-fvisibility=default')
208-
209-
if settings.LTO:
210-
if not any(a.startswith('-flto') for a in user_args):
211-
flags.append('-flto=' + settings.LTO)
212-
# setjmp/longjmp handling using Wasm EH
213-
# For non-LTO, '-mllvm -wasm-enable-eh' added in
214-
# building.llvm_backend_args() sets this feature in clang. But in LTO, the
215-
# argument is added to wasm-ld instead, so clang needs to know that EH is
216-
# enabled so that it can be added to the attributes in LLVM IR.
217-
if settings.SUPPORT_LONGJMP == 'wasm':
218-
flags.append('-mexception-handling')
219-
220-
else:
221-
# In LTO mode these args get passed instead at link time when the backend runs.
222-
for a in building.llvm_backend_args():
223-
flags += ['-mllvm', a]
224-
225-
return flags
226-
227-
228-
@memoize
229-
def get_cflags(user_args):
230-
# Flags we pass to the compiler when building C/C++ code
231-
# We add these to the user's flags (newargs), but not when building .s or .S assembly files
232-
cflags = get_clang_flags(user_args)
233-
cflags.append('--sysroot=' + cache.get_sysroot(absolute=True))
234-
235-
if settings.EMSCRIPTEN_TRACING:
236-
cflags.append('-D__EMSCRIPTEN_TRACING__=1')
237-
238-
if settings.SHARED_MEMORY:
239-
cflags.append('-D__EMSCRIPTEN_SHARED_MEMORY__=1')
240-
241-
if settings.WASM_WORKERS:
242-
cflags.append('-D__EMSCRIPTEN_WASM_WORKERS__=1')
243-
244-
if not settings.STRICT:
245-
# The preprocessor define EMSCRIPTEN is deprecated. Don't pass it to code
246-
# in strict mode. Code should use the define __EMSCRIPTEN__ instead.
247-
cflags.append('-DEMSCRIPTEN')
248-
249-
ports.add_cflags(cflags, settings)
250-
251-
def array_contains_any_of(hay, needles):
252-
for n in needles:
253-
if n in hay:
254-
return True
255-
256-
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER) or array_contains_any_of(user_args, SIMD_NEON_FLAGS):
257-
if '-msimd128' not in user_args and '-mrelaxed-simd' not in user_args:
258-
exit_with_error('passing any of ' + ', '.join(SIMD_INTEL_FEATURE_TOWER + SIMD_NEON_FLAGS) + ' flags also requires passing -msimd128 (or -mrelaxed-simd)!')
259-
cflags += ['-D__SSE__=1']
260-
261-
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER[1:]):
262-
cflags += ['-D__SSE2__=1']
263-
264-
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER[2:]):
265-
cflags += ['-D__SSE3__=1']
266-
267-
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER[3:]):
268-
cflags += ['-D__SSSE3__=1']
269-
270-
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER[4:]):
271-
cflags += ['-D__SSE4_1__=1']
272-
273-
# Handle both -msse4.2 and its alias -msse4.
274-
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER[5:]):
275-
cflags += ['-D__SSE4_2__=1']
276-
277-
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER[7:]):
278-
cflags += ['-D__AVX__=1']
279-
280-
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER[8:]):
281-
cflags += ['-D__AVX2__=1']
282-
283-
if array_contains_any_of(user_args, SIMD_NEON_FLAGS):
284-
cflags += ['-D__ARM_NEON__=1']
285-
286-
if '-nostdinc' not in user_args:
287-
if not settings.USE_SDL:
288-
cflags += ['-Xclang', '-iwithsysroot' + os.path.join('/include', 'fakesdl')]
289-
cflags += ['-Xclang', '-iwithsysroot' + os.path.join('/include', 'compat')]
290-
291-
return cflags
292-
293-
294174
def get_library_basename(filename):
295175
"""Similar to get_file_suffix this strips off all numeric suffixes and then
296176
then final non-numeric one. For example for 'libz.so.1.2.8' returns 'libz'"""
@@ -319,7 +199,7 @@ def run(args):
319199
if len(args) == 2 and args[1] == '-v':
320200
# autoconf likes to see 'GNU' in the output to enable shared object support
321201
print(cmdline.version_string(), file=sys.stderr)
322-
return shared.check_call([clang, '-v'] + get_target_flags(), check=False).returncode
202+
return shared.check_call([clang, '-v'] + compile.get_target_flags(), check=False).returncode
323203

324204
# Additional compiler flags that we treat as if they were passed to us on the
325205
# commandline
@@ -652,13 +532,13 @@ def phase_compile_inputs(options, state, newargs):
652532
system_libs.ensure_sysroot()
653533

654534
def get_clang_command():
655-
return compiler + get_cflags(state.orig_args)
535+
return compiler + compile.get_cflags(state.orig_args)
656536

657537
def get_clang_command_preprocessed():
658-
return compiler + get_clang_flags(state.orig_args)
538+
return compiler + compile.get_clang_flags(state.orig_args)
659539

660540
def get_clang_command_asm():
661-
return compiler + get_target_flags()
541+
return compiler + compile.get_target_flags()
662542

663543
if state.mode == Mode.COMPILE_ONLY:
664544
if options.output_file and get_file_suffix(options.output_file) == '.bc' and not settings.LTO and '-emit-llvm' not in state.orig_args:

emscan-deps.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@
1010
"""
1111

1212
import sys
13-
import emcc
14-
from tools import shared, cmdline
13+
14+
from tools import shared, cmdline, compile
1515

1616
argv = sys.argv[1:]
1717

1818
# Parse and discard any emcc-specific flags (e.g. -sXXX).
1919
newargs = cmdline.parse_arguments(argv)[1]
2020

2121
# Add any clang flags that emcc would add.
22-
newargs += emcc.get_cflags(tuple(argv))
22+
newargs += compile.get_cflags(tuple(argv))
2323

2424
shared.exec_process([shared.CLANG_SCAN_DEPS] + newargs)

tools/compile.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
#!/usr/bin/env python3
2+
# Copyright 2025 The Emscripten Authors. All rights reserved.
3+
# Emscripten is available under two separate licenses, the MIT license and the
4+
# University of Illinois/NCSA Open Source License. Both these licenses can be
5+
# found in the LICENSE file.
6+
7+
"""The functions in this file define the compiler flags that emcc passes to clang.
8+
9+
There are three different levels of flags, each one a superset of the next:
10+
11+
get_target_flags(): Defines just `-target` flags and should always be
12+
used when calling clang, or any other llvm tool.
13+
14+
get_clang_flags(): In addition to the target flags this function returns all the
15+
required compiler flags.
16+
17+
get_cflags(): In addition to compiler flags this function also returns pre-processor
18+
flags. For example, include paths and macro defintions.
19+
"""
20+
21+
import os
22+
23+
from . cmdline import SIMD_INTEL_FEATURE_TOWER, SIMD_NEON_FLAGS
24+
from . import shared, building, cache, ports
25+
from . settings import settings
26+
from . utils import memoize
27+
28+
29+
def get_target_flags():
30+
return ['-target', shared.get_llvm_target()]
31+
32+
33+
def get_clang_flags(user_args):
34+
flags = get_target_flags()
35+
36+
# if exception catching is disabled, we can prevent that code from being
37+
# generated in the frontend
38+
if settings.DISABLE_EXCEPTION_CATCHING and not settings.WASM_EXCEPTIONS:
39+
flags.append('-fignore-exceptions')
40+
41+
if settings.INLINING_LIMIT:
42+
flags.append('-fno-inline-functions')
43+
44+
if settings.PTHREADS:
45+
if '-pthread' not in user_args:
46+
flags.append('-pthread')
47+
elif settings.SHARED_MEMORY:
48+
if '-matomics' not in user_args:
49+
flags.append('-matomics')
50+
if '-mbulk-memory' not in user_args:
51+
flags.append('-mbulk-memory')
52+
53+
if settings.RELOCATABLE and '-fPIC' not in user_args:
54+
flags.append('-fPIC')
55+
56+
if settings.RELOCATABLE or settings.LINKABLE or '-fPIC' in user_args:
57+
if not any(a.startswith('-fvisibility') for a in user_args):
58+
# For relocatable code we default to visibility=default in emscripten even
59+
# though the upstream backend defaults visibility=hidden. This matches the
60+
# expectations of C/C++ code in the wild which expects undecorated symbols
61+
# to be exported to other DSO's by default.
62+
flags.append('-fvisibility=default')
63+
64+
if settings.LTO:
65+
if not any(a.startswith('-flto') for a in user_args):
66+
flags.append('-flto=' + settings.LTO)
67+
# setjmp/longjmp handling using Wasm EH
68+
# For non-LTO, '-mllvm -wasm-enable-eh' added in
69+
# building.llvm_backend_args() sets this feature in clang. But in LTO, the
70+
# argument is added to wasm-ld instead, so clang needs to know that EH is
71+
# enabled so that it can be added to the attributes in LLVM IR.
72+
if settings.SUPPORT_LONGJMP == 'wasm':
73+
flags.append('-mexception-handling')
74+
75+
else:
76+
# In LTO mode these args get passed instead at link time when the backend runs.
77+
for a in building.llvm_backend_args():
78+
flags += ['-mllvm', a]
79+
80+
return flags
81+
82+
83+
@memoize
84+
def get_cflags(user_args):
85+
# Flags we pass to the compiler when building C/C++ code
86+
# We add these to the user's flags (newargs), but not when building .s or .S assembly files
87+
cflags = get_clang_flags(user_args)
88+
cflags.append('--sysroot=' + cache.get_sysroot(absolute=True))
89+
90+
if settings.EMSCRIPTEN_TRACING:
91+
cflags.append('-D__EMSCRIPTEN_TRACING__=1')
92+
93+
if settings.SHARED_MEMORY:
94+
cflags.append('-D__EMSCRIPTEN_SHARED_MEMORY__=1')
95+
96+
if settings.WASM_WORKERS:
97+
cflags.append('-D__EMSCRIPTEN_WASM_WORKERS__=1')
98+
99+
if not settings.STRICT:
100+
# The preprocessor define EMSCRIPTEN is deprecated. Don't pass it to code
101+
# in strict mode. Code should use the define __EMSCRIPTEN__ instead.
102+
cflags.append('-DEMSCRIPTEN')
103+
104+
ports.add_cflags(cflags, settings)
105+
106+
def array_contains_any_of(hay, needles):
107+
for n in needles:
108+
if n in hay:
109+
return True
110+
111+
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER) or array_contains_any_of(user_args, SIMD_NEON_FLAGS):
112+
if '-msimd128' not in user_args and '-mrelaxed-simd' not in user_args:
113+
shared.exit_with_error('passing any of ' + ', '.join(SIMD_INTEL_FEATURE_TOWER + SIMD_NEON_FLAGS) + ' flags also requires passing -msimd128 (or -mrelaxed-simd)!')
114+
cflags += ['-D__SSE__=1']
115+
116+
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER[1:]):
117+
cflags += ['-D__SSE2__=1']
118+
119+
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER[2:]):
120+
cflags += ['-D__SSE3__=1']
121+
122+
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER[3:]):
123+
cflags += ['-D__SSSE3__=1']
124+
125+
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER[4:]):
126+
cflags += ['-D__SSE4_1__=1']
127+
128+
# Handle both -msse4.2 and its alias -msse4.
129+
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER[5:]):
130+
cflags += ['-D__SSE4_2__=1']
131+
132+
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER[7:]):
133+
cflags += ['-D__AVX__=1']
134+
135+
if array_contains_any_of(user_args, SIMD_INTEL_FEATURE_TOWER[8:]):
136+
cflags += ['-D__AVX2__=1']
137+
138+
if array_contains_any_of(user_args, SIMD_NEON_FLAGS):
139+
cflags += ['-D__ARM_NEON__=1']
140+
141+
if '-nostdinc' not in user_args:
142+
if not settings.USE_SDL:
143+
cflags += ['-Xclang', '-iwithsysroot' + os.path.join('/include', 'fakesdl')]
144+
cflags += ['-Xclang', '-iwithsysroot' + os.path.join('/include', 'compat')]
145+
146+
return cflags

0 commit comments

Comments
 (0)