Skip to content

Commit d8ec08a

Browse files
authored
Make use of pathlib.Path when dealing with paths within emscripten. NFC (#14916)
This change is very much like that large change I made to the test suite. See #14191 and #14175. It enables is to use unix style paths rather than arrays of path components which has several advantages. As well as beeing more readable and writable it also allows for things like `git grep "musl/src"` to work as expected. For an example of how much more readable it makes the code see `tools/system_libs.py`. This change was made almost exclusively with a bunch of `sed` commands. Because there is likely some minor performance overhead I did some measurements. Running `./tests/runner wasm2 --skip-slow`: before: real 1m10.403s user 49m40.135s sys 6m14.466s after: real 1m10.397s user 49m43.849s sys 6m10.698s Running `./embuilder build libc --force`: before: real 0m5.597s user 3m2.721s sys 0m50.843s after: real 0m5.609s user 3m0.998s sys 0m49.796s
1 parent 60da014 commit d8ec08a

24 files changed

+153
-149
lines changed

emcc.py

+24-24
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939

4040
import emscripten
41-
from tools import shared, system_libs
41+
from tools import shared, system_libs, utils
4242
from tools import colored_logger, diagnostics, building
4343
from tools.shared import unsuffixed, unsuffixed_basename, WINDOWS, safe_copy
4444
from tools.shared import run_process, read_and_preprocess, exit_with_error, DEBUG
@@ -240,7 +240,7 @@ def __init__(self):
240240
self.embed_files = []
241241
self.exclude_files = []
242242
self.ignore_dynamic_linking = False
243-
self.shell_path = shared.path_from_root('src', 'shell.html')
243+
self.shell_path = utils.path_from_root('src/shell.html')
244244
self.source_map_base = ''
245245
self.emrun = False
246246
self.cpu_profiler = False
@@ -979,7 +979,7 @@ def run(args):
979979
# site/build/text/docs/tools_reference/emcc.txt
980980
# This then needs to be copied to its final home in docs/emcc.txt from where
981981
# we read it here. We have CI rules that ensure its always up-to-date.
982-
with open(shared.path_from_root('docs', 'emcc.txt'), 'r') as f:
982+
with open(utils.path_from_root('docs/emcc.txt'), 'r') as f:
983983
print(f.read())
984984

985985
print('''
@@ -1023,7 +1023,7 @@ def run(args):
10231023
args = [x for x in args if x != '--cflags']
10241024
with misc_temp_files.get_file(suffix='.o') as temp_target:
10251025
input_file = 'hello_world.c'
1026-
cmd = [shared.PYTHON, sys.argv[0], shared.path_from_root('tests', input_file), '-v', '-c', '-o', temp_target] + args
1026+
cmd = [shared.PYTHON, sys.argv[0], utils.path_from_root('tests', input_file), '-v', '-c', '-o', temp_target] + args
10271027
proc = run_process(cmd, stderr=PIPE, check=False)
10281028
if proc.returncode != 0:
10291029
print(proc.stderr)
@@ -1367,19 +1367,19 @@ def phase_linker_setup(options, state, newargs, settings_map):
13671367
add_link_flag(state, sys.maxsize, f)
13681368

13691369
if options.emrun:
1370-
options.pre_js += read_file(shared.path_from_root('src', 'emrun_prejs.js')) + '\n'
1371-
options.post_js += read_file(shared.path_from_root('src', 'emrun_postjs.js')) + '\n'
1370+
options.pre_js += read_file(utils.path_from_root('src/emrun_prejs.js')) + '\n'
1371+
options.post_js += read_file(utils.path_from_root('src/emrun_postjs.js')) + '\n'
13721372
# emrun mode waits on program exit
13731373
settings.EXIT_RUNTIME = 1
13741374

13751375
if options.cpu_profiler:
1376-
options.post_js += read_file(shared.path_from_root('src', 'cpuprofiler.js')) + '\n'
1376+
options.post_js += read_file(utils.path_from_root('src/cpuprofiler.js')) + '\n'
13771377

13781378
if options.memory_profiler:
13791379
settings.MEMORYPROFILER = 1
13801380

13811381
if options.thread_profiler:
1382-
options.post_js += read_file(shared.path_from_root('src', 'threadprofiler.js')) + '\n'
1382+
options.post_js += read_file(utils.path_from_root('src/threadprofiler.js')) + '\n'
13831383

13841384
if options.memory_init_file is None:
13851385
options.memory_init_file = settings.OPT_LEVEL >= 2
@@ -2030,8 +2030,8 @@ def check_memory_setting(setting):
20302030

20312031
if settings.MINIMAL_RUNTIME:
20322032
# Minimal runtime uses a different default shell file
2033-
if options.shell_path == shared.path_from_root('src', 'shell.html'):
2034-
options.shell_path = shared.path_from_root('src', 'shell_minimal_runtime.html')
2033+
if options.shell_path == utils.path_from_root('src/shell.html'):
2034+
options.shell_path = utils.path_from_root('src/shell_minimal_runtime.html')
20352035

20362036
if settings.EXIT_RUNTIME:
20372037
settings.DEFAULT_LIBRARY_FUNCS_TO_INCLUDE += ['proc_exit']
@@ -2045,7 +2045,7 @@ def check_memory_setting(setting):
20452045

20462046
if settings.MODULARIZE and not (settings.EXPORT_ES6 and not settings.SINGLE_FILE) and \
20472047
settings.EXPORT_NAME == 'Module' and options.oformat == OFormat.HTML and \
2048-
(options.shell_path == shared.path_from_root('src', 'shell.html') or options.shell_path == shared.path_from_root('src', 'shell_minimal.html')):
2048+
(options.shell_path == utils.path_from_root('src/shell.html') or options.shell_path == utils.path_from_root('src/shell_minimal.html')):
20492049
exit_with_error(f'Due to collision in variable name "Module", the shell file "{options.shell_path}" is not compatible with build options "-s MODULARIZE=1 -s EXPORT_NAME=Module". Either provide your own shell file, change the name of the export to something else to avoid the name collision. (see https://github.com/emscripten-core/emscripten/issues/7950 for details)')
20502050

20512051
if settings.STANDALONE_WASM:
@@ -2638,7 +2638,7 @@ def phase_final_emitting(options, state, target, wasm_target, memfile):
26382638
target_dir = os.path.dirname(os.path.abspath(target))
26392639
worker_output = os.path.join(target_dir, settings.PTHREAD_WORKER_FILE)
26402640
with open(worker_output, 'w') as f:
2641-
f.write(shared.read_and_preprocess(shared.path_from_root('src', 'worker.js'), expand_macros=True))
2641+
f.write(shared.read_and_preprocess(utils.path_from_root('src/worker.js'), expand_macros=True))
26422642

26432643
# Minify the worker.js file in optimized builds
26442644
if (settings.OPT_LEVEL >= 1 or settings.SHRINK_LEVEL >= 1) and not settings.DEBUG_LEVEL:
@@ -2659,7 +2659,7 @@ def phase_final_emitting(options, state, target, wasm_target, memfile):
26592659
# Process .js runtime file. Note that we need to handle the license text
26602660
# here, so that it will not confuse the hacky script.
26612661
shared.JS.handle_license(final_js)
2662-
shared.run_process([shared.PYTHON, shared.path_from_root('tools', 'hacky_postprocess_around_closure_limitations.py'), final_js])
2662+
shared.run_process([shared.PYTHON, utils.path_from_root('tools/hacky_postprocess_around_closure_limitations.py'), final_js])
26632663

26642664
# Unmangle previously mangled `import.meta` references in both main code and libraries.
26652665
# See also: `preprocess` in parseTools.js.
@@ -2717,13 +2717,13 @@ def version_string():
27172717
# if the emscripten folder is not a git repo, don't run git show - that can
27182718
# look up and find the revision in a parent directory that is a git repo
27192719
revision_suffix = ''
2720-
if os.path.exists(shared.path_from_root('.git')):
2720+
if os.path.exists(utils.path_from_root('.git')):
27212721
git_rev = run_process(
27222722
['git', 'rev-parse', 'HEAD'],
2723-
stdout=PIPE, stderr=PIPE, cwd=shared.path_from_root()).stdout.strip()
2723+
stdout=PIPE, stderr=PIPE, cwd=utils.path_from_root()).stdout.strip()
27242724
revision_suffix = '-git (%s)' % git_rev
2725-
elif os.path.exists(shared.path_from_root('emscripten-revision.txt')):
2726-
with open(shared.path_from_root('emscripten-revision.txt')) as f:
2725+
elif os.path.exists(utils.path_from_root('emscripten-revision.txt')):
2726+
with open(utils.path_from_root('emscripten-revision.txt')) as f:
27272727
git_rev = f.read().strip()
27282728
revision_suffix = ' (%s)' % git_rev
27292729
return f'emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) {shared.EMSCRIPTEN_VERSION}{revision_suffix}'
@@ -3163,7 +3163,7 @@ def phase_binaryen(target, options, wasm_target):
31633163
building.asyncify_lazy_load_code(wasm_target, debug=intermediate_debug_info)
31643164

31653165
def preprocess_wasm2js_script():
3166-
return read_and_preprocess(shared.path_from_root('src', 'wasm2js.js'), expand_macros=True)
3166+
return read_and_preprocess(utils.path_from_root('src/wasm2js.js'), expand_macros=True)
31673167

31683168
def run_closure_compiler():
31693169
global final_js
@@ -3441,7 +3441,7 @@ def generate_traditional_runtime_html(target, options, js_target, target_basenam
34413441
# when script.inline isn't empty, add required helper functions such as tryParseAsDataURI
34423442
if script.inline:
34433443
for filename in ('arrayUtils.js', 'base64Utils.js', 'URIUtils.js'):
3444-
content = read_and_preprocess(shared.path_from_root('src', filename))
3444+
content = read_and_preprocess(utils.path_from_root('src', filename))
34453445
script.inline = content + script.inline
34463446

34473447
script.inline = 'var ASSERTIONS = %s;\n%s' % (settings.ASSERTIONS, script.inline)
@@ -3516,7 +3516,7 @@ def generate_html(target, options, js_target, target_basename,
35163516

35173517
if settings.EXPORT_NAME != 'Module' and \
35183518
not settings.MINIMAL_RUNTIME and \
3519-
options.shell_path == shared.path_from_root('src', 'shell.html'):
3519+
options.shell_path == utils.path_from_root('src/shell.html'):
35203520
# the minimal runtime shell HTML is designed to support changing the export
35213521
# name, but the normal one does not support that currently
35223522
exit_with_error('Customizing EXPORT_NAME requires that the HTML be customized to use that name (see https://github.com/emscripten-core/emscripten/issues/10086)')
@@ -3547,9 +3547,9 @@ def generate_worker_js(target, js_target, target_basename):
35473547

35483548

35493549
def worker_js_script(proxy_worker_filename):
3550-
web_gl_client_src = read_file(shared.path_from_root('src', 'webGLClient.js'))
3551-
idb_store_src = read_file(shared.path_from_root('src', 'IDBStore.js'))
3552-
proxy_client_src = read_file(shared.path_from_root('src', 'proxyClient.js'))
3550+
web_gl_client_src = read_file(utils.path_from_root('src/webGLClient.js'))
3551+
idb_store_src = read_file(utils.path_from_root('src/IDBStore.js'))
3552+
proxy_client_src = read_file(utils.path_from_root('src/proxyClient.js'))
35533553
proxy_client_src = do_replace(proxy_client_src, '{{{ filename }}}', proxy_worker_filename)
35543554
proxy_client_src = do_replace(proxy_client_src, '{{{ IDBStore.js }}}', idb_store_src)
35553555
return web_gl_client_src + '\n' + proxy_client_src
@@ -3662,7 +3662,7 @@ def replacement(self):
36623662

36633663
def is_valid_abspath(options, path_name):
36643664
# Any path that is underneath the emscripten repository root must be ok.
3665-
if shared.path_from_root().replace('\\', '/') in path_name.replace('\\', '/'):
3665+
if utils.path_from_root().replace('\\', '/') in path_name.replace('\\', '/'):
36663666
return True
36673667

36683668
def in_directory(root, child):

emcmake.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ def has_substr(args, substr):
3333

3434
# Append the Emscripten toolchain file if the user didn't specify one.
3535
if not has_substr(args, '-DCMAKE_TOOLCHAIN_FILE'):
36-
args.append('-DCMAKE_TOOLCHAIN_FILE=' + utils.path_from_root('cmake', 'Modules', 'Platform', 'Emscripten.cmake'))
36+
args.append('-DCMAKE_TOOLCHAIN_FILE=' + utils.path_from_root('cmake/Modules/Platform/Emscripten.cmake'))
3737

3838
if not has_substr(args, '-DCMAKE_CROSSCOMPILING_EMULATOR'):
3939
node_js = config.NODE_JS[0]

emscons.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
import os
1212
import subprocess
1313
import sys
14-
from tools import shared
14+
from tools import utils
1515

16-
tool_path = os.path.join(shared.path_from_root('tools'), 'scons', 'site_scons', 'site_tools', 'emscripten')
16+
tool_path = utils.path_from_root('tools/scons/site_scons/site_tools/emscripten')
1717

1818
env = os.environ.copy()
1919
env['EMSCRIPTEN_TOOL_PATH'] = tool_path

emscripten.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ def compile_settings():
174174
# Call js compiler
175175
env = os.environ.copy()
176176
env['EMCC_BUILD_DIR'] = os.getcwd()
177-
out = shared.run_js_tool(path_from_root('src', 'compiler.js'),
177+
out = shared.run_js_tool(path_from_root('src/compiler.js'),
178178
[settings_file], stdout=subprocess.PIPE, stderr=stderr_file,
179179
cwd=path_from_root('src'), env=env)
180180
assert '//FORWARDED_DATA:' in out, 'Did not receive forwarded data in pre output - process failed?'

tests/clang_native.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
# These extra args need to be passed to Clang when targeting a native host system executable
1515
def get_clang_native_args():
1616
if MACOS:
17-
return ['-isystem', path_from_root('system', 'include', 'libcxx')]
17+
return ['-isystem', path_from_root('system/include/libcxx')]
1818
elif os.name == 'nt':
1919
# TODO: If Windows.h et al. are needed, will need to add something like '-isystemC:/Program
2020
# Files (x86)/Microsoft SDKs/Windows/v7.1A/Include'.

tests/fuzz/csmith_driver.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
from tools import shared
2323
from tools import config
24+
from tools import utils
2425

2526
# can add flags like --no-threads --ion-offthread-compile=off
2627
engine = eval('config.' + sys.argv[1]) if len(sys.argv) > 1 else config.JS_ENGINES[0]
@@ -84,7 +85,7 @@
8485
continue
8586

8687
shared.run_process([COMP, '-m32', opts, '-emit-llvm', '-c', fullname, '-o', filename + '.bc'] + CSMITH_CFLAGS + shared.get_cflags() + ['-w'])
87-
shared.run_process([shared.path_from_root('tools', 'nativize_llvm.py'), filename + '.bc'], stderr=PIPE)
88+
shared.run_process([utils.path_from_root('tools/nativize_llvm.py'), filename + '.bc'], stderr=PIPE)
8889
shutil.move(filename + '.bc.run', filename + '2')
8990
shared.run_process([COMP, fullname, '-o', filename + '3'] + CSMITH_CFLAGS + ['-w'])
9091
print('3) Run natively')

tests/jsrun.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import common
1010
from subprocess import Popen, PIPE, CalledProcessError
1111

12-
from tools import shared
12+
from tools import shared, utils
1313

1414
WORKING_ENGINES = {} # Holds all configured engines and whether they work: maps path -> True/False
1515

@@ -59,7 +59,7 @@ def check_engine(engine):
5959
if engine_path not in WORKING_ENGINES:
6060
logging.debug('Checking JS engine %s' % engine)
6161
try:
62-
output = run_js(shared.path_from_root('tests/hello_world.js'), engine, skip_check=True)
62+
output = run_js(utils.path_from_root('tests/hello_world.js'), engine, skip_check=True)
6363
if 'hello, world!' in output:
6464
WORKING_ENGINES[engine_path] = True
6565
else:

tests/runner.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@
3737
import jsrun
3838
import parallel_testsuite
3939
import common
40-
from tools import shared, config
40+
from tools import shared, config, utils
4141

4242

43-
sys.path.append(shared.path_from_root('third_party/websockify'))
43+
sys.path.append(utils.path_from_root('third_party/websockify'))
4444

4545
logger = logging.getLogger("runner")
4646

tests/test_browser.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ def test_zzz_html_source_map(self):
231231

232232
def test_emscripten_log(self):
233233
self.btest_exit(test_file('emscripten_log/emscripten_log.cpp'),
234-
args=['--pre-js', path_from_root('src', 'emscripten-source-map.min.js'), '-gsource-map'])
234+
args=['--pre-js', path_from_root('src/emscripten-source-map.min.js'), '-gsource-map'])
235235

236236
def test_preload_file(self):
237237
create_file('somefile.txt', 'load me right before running the code please')
@@ -574,7 +574,7 @@ def test_custom_file_package_url(self):
574574
# change the file package base dir to look in a "cdn". note that normally
575575
# you would add this in your own custom html file etc., and not by
576576
# modifying the existing shell in this manner
577-
default_shell = read_file(path_from_root('src', 'shell.html'))
577+
default_shell = read_file(path_from_root('src/shell.html'))
578578
create_file('shell.html', default_shell.replace('var Module = {', '''
579579
var Module = {
580580
locateFile: function(path, prefix) {
@@ -668,7 +668,7 @@ def test():
668668
test()
669669

670670
# TODO: CORS, test using a full url for locateFile
671-
# create_file('shell.html', read_file(path_from_root('src', 'shell.html')).replace('var Module = {', 'var Module = { locateFile: function (path) {return "http:/localhost:8888/cdn/" + path;}, '))
671+
# create_file('shell.html', read_file(path_from_root('src/shell.html')).replace('var Module = {', 'var Module = { locateFile: function (path) {return "http:/localhost:8888/cdn/" + path;}, '))
672672
# test()
673673

674674
def test_dev_random(self):
@@ -3683,7 +3683,7 @@ def test_memory_growth_during_startup(self):
36833683
# pthreads tests
36843684

36853685
def prep_no_SAB(self):
3686-
create_file('html.html', read_file(path_from_root('src', 'shell_minimal.html')).replace('''<body>''', '''<body>
3686+
create_file('html.html', read_file(path_from_root('src/shell_minimal.html')).replace('''<body>''', '''<body>
36873687
<script>
36883688
SharedArrayBuffer = undefined;
36893689
Atomics = undefined;
@@ -3992,15 +3992,15 @@ def test_pthread_custom_pthread_main_url(self):
39923992
''')
39933993

39943994
# Test that it is possible to define "Module.locateFile" string to locate where worker.js will be loaded from.
3995-
create_file('shell.html', read_file(path_from_root('src', 'shell.html')).replace('var Module = {', 'var Module = { locateFile: function (path, prefix) {if (path.endsWith(".wasm")) {return prefix + path;} else {return "cdn/" + path;}}, '))
3995+
create_file('shell.html', read_file(path_from_root('src/shell.html')).replace('var Module = {', 'var Module = { locateFile: function (path, prefix) {if (path.endsWith(".wasm")) {return prefix + path;} else {return "cdn/" + path;}}, '))
39963996
self.compile_btest(['main.cpp', '--shell-file', 'shell.html', '-s', 'WASM=0', '-s', 'IN_TEST_HARNESS', '-s', 'USE_PTHREADS', '-s', 'PTHREAD_POOL_SIZE', '-o', 'test.html'], reporting=Reporting.JS_ONLY)
39973997
shutil.move('test.worker.js', Path('cdn/test.worker.js'))
39983998
if os.path.exists('test.html.mem'):
39993999
shutil.copyfile('test.html.mem', Path('cdn/test.html.mem'))
40004000
self.run_browser('test.html', '', '/report_result?exit:0')
40014001

40024002
# Test that it is possible to define "Module.locateFile(foo)" function to locate where worker.js will be loaded from.
4003-
create_file('shell2.html', read_file(path_from_root('src', 'shell.html')).replace('var Module = {', 'var Module = { locateFile: function(filename) { if (filename == "test.worker.js") return "cdn/test.worker.js"; else return filename; }, '))
4003+
create_file('shell2.html', read_file(path_from_root('src/shell.html')).replace('var Module = {', 'var Module = { locateFile: function(filename) { if (filename == "test.worker.js") return "cdn/test.worker.js"; else return filename; }, '))
40044004
self.compile_btest(['main.cpp', '--shell-file', 'shell2.html', '-s', 'WASM=0', '-s', 'IN_TEST_HARNESS', '-s', 'USE_PTHREADS', '-s', 'PTHREAD_POOL_SIZE', '-o', 'test2.html'], reporting=Reporting.JS_ONLY)
40054005
try_delete('test.worker.js')
40064006
self.run_browser('test2.html', '', '/report_result?exit:0')
@@ -4268,7 +4268,7 @@ def test_manual_wasm_instantiate(self, args=[]):
42684268
def test_wasm_locate_file(self):
42694269
# Test that it is possible to define "Module.locateFile(foo)" function to locate where worker.js will be loaded from.
42704270
ensure_dir('cdn')
4271-
create_file('shell2.html', read_file(path_from_root('src', 'shell.html')).replace('var Module = {', 'var Module = { locateFile: function(filename) { if (filename == "test.wasm") return "cdn/test.wasm"; else return filename; }, '))
4271+
create_file('shell2.html', read_file(path_from_root('src/shell.html')).replace('var Module = {', 'var Module = { locateFile: function(filename) { if (filename == "test.wasm") return "cdn/test.wasm"; else return filename; }, '))
42724272
self.compile_btest([test_file('browser_test_hello_world.c'), '--shell-file', 'shell2.html', '-o', 'test.html'])
42734273
shutil.move('test.wasm', Path('cdn/test.wasm'))
42744274
self.run_browser('test.html', '', '/report_result?0')
@@ -4863,7 +4863,7 @@ def test_unicode_html_shell(self):
48634863
return 0;
48644864
}
48654865
''')
4866-
create_file('shell.html', read_file(path_from_root('src', 'shell.html')).replace('Emscripten-Generated Code', 'Emscripten-Generated Emoji 😅'))
4866+
create_file('shell.html', read_file(path_from_root('src/shell.html')).replace('Emscripten-Generated Code', 'Emscripten-Generated Emoji 😅'))
48674867
self.btest_exit('main.cpp', args=['--shell-file', 'shell.html'])
48684868

48694869
# Tests the functionality of the emscripten_thread_sleep() function.

tests/test_sockets.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ def test_websocket_send(self):
364364
# Test that native POSIX sockets API can be used by proxying calls to an intermediate WebSockets -> POSIX sockets bridge server
365365
def test_posix_proxy_sockets(self):
366366
# Build the websocket bridge server
367-
self.run_process(['cmake', path_from_root('tools', 'websocket_to_posix_proxy')])
367+
self.run_process(['cmake', path_from_root('tools/websocket_to_posix_proxy')])
368368
self.run_process(['cmake', '--build', '.'])
369369
if os.name == 'nt': # This is not quite exact, instead of "isWindows()" this should be "If CMake defaults to building with Visual Studio", but there is no good check for that, so assume Windows==VS.
370370
proxy_server = os.path.join(self.get_dir(), 'Debug', 'websocket_to_posix_proxy.exe')

third_party/websockify/websockify.py

-1
This file was deleted.

third_party/websockify/websockify.py

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env python
2+
3+
import websockify
4+
5+
websockify.websocketproxy.websockify_init()

0 commit comments

Comments
 (0)