Skip to content

Commit 964fc9a

Browse files
authored
Use stdin to pass settings to compiler.mjs / preprocessor.mjs (emscripten-core#23650)
This avoids writing more files to disc than we need to. One of my hopes here is that this will be a little more performant, especially on windows, where the filesystem isn't the fastest. In order to aid debugging we stash copied of the these generated settings using the save_intermediate mechanism.
1 parent 734376a commit 964fc9a

File tree

8 files changed

+63
-44
lines changed

8 files changed

+63
-44
lines changed

test/test_other.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2969,7 +2969,7 @@ def test_emcc_debug_files(self, opt):
29692969
self.assertFalse(os.path.exists(self.canonical_temp_dir))
29702970
else:
29712971
print(sorted(os.listdir(self.canonical_temp_dir)))
2972-
self.assertExists(os.path.join(self.canonical_temp_dir, 'emcc-02-original.js'))
2972+
self.assertExists(os.path.join(self.canonical_temp_dir, 'emcc-04-original.js'))
29732973

29742974
def test_debuginfo_line_tables_only(self):
29752975
def test(do_compile):

tools/building.py

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,16 +1224,45 @@ def run_wasm_opt(infile, outfile=None, args=[], **kwargs): # noqa
12241224
return run_binaryen_command('wasm-opt', infile, outfile, args=args, **kwargs)
12251225

12261226

1227-
def save_intermediate(src, dst):
1227+
intermediate_counter = 0
1228+
1229+
1230+
def new_intermediate_filename(name):
1231+
assert DEBUG
1232+
global intermediate_counter
1233+
basename = 'emcc-%02d-%s' % (intermediate_counter, name)
1234+
intermediate_counter += 1
1235+
filename = os.path.join(shared.CANONICAL_TEMP_DIR, basename)
1236+
logger.debug('saving intermediate file %s' % filename)
1237+
return filename
1238+
1239+
1240+
def save_intermediate(src, name):
1241+
"""Copy an existing file CANONICAL_TEMP_DIR"""
12281242
if DEBUG:
1229-
dst = 'emcc-%02d-%s' % (save_intermediate.counter, dst)
1230-
save_intermediate.counter += 1
1231-
dst = os.path.join(shared.CANONICAL_TEMP_DIR, dst)
1232-
logger.debug('saving debug copy %s' % dst)
1233-
shutil.copyfile(src, dst)
1243+
shutil.copyfile(src, new_intermediate_filename(name))
1244+
1245+
1246+
def write_intermediate(content, name):
1247+
"""Generate a new debug file CANONICAL_TEMP_DIR"""
1248+
if DEBUG:
1249+
utils.write_file(new_intermediate_filename(name), content)
1250+
1251+
1252+
def read_and_preprocess(filename, expand_macros=False):
1253+
# Create a settings file with the current settings to pass to the JS preprocessor
1254+
settings_json = json.dumps(settings.external_dict(), sort_keys=True, indent=2)
1255+
write_intermediate(settings_json, 'settings.json')
12341256

1257+
# Run the JS preprocessor
1258+
dirname, filename = os.path.split(filename)
1259+
if not dirname:
1260+
dirname = None
1261+
args = ['-', filename]
1262+
if expand_macros:
1263+
args += ['--expand-macros']
12351264

1236-
save_intermediate.counter = 0 # type: ignore
1265+
return shared.run_js_tool(path_from_root('tools/preprocessor.mjs'), args, input=settings_json, stdout=subprocess.PIPE, cwd=dirname)
12371266

12381267

12391268
def js_legalization_pass_flags():

tools/compiler.mjs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,12 @@ Usage: compiler.mjs <settings.json> [-o out.js] [--symbols-only]`);
3737
}
3838

3939
// Load settings from JSON passed on the command line
40-
const settingsFile = positionals[0];
40+
let settingsFile = positionals[0];
4141
assert(settingsFile, 'settings file not specified');
42+
if (settingsFile == '-') {
43+
// Read settings json from stdin (FD 0)
44+
settingsFile = 0;
45+
}
4246
const userSettings = JSON.parse(readFile(settingsFile));
4347
applySettings(userSettings);
4448

tools/emscripten.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -182,16 +182,15 @@ def compile_javascript(symbols_only=False):
182182
stderr_file = open(stderr_file, 'w')
183183

184184
# Save settings to a file to work around v8 issue 1579
185-
with shared.get_temp_files().get_file('.json') as settings_file:
186-
with open(settings_file, 'w') as s:
187-
json.dump(settings.external_dict(), s, sort_keys=True, indent=2)
188-
189-
# Call js compiler
190-
args = [settings_file]
191-
if symbols_only:
192-
args += ['--symbols-only']
193-
out = shared.run_js_tool(path_from_root('tools/compiler.mjs'),
194-
args, stdout=subprocess.PIPE, stderr=stderr_file, encoding='utf-8')
185+
settings_json = json.dumps(settings.external_dict(), sort_keys=True, indent=2)
186+
building.write_intermediate(settings_json, 'settings.json')
187+
188+
# Call js compiler. Passing `-` here mean read the settings from stdin.
189+
args = ['-']
190+
if symbols_only:
191+
args += ['--symbols-only']
192+
out = shared.run_js_tool(path_from_root('tools/compiler.mjs'),
193+
args, input=settings_json, stdout=subprocess.PIPE, stderr=stderr_file)
195194
if symbols_only:
196195
glue = None
197196
forwarded_data = out

tools/link.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ def read_js_files(files):
303303
for f in files:
304304
content = read_file(f)
305305
if content.startswith('#preprocess\n'):
306-
contents.append(shared.read_and_preprocess(f, expand_macros=True))
306+
contents.append(building.read_and_preprocess(f, expand_macros=True))
307307
else:
308308
contents.append(content)
309309
contents = '\n'.join(contents)
@@ -2078,7 +2078,7 @@ def fix_es6_import_statements(js_file):
20782078
def create_worker_file(input_file, target_dir, output_file, options):
20792079
output_file = os.path.join(target_dir, output_file)
20802080
input_file = utils.path_from_root(input_file)
2081-
contents = shared.read_and_preprocess(input_file, expand_macros=True)
2081+
contents = building.read_and_preprocess(input_file, expand_macros=True)
20822082
write_file(output_file, contents)
20832083

20842084
fix_es6_import_statements(output_file)
@@ -2284,7 +2284,7 @@ def phase_binaryen(target, options, wasm_target):
22842284
if settings.WASM == 2:
22852285
# With normal wasm2js mode this file gets included as part of the
22862286
# preamble, but with WASM=2 its a separate file.
2287-
wasm2js_polyfill = shared.read_and_preprocess(utils.path_from_root('src/wasm2js.js'), expand_macros=True)
2287+
wasm2js_polyfill = building.read_and_preprocess(utils.path_from_root('src/wasm2js.js'), expand_macros=True)
22882288
wasm2js_template = wasm_target + '.js'
22892289
write_file(wasm2js_template, wasm2js_polyfill)
22902290
# generate secondary file for JS symbols
@@ -2543,7 +2543,7 @@ def generate_traditional_runtime_html(target, options, js_target, target_basenam
25432543
# name, but the normal one does not support that currently
25442544
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)')
25452545

2546-
shell = shared.read_and_preprocess(options.shell_path)
2546+
shell = building.read_and_preprocess(options.shell_path)
25472547
if '{{{ SCRIPT }}}' not in shell:
25482548
exit_with_error('HTML shell must contain {{{ SCRIPT }}}, see src/shell.html for an example')
25492549
base_js_target = os.path.basename(js_target)
@@ -2689,7 +2689,7 @@ def generate_worker_js(target, options, js_target, target_basename):
26892689

26902690
def worker_js_script(proxy_worker_filename):
26912691
web_gl_client_src = read_file(utils.path_from_root('src/webGLClient.js'))
2692-
proxy_client_src = shared.read_and_preprocess(utils.path_from_root('src/proxyClient.js'), expand_macros=True)
2692+
proxy_client_src = building.read_and_preprocess(utils.path_from_root('src/proxyClient.js'), expand_macros=True)
26932693
if not settings.SINGLE_FILE and not os.path.dirname(proxy_worker_filename):
26942694
proxy_worker_filename = './' + proxy_worker_filename
26952695
proxy_client_src = do_replace(proxy_client_src, '<<< filename >>>', proxy_worker_filename)

tools/minimal_runtime_shell.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
__rootdir__ = os.path.dirname(__scriptdir__)
88
sys.path.insert(0, __rootdir__)
99

10+
from . import building
1011
from . import shared
1112
from . import utils
1213
from . import feature_matrix
@@ -194,7 +195,7 @@ def generate_minimal_runtime_html(target, options, js_target, target_basename):
194195
temp_files = shared.get_temp_files()
195196
with temp_files.get_file(suffix='.js') as shell_temp:
196197
utils.write_file(shell_temp, shell)
197-
shell = shared.read_and_preprocess(shell_temp)
198+
shell = building.read_and_preprocess(shell_temp)
198199

199200
if re.search(r'{{{\s*SCRIPT\s*}}}', shell):
200201
shared.exit_with_error('--shell-file "' + options.shell_path + '": MINIMAL_RUNTIME uses a different kind of HTML page shell file than the traditional runtime! Please see $EMSCRIPTEN/src/shell_minimal_runtime.html for a template to use as a basis.')

tools/preprocessor.mjs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,12 @@ loadDefaultSettings();
3636
assert(positionals.length == 2, 'Script requires 2 arguments');
3737

3838
// Load settings from JSON passed on the command line
39-
const settingsFile = positionals[0];
39+
let settingsFile = positionals[0];
4040
assert(settingsFile, 'settings file not specified');
41+
if (settingsFile == '-') {
42+
// Read settings json from stdin (FD 0)
43+
settingsFile = 0;
44+
}
4145
const userSettings = JSON.parse(readFile(settingsFile));
4246
applySettings(userSettings);
4347

tools/shared.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from enum import Enum, unique, auto
99
from subprocess import PIPE
1010
import atexit
11-
import json
1211
import logging
1312
import os
1413
import re
@@ -719,23 +718,6 @@ def safe_copy(src, dst):
719718
make_writable(dst)
720719

721720

722-
def read_and_preprocess(filename, expand_macros=False):
723-
# Create a settings file with the current settings to pass to the JS preprocessor
724-
with get_temp_files().get_file('.json') as settings_file:
725-
with open(settings_file, 'w') as s:
726-
json.dump(settings.external_dict(), s, sort_keys=True, indent=2)
727-
728-
# Run the JS preprocessor
729-
dirname, filename = os.path.split(filename)
730-
if not dirname:
731-
dirname = None
732-
args = [settings_file, filename]
733-
if expand_macros:
734-
args += ['--expand-macros']
735-
736-
return run_js_tool(path_from_root('tools/preprocessor.mjs'), args, stdout=subprocess.PIPE, cwd=dirname)
737-
738-
739721
def do_replace(input_, pattern, replacement):
740722
if pattern not in input_:
741723
exit_with_error('expected to find pattern in input JS: %s' % pattern)

0 commit comments

Comments
 (0)