|
8 | 8 | Primary build targets are "emscripten-node-dl" (NodeJS, dynamic linking),
|
9 | 9 | "emscripten-browser", and "wasi".
|
10 | 10 |
|
11 |
| -Emscripten builds require Emscripten SDK. The tools looks for 'EMSCRIPTEN' |
12 |
| -env var and falls back to EMSDK installed at /opt/emsdk. |
| 11 | +Emscripten builds require a recent Emscripten SDK. The tools looks for an |
| 12 | +activated EMSDK environment (". /path/to/emsdk_env.sh"). |
13 | 13 |
|
14 | 14 | WASI builds require WASI SDK and wasmtime. The tool looks for 'WASI_SDK_PATH'
|
15 | 15 | and falls back to /opt/wasi-sdk.
|
|
35 | 35 |
|
36 | 36 | # path to WASI-SDK root
|
37 | 37 | WASI_SDK_PATH = pathlib.Path(os.environ.get("WASI_SDK_PATH", "/opt/wasi-sdk"))
|
38 |
| -# path to Emscripten directory (upstream/emscripten subdirectory in the EMSDK) |
39 |
| -EMSCRIPTEN_PATH = pathlib.Path(os.environ.get("EMSCRIPTEN", "/opt/emsdk/upstream/emscripten")) |
| 38 | + |
| 39 | +# path to Emscripten SDK config file. |
| 40 | +# auto-detect's EMSDK in /opt/emsdk without ". emsdk_env.sh". |
| 41 | +EM_CONFIG = pathlib.Path(os.environ.setdefault("EM_CONFIG", "/opt/emsdk/.emscripten")) |
| 42 | +# 3.1.16 has broken utime() |
| 43 | +EMSDK_MIN_VERSION = (3, 1, 17) |
| 44 | +_MISSING = pathlib.PurePath("MISSING") |
40 | 45 |
|
41 | 46 | # WASM_WEBSERVER = WASMTOOLS / "wasmwebserver.py"
|
42 | 47 |
|
43 | 48 | INSTALL_EMSDK = """
|
44 | 49 | wasm32-emscripten builds need Emscripten SDK. Please follow instructions at
|
45 | 50 | https://emscripten.org/docs/getting_started/downloads.html how to install
|
46 |
| -Emscripten tp "/opt/emsdk". Alternatively you can install the SDK in a |
47 |
| -different location and set the environment variable |
48 |
| -EMSCRIPTEN=.../upstream/emscripten (the directory with emcc and |
49 |
| -emconfigure scripts), e.g. with ". emsdk_env.sh". |
| 51 | +Emscripten and how to activate the SDK with ". /path/to/emsdk_env.sh". |
50 | 52 | """
|
51 | 53 |
|
52 | 54 | INSTALL_WASI_SDK = """
|
|
63 | 65 | """
|
64 | 66 |
|
65 | 67 |
|
| 68 | +def get_emscripten_root(emconfig: pathlib.Path = EM_CONFIG) -> pathlib.Path: |
| 69 | + """Parse EM_CONFIG file and lookup EMSCRIPTEN_ROOT |
| 70 | +
|
| 71 | + The ".emscripten" config file is a Python snippet that uses "EM_CONFIG" |
| 72 | + environment variable. EMSCRIPTEN_ROOT is the "upstream/emscripten" |
| 73 | + subdirectory with tools like "emconfigure". |
| 74 | + """ |
| 75 | + if not emconfig.exists(): |
| 76 | + return _MISSING |
| 77 | + with open(emconfig, encoding="utf-8") as f: |
| 78 | + code = f.read() |
| 79 | + # EM_CONFIG file is a Python snippet |
| 80 | + local = {} |
| 81 | + exec(code, globals(), local) |
| 82 | + return pathlib.Path(local["EMSCRIPTEN_ROOT"]) |
| 83 | + |
| 84 | + |
| 85 | +EMSCRIPTEN_ROOT = get_emscripten_root() |
| 86 | + |
| 87 | + |
66 | 88 | class MissingDependency(ValueError):
|
67 | 89 | def __init__(self, command: str, text: str):
|
68 | 90 | self.command = command
|
@@ -107,17 +129,34 @@ def getenv(self) -> dict:
|
107 | 129 |
|
108 | 130 |
|
109 | 131 | def _check_emscripten():
|
110 |
| - emconfigure = EMSCRIPTEN_PATH / "emconfigure" |
| 132 | + if EMSCRIPTEN_ROOT is _MISSING: |
| 133 | + raise MissingDependency("Emscripten SDK EM_CONFIG", INSTALL_EMSDK) |
| 134 | + # sanity check |
| 135 | + emconfigure = EMSCRIPTEN.configure_wrapper |
111 | 136 | if not emconfigure.exists():
|
112 | 137 | raise MissingDependency(emconfigure, INSTALL_EMSDK)
|
| 138 | + # version check |
| 139 | + version_txt = EMSCRIPTEN_ROOT / "emscripten-version.txt" |
| 140 | + if not version_txt.exists(): |
| 141 | + raise MissingDependency(version_txt, INSTALL_EMSDK) |
| 142 | + with open(version_txt) as f: |
| 143 | + version = f.read().strip().strip('"') |
| 144 | + version_tuple = tuple(int(v) for v in version.split(".")) |
| 145 | + if version_tuple < EMSDK_MIN_VERSION: |
| 146 | + raise MissingDependency( |
| 147 | + version_txt, |
| 148 | + f"Emscripten SDK {version} in '{EMSCRIPTEN_ROOT}' is older than " |
| 149 | + "minimum required version " |
| 150 | + f"{'.'.join(str(v) for v in EMSDK_MIN_VERSION)}.", |
| 151 | + ) |
113 | 152 |
|
114 | 153 |
|
115 | 154 | EMSCRIPTEN = Platform(
|
116 | 155 | "emscripten",
|
117 | 156 | pythonexe="python.js",
|
118 | 157 | config_site=WASMTOOLS / "config.site-wasm32-emscripten",
|
119 |
| - configure_wrapper=EMSCRIPTEN_PATH / "emconfigure", |
120 |
| - make_wrapper=EMSCRIPTEN_PATH / "emmake", |
| 158 | + configure_wrapper=EMSCRIPTEN_ROOT / "emconfigure", |
| 159 | + make_wrapper=EMSCRIPTEN_ROOT / "emmake", |
121 | 160 | environ={"EM_COMPILER_WRAPPER": "ccache"} if HAS_CCACHE else None,
|
122 | 161 | check=_check_emscripten,
|
123 | 162 | )
|
@@ -434,7 +473,7 @@ def main():
|
434 | 473 | try:
|
435 | 474 | builder.host.platform.check()
|
436 | 475 | except MissingDependency as e:
|
437 |
| - parser.exit(2, str(e)) |
| 476 | + parser.exit(2, str(e) + "\n") |
438 | 477 |
|
439 | 478 | # hack for WASI
|
440 | 479 | if builder.host.is_wasi and not SETUP_LOCAL.exists():
|
|
0 commit comments