Skip to content

Commit d438601

Browse files
committed
Add a windows launcher program to replace the current .bat files
This is still just an experiment but eventually I hope to remove the `.bat` files in favor of this executable. Users who have issues can opt out via `EMCC_USE_BAT_FILES`. There are several reasons to want to do this: 1. Batch files are notoriously painful to work with and mis-understood. 2. Should be faster (no need to launch cmd.exe). 3. Works around several known issues with .bat files including one that is known unsolvable one (see emcc.bat for more details)
1 parent 8a64538 commit d438601

12 files changed

Lines changed: 355 additions & 24 deletions

File tree

.circleci/config.yml

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ commands:
503503
echo "-----"
504504
echo "Running browser tests (EMTEST_BROWSER=$EMTEST_BROWSER)"
505505
echo "-----"
506-
test/runner.bat << parameters.test_targets >>
506+
test/runner.exe << parameters.test_targets >>
507507
- upload-test-results
508508
test-sockets-chrome:
509509
description: "Runs emscripten sockets tests under chrome"
@@ -1251,6 +1251,17 @@ jobs:
12511251
steps:
12521252
- test-sockets-chrome
12531253

1254+
build-windows-launcher:
1255+
executor:
1256+
name: win/server-2022
1257+
shell: cmd.exe
1258+
steps:
1259+
- checkout
1260+
- run: call .circleci\setup_vs2022.bat && cd tools\pylauncher && call build.bat
1261+
- store_artifacts:
1262+
path: tools/pylauncher/pylauncher.exe
1263+
destination: pylauncher.exe
1264+
12541265
# windows and mac do not have separate build and test jobs, as they only run
12551266
# a limited set of tests; it is simpler and faster to do it all in one job.
12561267
test-windows:
@@ -1277,6 +1288,10 @@ jobs:
12771288
EMTEST_BROWSER: "0"
12781289
steps:
12791290
- checkout
1291+
- run:
1292+
name: Build launcher
1293+
command: call .circleci\setup_vs2019.bat && cd tools\pylauncher && call build.bat
1294+
shell: cmd.exe
12801295
- run:
12811296
name: Install packages
12821297
command: |
@@ -1286,17 +1301,14 @@ jobs:
12861301
- install-emsdk
12871302
- pip-install:
12881303
python: "$EMSDK_PYTHON"
1289-
# run-tests depends on the ./test/runner script which is normally only
1290-
# created on UNIX systems (windows uses runner.bat)
1291-
- run: $EMSDK_PYTHON tools/maint/create_entry_points.py --all
12921304
- run:
12931305
name: "crossplatform tests"
1294-
command: test/runner.bat --crossplatform-only
1306+
command: test/runner.exe --crossplatform-only
12951307
- upload-test-results
12961308
# Run a single websockify-based test to ensure it works on windows.
12971309
- run:
12981310
name: "sockets.test_nodejs_sockets_echo*"
1299-
command: "test/runner.bat sockets.test_nodejs_sockets_echo*"
1311+
command: "test/runner.exe sockets.test_nodejs_sockets_echo*"
13001312
- upload-test-results
13011313

13021314
test-mac-arm64:
@@ -1393,6 +1405,7 @@ workflows:
13931405
- test-node-compat
13941406
- test-windows
13951407
- test-windows-browser-firefox
1408+
- build-windows-launcher
13961409
- test-mac-arm64:
13971410
requires:
13981411
- build-linux

.circleci/setup_vs2019.bat

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
echo "setting up x64 toolchain"
2+
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" x86_amd64
3+
where cl.exe
4+
echo "done"

.circleci/setup_vs2022.bat

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
echo "setting up x64 toolchain"
2+
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64
3+
where cl.exe
4+
echo "done"

.gitignore

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ coverage.xml
3939
!/tools/run_python.ps1
4040
!/tools/run_python_compiler.ps1
4141

42+
/tools/maint/pylauncher/pylauncher.obj
43+
4244
# Shell scripts (created by ./tools/maint/create_entry_points.py)
4345
em++
4446
emcc
@@ -88,3 +90,28 @@ emsymbolizer.bat
8890
test/runner.bat
8991
tools/file_packager.bat
9092
tools/webidl_binder.bat
93+
94+
bootstrap.exe
95+
em++.exe
96+
emcc.exe
97+
em-config.exe
98+
emar.exe
99+
embuilder.exe
100+
emcmake.exe
101+
emconfigure.exe
102+
emdump.exe
103+
emdwp.exe
104+
emmake.exe
105+
emnm.exe
106+
empath-split.exe
107+
emprofile.exe
108+
emranlib.exe
109+
emrun.exe
110+
emscan-deps.exe
111+
emscons.exe
112+
emsize.exe
113+
emstrip.exe
114+
emsymbolizer.exe
115+
tools/file_packager.exe
116+
tools/webidl_binder.exe
117+
test/runner.exe

ChangeLog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ See docs/process.md for more on how version tagging works.
2121
5.0.2 (in development)
2222
----------------------
2323
- SDL2 port updated from 2.32.8 to 2.32.10. (#26298)
24+
- The Windows `.bat` files that were previosly used to luanch emscripten's
25+
python programs (e.g. `emcc.bat`) were removed and replaced with `.exe`
26+
launchers. These should be faster and have fewer limitations. If you have
27+
issues with these you can opt out by setting `EMCC_USE_BAT_FILES` in the
28+
environment and re-run `tools/maint/create_entry_points.py`. (#24858)
2429
- The remaining launcher scripts (e.g. `emcc.bat`) were removed from the git
2530
repository. These scripts are created by the `./bootstrap` script which
2631
must be run before the toolchain is usable (for folks using a git checkout of

cmake/Modules/Platform/Emscripten.cmake

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,15 @@ get_filename_component(EMSCRIPTEN_ROOT_PATH "${EMSCRIPTEN_ROOT_PATH}" ABSOLUTE)
6666
list(APPEND CMAKE_MODULE_PATH "${EMSCRIPTEN_ROOT_PATH}/cmake/Modules")
6767

6868
if (CMAKE_HOST_WIN32)
69-
set(EMCC_SUFFIX ".bat")
69+
# We use windows executables these days rather than `.bat` files, but we
70+
# still project a fallback of using `.bat` files in the interim
71+
if ("${EMSCRIPTEN_ROOT_PATH}/emcc.exe")
72+
set(EMCC_SUFFIX ".exe")
73+
else()
74+
set(USE_BAT_FILES)
75+
set(EMCC_SUFFIX ".bat")
76+
else()
77+
endif()
7078
else()
7179
set(EMCC_SUFFIX "")
7280
endif()
@@ -268,12 +276,15 @@ endif()
268276

269277
set(CMAKE_EXECUTABLE_SUFFIX ".js")
270278

271-
set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES 1)
272-
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_LIBRARIES 1)
273-
set(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1)
274-
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1)
275-
set(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1)
276-
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1)
279+
if (DEFINED USE_BAT_FILES)
280+
# See https://github.com/emscripten-core/emscripten/issues/2386
281+
set(CMAKE_C_USE_RESPONSE_FILE_FOR_LIBRARIES 1)
282+
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_LIBRARIES 1)
283+
set(CMAKE_C_USE_RESPONSE_FILE_FOR_OBJECTS 1)
284+
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_OBJECTS 1)
285+
set(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES 1)
286+
set(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES 1)
287+
endif()
277288

278289
set(CMAKE_C_RESPONSE_FILE_LINK_FLAG "@")
279290
set(CMAKE_CXX_RESPONSE_FILE_LINK_FLAG "@")

tools/maint/create_entry_points.py

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,23 @@
77
"""Tool for creating/maintaining the python launcher scripts for all the emscripten
88
python tools.
99
10-
This tool makes copies or `run_python.sh/.bat` and `run_python_compiler.sh/.bat`
11-
script for each entry point. On UNIX we previously used symbolic links for
12-
simplicity but this breaks MINGW users on windows who want to use the shell script
13-
launcher but don't have symlink support.
10+
This tool makes copies of the launcher for UNIX and/or windows for each of the
11+
python entry points.
12+
13+
For UNIX we use a `run_python.sh` script that will exex that python executable.
14+
15+
For windows we use `launcher.exe` which is small C program that launches python.
16+
17+
Hitorically we used `run_python.bat` on windows but found that it was a constant
18+
source of bugs, as well we bring slower than the dedicated launcher.exe.
19+
20+
On UNIX we previously used symbolic links for simplicity but this breaks MINGW
21+
users on windows who want to use the shell script launcher but don't have
22+
symlink support.
1423
"""
1524

1625
import os
26+
import shutil
1727
import stat
1828
import sys
1929

@@ -61,12 +71,20 @@
6171
}
6272

6373

74+
windows_exe = os.path.join(__rootdir__, 'tools/pylauncher/pylauncher.exe')
75+
76+
6477
def make_executable(filename):
6578
old_mode = stat.S_IMODE(os.stat(filename).st_mode)
6679
os.chmod(filename, old_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
6780

6881

69-
def main(all_platforms):
82+
def maybe_remove(filename):
83+
if os.path.exists(filename):
84+
os.remove(filename)
85+
86+
87+
def main(all_platforms, use_bat_files):
7088
is_windows = sys.platform.startswith('win')
7189
is_msys2 = 'MSYSTEM' in os.environ
7290
do_unix = all_platforms or not is_windows or is_msys2
@@ -99,15 +117,23 @@ def generate_entry_points(cmd, path):
99117
make_executable(launcher)
100118

101119
if do_windows:
102-
with open(launcher + '.bat', 'w') as f:
103-
f.write(bat_data)
104-
105-
with open(launcher + '.ps1', 'w') as f:
106-
f.write(ps1_data)
120+
maybe_remove(launcher + '.bat')
121+
maybe_remove(launcher + '.ps1')
122+
maybe_remove(launcher + '.exe')
123+
# We use windows executables these days rather than `.bat` files, but for an
124+
# interim period we still support the old `.bat` files via the `EMCC_USE_BAT_FILES`
125+
# environment variable.
126+
if use_bat_files:
127+
with open(launcher + '.bat', 'w') as f:
128+
f.write(bat_data)
129+
with open(launcher + '.ps1', 'w') as f:
130+
f.write(ps1_data)
131+
else:
132+
shutil.copyfile(windows_exe, launcher + '.exe')
107133

108134
generate_entry_points(entry_points, os.path.join(__scriptdir__, 'run_python'))
109135
generate_entry_points(compiler_entry_points, os.path.join(__scriptdir__, 'run_python_compiler'))
110136

111137

112138
if __name__ == '__main__':
113-
sys.exit(main('--all' in sys.argv))
139+
sys.exit(main('--all' in sys.argv, '--bat-files' in sys.argv))

tools/pylauncher/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Windows Python Script Launcher
2+
==============================
3+
4+
This directory contains a simple launcher program for windows which is used to
5+
execute the emscripten compiler entry points using the python interpreter. It
6+
uses the its own name (the name of the currently running executable) to
7+
determine which python script to run and serves the same purpose as the
8+
``run_python.sh`` script does on non-windows platforms.
9+
10+
We build this executable statically using ``/MT`` so that it is maximally
11+
portable.

tools/pylauncher/build.bat

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
:: /MT : Statically link to the C runtime library for max portability
2+
:: /O1 : Favor small code (optimization for size)
3+
4+
cl pylauncher.c /Fe:pylauncher.exe /MT /O1

tools/pylauncher/build.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
3+
SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}")
4+
cd ${SCRIPT_DIR}
5+
6+
x86_64-w64-mingw32-gcc -Werror -static-libgcc -static-libstdc++ -s -Os pylauncher.c -o pylauncher.exe -lshlwapi -lshell32

0 commit comments

Comments
 (0)