Skip to content

Commit 343fed5

Browse files
authored
Add test runner option --log-test-environment (#25843)
Add test runner option --log-test-environment, which will introspect and print detailed information about Emscripten tool setup: Emcc, Clang, Binaryen, Node, Python and LLVM. This helps CI maintainers emit info to test run logs of the active setup for reference. `test/runner --log-test-environment <tests_to_run>` will then print a following log info dump before starting the tests: ``` C:\emsdk\emscripten\main>test\runner --log-test-environment ======================== Test Setup ======================== Test time: Thursday, November 20, 2025 22:28:18 UTC Python: "C:\emsdk\python\3.13.3_64bit\python.exe". Version: 3.13.3 (tags/v3.13.3:6280bb5, Apr 8 2025, 14:47:33) [MSC v.1943 64 bit (AMD64)] Emscripten test runner path: "C:\emsdk\emscripten\main\test\runner.py" Emscripten repository: "C:\emsdk\emscripten\main" emscripten-version.txt: 4.0.21-git Emscripten commit cce3a70 Author: Jukka Jylänki <[email protected]> Date: Fri Nov 21 00:26:51 2025 +0200 Add test runner option --log-test-environment, which will introspect and print detailed information about Emscripten tool setup: Emcc, Clang, Binaryen, Node, Python and LLVM. This helps CI maintainers emit info to test run logs of the active setup for reference. EM_CONFIG: "C:\emsdk\.emscripten" import os emsdk_path = os.path.dirname(os.getenv('EM_CONFIG')).replace('\\', '/') LLVM_ROOT = emsdk_path + '/llvm/git/build_main_vs2022_64/Release/bin' NODE_JS = emsdk_path + '/node/22.16.0_64bit/bin/node.exe' EMSDK_CMAKE = emsdk_path + '/cmake/4.2.0-rc3_64bit/bin/cmake.exe' PYTHON = emsdk_path + '/python/3.13.3_64bit/python.exe' EMSCRIPTEN_ROOT = emsdk_path + '/emscripten/main' BINARYEN_ROOT = emsdk_path + '/binaryen/main_vs2022_64bit_binaryen' MINGW_ROOT = emsdk_path + '/mingw/7.1.0_64bit' NINJA = emsdk_path + '/ninja/git-release_64bit/bin' EMSDK_ACTIVATED_TEST_BROWSER = emsdk_path + '/firefox/78.15.0esr_64bit/firefox.exe' NODE_JS: ['C:/emsdk/node/22.16.0_64bit/bin/node.exe']. Version: v22.16.0 BINARYEN_ROOT: C:/emsdk/binaryen/main_vs2022_64bit_binaryen wasm-opt version: wasm-opt version 124 (version_124-122-g8a66d2a7d) Binaryen git directory: "C:\emsdk\binaryen\main" Binaryen commit 8a66d2a7d48a0014dce5e22a2fa8eee12eb09b7c Author: Alon Zakai <[email protected]> Date: Thu Nov 6 11:53:49 2025 -0800 GUFA: Represent imported functions as globals (#8025) The meaning of Global in PossibleContents changes from "an actual wasm Global" to "an immutable global wasm thing, either a Global or a Function." Imported wasm Functions are effectively immutable values in the global scope - not concrete, specifically-known functions - so this is more correct. In particular, two imported Globals (of compatible types) might or might not be the same, and likewise with imported Functions. And that is not the case for defined Functions - they are definitely different. This does not fix the issues related to imported function type handling - #7993 does that - but this refactoring makes it possible to properly optimize imported functions afterward. This does make the PossibleContents object grow from 32 to 40 bytes, which might be why this adds 3-4% overhead to GUFA, but I don't see a good way to avoid that, unfortunately. Keeping our ability to optimize imported functions might be worth that 3-4% (we recently saw a few digits improvement due to properly optimizing imported externs, for example, from #8005). LLVM_ROOT: C:/emsdk/llvm/git/build_main_vs2022_64/Release/bin LLVM git directory: "C:/emsdk/llvm/git\src" LLVM commit d65be16ab6adf00af21e75d29049ae5de0f3a38a Author: Ryan Cowan <[email protected]> Date: Mon Nov 17 15:55:40 2025 +0000 [AArch64][GlobalISel] Add combine for build_vector(unmerge, unmerge, undef, undef) (#165539) This PR adds a new combine to the `post-legalizer-combiner` pass. The new combine checks for vectors being unmerged and subsequently padded with `G_IMPLICIT_DEF` values by building a new vector. If such a case is found, the vector being unmerged is instead just concatenated with a `G_IMPLICIT_DEF` that is as wide as the vector being unmerged. This removes unnecessary `mov` instructions in a few places. Clang: "C:/emsdk/llvm/git/build_main_vs2022_64/Release/bin\clang.exe" clang version 22.0.0git (https://github.com/llvm/llvm-project.git d65be16ab6adf00af21e75d29049ae5de0f3a38a) Target: x86_64-pc-windows-msvc Thread model: posix InstalledDir: C:\emsdk\llvm\git\build_main_vs2022_64\Release\bin EMTEST_BROWSER: "C:\\emsdk\\firefox\\78.15.0esr_64bit\\firefox.exe" -new-instance -wait-for-browser Firefox version: 78 Not detected as a Safari browser EMSDK: "C:/emsdk" Emsdk commit fe91d96cfd53f505a2ce561b01320124bff438a1 Author: Jukka Jylänki <[email protected]> Date: Mon Nov 17 18:41:28 2025 +0200 Use exit_with_error ==================== End of Test Setup ===================== ```
1 parent a58305a commit 343fed5

File tree

2 files changed

+104
-4
lines changed

2 files changed

+104
-4
lines changed

test/runner.py

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@
1919

2020
import argparse
2121
import atexit
22+
import datetime
2223
import fnmatch
2324
import glob
2425
import logging
2526
import math
2627
import operator
2728
import os
2829
import random
30+
import re
31+
import subprocess
2932
import sys
3033
import time
3134
import unittest
@@ -44,7 +47,7 @@
4447
from common import errlog
4548
from single_line_runner import SingleLineTestRunner
4649

47-
from tools import colored_logger, config, shared, utils
50+
from tools import building, colored_logger, config, shared, utils
4851

4952
logger = logging.getLogger("runner")
5053

@@ -506,6 +509,7 @@ def parse_args():
506509
'Useful when combined with --failfast')
507510
parser.add_argument('--force64', action='store_true')
508511
parser.add_argument('--crossplatform-only', action='store_true')
512+
parser.add_argument('--log-test-environment', action='store_true', help='Prints out detailed information about the current environment. Useful for adding more info to CI test runs.')
509513
parser.add_argument('--force-browser-process-termination', action='store_true', help='If true, a fail-safe method is used to ensure that all browser processes are terminated before and after the test suite run. Note that this option will terminate all browser processes, not just those launched by the harness, so will result in loss of all open browsing sessions.')
510514
parser.add_argument('--repeat', type=int, default=1,
511515
help='Repeat each test N times (default: 1).')
@@ -563,6 +567,95 @@ def cleanup_emscripten_temp():
563567
pass
564568

565569

570+
def print_repository_info(directory, repository_name):
571+
current_commit = utils.run_process(['git', 'log', '--abbrev-commit', '-n1', '--pretty=oneline'], cwd=directory, stdout=subprocess.PIPE).stdout.strip()
572+
print(f'\n{repository_name} {current_commit}\n')
573+
local_changes = utils.run_process(['git', 'diff'], cwd=directory, stdout=subprocess.PIPE).stdout.strip()
574+
if local_changes:
575+
print(f'\n{local_changes}\n')
576+
577+
578+
def log_test_environment():
579+
"""Print detailed information about the current test environment. Useful for
580+
logging test run configuration in a CI."""
581+
print('======================== Test Setup ========================')
582+
print(f'Test time: {datetime.datetime.now(datetime.timezone.utc).strftime("%A, %B %d, %Y %H:%M:%S %Z")}')
583+
print(f'Python: "{sys.executable}". Version: {sys.version}')
584+
print(f'Emscripten test runner path: "{os.path.realpath(__file__)}"')
585+
586+
if os.path.isdir(utils.path_from_root('.git')):
587+
print(f'\nEmscripten repository: "{__rootpath__}"')
588+
589+
emscripten_version = utils.path_from_root('emscripten-version.txt')
590+
if os.path.isfile(emscripten_version):
591+
print(f'emscripten-version.txt: {utils.EMSCRIPTEN_VERSION}')
592+
593+
if os.path.isdir(os.path.join(__rootpath__, '.git')):
594+
print_repository_info(__rootpath__, 'Emscripten')
595+
596+
print(f'EM_CONFIG: "{config.EM_CONFIG}"')
597+
if os.path.isfile(config.EM_CONFIG):
598+
print(f'\n{utils.read_file(config.EM_CONFIG).strip()}\n')
599+
600+
node_js_version = utils.run_process(config.NODE_JS + ['--version'], stdout=subprocess.PIPE).stdout.strip()
601+
print(f'NODE_JS: {config.NODE_JS}. Version: {node_js_version}')
602+
603+
print(f'BINARYEN_ROOT: {config.BINARYEN_ROOT}')
604+
wasm_opt_version = building.get_binaryen_version(building.get_binaryen_bin()).strip()
605+
print(f'wasm-opt version: {wasm_opt_version}')
606+
607+
binaryen_git_dir = config.BINARYEN_ROOT
608+
# Detect emsdk directory structure (build root vs source root)
609+
if re.match(r'main_.*_64bit_binaryen', os.path.basename(binaryen_git_dir)):
610+
binaryen_git_dir = os.path.realpath(os.path.join(binaryen_git_dir, '..', 'main'))
611+
if os.path.isdir(os.path.join(binaryen_git_dir, '.git')):
612+
print(f'Binaryen git directory: "{binaryen_git_dir}"')
613+
print_repository_info(binaryen_git_dir, 'Binaryen')
614+
615+
print(f'LLVM_ROOT: {config.LLVM_ROOT}')
616+
617+
# Find LLVM git directory in emsdk aware fashion
618+
def find_llvm_git_root(dir):
619+
while True:
620+
if os.path.isdir(os.path.join(dir, ".git")):
621+
return dir
622+
if os.path.isdir(os.path.join(dir, "src", ".git")):
623+
return os.path.join(dir, "src")
624+
if os.path.dirname(dir) == dir:
625+
return None
626+
dir = os.path.dirname(dir)
627+
628+
llvm_git_root = find_llvm_git_root(config.LLVM_ROOT)
629+
if llvm_git_root:
630+
print(f'LLVM git directory: "{llvm_git_root}"')
631+
print_repository_info(llvm_git_root, 'LLVM')
632+
633+
clang_version = utils.run_process([shared.CLANG_CC, '--version'], stdout=subprocess.PIPE).stdout.strip()
634+
print(f'Clang: "{shared.CLANG_CC}"\n{clang_version}\n')
635+
636+
print(f'EMTEST_BROWSER: {browser_common.EMTEST_BROWSER}')
637+
if browser_common.is_firefox():
638+
print(f'Firefox version: {browser_common.get_firefox_version()}')
639+
else:
640+
print('Not detected as a Firefox browser')
641+
if browser_common.is_safari():
642+
print(f'Safari version: {browser_common.get_safari_version()}')
643+
else:
644+
print('Not detected as a Safari browser')
645+
if browser_common.is_chrome():
646+
print('Browser is Chrome.')
647+
else:
648+
print('Not detected as a Chrome browser')
649+
650+
emsdk_dir = os.getenv('EMSDK')
651+
print(f'\nEMSDK: "{emsdk_dir}"')
652+
if emsdk_dir:
653+
if os.path.isdir(os.path.join(emsdk_dir, '.git')):
654+
print_repository_info(emsdk_dir, 'Emsdk')
655+
656+
print('==================== End of Test Setup =====================')
657+
658+
566659
def main():
567660
options = parse_args()
568661

@@ -606,6 +699,9 @@ def set_env(name, option_value):
606699

607700
browser_common.init(options.force_browser_process_termination)
608701

702+
if options.log_test_environment or os.getenv('CI'):
703+
log_test_environment()
704+
609705
def prepend_default(arg):
610706
if arg.startswith('test_'):
611707
return default_core_test_mode + '.' + arg

tools/building.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,21 +1189,25 @@ def get_binaryen_feature_flags():
11891189
return ['--detect-features']
11901190

11911191

1192-
def check_binaryen(bindir):
1192+
def get_binaryen_version(bindir):
11931193
opt = os.path.join(bindir, utils.exe_suffix('wasm-opt'))
11941194
if not os.path.exists(opt):
11951195
exit_with_error('binaryen executable not found (%s). Please check your binaryen installation' % opt)
11961196
try:
1197-
output = run_process([opt, '--version'], stdout=PIPE).stdout
1197+
return run_process([opt, '--version'], stdout=PIPE).stdout
11981198
except subprocess.CalledProcessError:
11991199
exit_with_error('error running binaryen executable (%s). Please check your binaryen installation' % opt)
1200+
1201+
1202+
def check_binaryen(bindir):
1203+
output = get_binaryen_version(bindir)
12001204
if output:
12011205
output = output.splitlines()[0]
12021206
try:
12031207
version = output.split()[2]
12041208
version = int(version)
12051209
except (IndexError, ValueError):
1206-
exit_with_error('error parsing binaryen version (%s). Please check your binaryen installation (%s)' % (output, opt))
1210+
exit_with_error(f'error parsing binaryen version ({output}). Please check your binaryen installation')
12071211

12081212
# Allow the expected version or the following one in order avoid needing to update both
12091213
# emscripten and binaryen in lock step in emscripten-releases.

0 commit comments

Comments
 (0)