Compare commits

..

10 Commits

Author SHA1 Message Date
emscripten-bot
c0bb220cb6 Release 4.0.23 (#1648)
With emscripten-releases revisions:

https://chromium.googlesource.com/emscripten-releases/+/aaa43392544d695232b70eda706d751f18980c2a
(LTO)

https://chromium.googlesource.com/emscripten-releases/+/7b0b10e1a743dabe4b66759c90ff2bcbed0d3b8d
(asserts)
2026-01-09 16:21:07 -08:00
Sam Clegg
fc80c2d544 Convert test code to use subprocess.run. NFC (#1647) 2025-12-18 15:29:15 -08:00
emscripten-bot
15915cad55 Release 4.0.22 (#1644)
With emscripten-releases revisions:

https://chromium.googlesource.com/emscripten-releases/+/bebaf7e50e31865b0724f17eaa52e161e2dfef5a
(LTO)
https://chromium.googlesource.com/emscripten-releases/+/64750c136
(asserts)
2025-12-17 20:59:04 -08:00
Sam Clegg
334f6902fe [CI] Update macos resource class. NFC (#1643)
See
https://circleci.com/changelog/deprecation-of-mac-m1-and-m2-resource-classes/

Sadly this also means we have to bump the version of macOS that we test
on from 12.6.1 to 13.2.1
2025-12-15 13:25:49 -08:00
Sam Clegg
11ea2ee53d Python fixes from ruff check (#1641) 2025-12-15 09:57:48 -08:00
emscripten-bot
b2436aafa7 Release 4.0.21 (#1638)
With emscripten-releases revisions:

https://chromium.googlesource.com/emscripten-releases/+/d70a5da89b3e673bf6a482724478fc17e81e575e
(LTO)

https://chromium.googlesource.com/emscripten-releases/+/50deeb529cc8a08f952af8a3087d2e27e0f77c3e
(asserts)
2025-12-02 10:36:51 -08:00
Sam Clegg
6e4471361a More usage of python3 features (#1636)
Mostly f-strings, but a few others too.
2025-12-01 17:11:00 -08:00
Sam Clegg
a040059ae2 Bump min macOS version to 11.0 (#1637)
We already specify 11.0 for `CMAKE_OSX_DEPLOYMENT_TARGET` in
`cmake_configure`

See #1634
2025-12-01 12:32:48 -08:00
Joshua T.
5a3430bbe3 Correctly tag latest built docker image (#1635)
Additionally removes the `alias` and `only_alias` arguments and adds a
single `tag` argument - this makes it clear about the tag being pushed
to.

Fixes: #1631
2025-11-27 19:32:52 +00:00
Sam Clegg
753652fd30 Update information about linux version used to build prebuilt binaries. NFC (#1633) 2025-11-26 15:10:11 -08:00
13 changed files with 282 additions and 201 deletions

View File

@@ -14,10 +14,10 @@ executors:
# brew itself which takes more than 4 minutes. # brew itself which takes more than 4 minutes.
HOMEBREW_NO_AUTO_UPDATE: "1" HOMEBREW_NO_AUTO_UPDATE: "1"
macos: macos:
# Corresponds to macOS 12.6.1 # Corresponds to macOS 13.2.1
# See https://circleci.com/docs/guides/execution-managed/using-macos/#supported-xcode-versions # See https://circleci.com/docs/guides/execution-managed/using-macos/#supported-xcode-versions
xcode: "14.0.1" xcode: "14.3.1"
resource_class: macos.m1.medium.gen1 resource_class: m4pro.medium
linux_arm64: linux_arm64:
machine: machine:
image: ubuntu-2004:2023.07.1 image: ubuntu-2004:2023.07.1
@@ -75,7 +75,7 @@ commands:
.\test\test_bazel.ps1 .\test\test_bazel.ps1
jobs: jobs:
flake8: lint:
executor: ubuntu executor: ubuntu
steps: steps:
- checkout - checkout
@@ -85,12 +85,12 @@ jobs:
apt-get update -q apt-get update -q
apt-get install -q -y python3-pip apt-get install -q -y python3-pip
- run: - run:
name: python3 flake8 name: python lint
command: | command: |
python3 -m pip install --upgrade pip python3 -m pip install --upgrade pip
python3 -m pip install flake8==7.1.1 python3 -m pip install flake8==7.1.1 ruff==0.14.1
python3 -m flake8 --show-source --statistics --extend-exclude=./scripts python3 -m flake8 --show-source --statistics --extend-exclude=./scripts
python3 -m ruff check
test-linux: test-linux:
executor: ubuntu executor: ubuntu
environment: environment:
@@ -238,7 +238,7 @@ jobs:
name: push image name: push image
command: | command: |
docker login -u "$DOCKER_USER" -p "$DOCKER_PASS" docker login -u "$DOCKER_USER" -p "$DOCKER_PASS"
make -C ./docker version=${CIRCLE_TAG} alias=${CIRCLE_TAG}-x64 only_alias=true push make -C ./docker version=${CIRCLE_TAG} tag=${CIRCLE_TAG}-x64 push
publish-docker-image-arm64: publish-docker-image-arm64:
executor: linux_arm64 executor: linux_arm64
@@ -254,7 +254,7 @@ jobs:
name: push image name: push image
command: | command: |
docker login -u "$DOCKER_USER" -p "$DOCKER_PASS" docker login -u "$DOCKER_USER" -p "$DOCKER_PASS"
make -C ./docker version=${CIRCLE_TAG} alias=${CIRCLE_TAG}-arm64 only_alias=true push make -C ./docker version=${CIRCLE_TAG} tag=${CIRCLE_TAG}-arm64 push
publish-docker-image-multiplatform: publish-docker-image-multiplatform:
executor: linux_arm64 executor: linux_arm64
@@ -264,7 +264,8 @@ jobs:
name: push image name: push image
command: | command: |
docker login -u "$DOCKER_USER" -p "$DOCKER_PASS" docker login -u "$DOCKER_USER" -p "$DOCKER_PASS"
make -C ./docker version=${CIRCLE_TAG} alias="latest" push-multiplatform make -C ./docker version=${CIRCLE_TAG} tag=${CIRCLE_TAG} push-multiplatform
make -C ./docker version=${CIRCLE_TAG} tag="latest" push-multiplatform
test-bazel7-linux: test-bazel7-linux:
executor: ubuntu executor: ubuntu
@@ -314,9 +315,9 @@ jobs:
- test-bazel-windows - test-bazel-windows
workflows: workflows:
flake8: lint:
jobs: jobs:
- flake8 - lint
test-linux: test-linux:
jobs: jobs:
- test-linux - test-linux

View File

@@ -55,8 +55,7 @@ https://emscripten.org/docs/building_from_source/toolchain_what_is_needed.html.
### Mac OS X ### Mac OS X
- For Intel-based Macs, macOS 10.13 or newer. For ARM64 M1 based Macs, macOS - macOS 11.0 or newer.
11.0 or newer.
- `java`: For running closure compiler (optional). After installing emscripten - `java`: For running closure compiler (optional). After installing emscripten
via emsdk, typing 'emcc --help' should pop up a OS X dialog "Java is not via emsdk, typing 'emcc --help' should pop up a OS X dialog "Java is not
installed. To open java, you need a Java SE 6 runtime. Would you like to installed. To open java, you need a Java SE 6 runtime. Would you like to
@@ -68,10 +67,12 @@ https://emscripten.org/docs/building_from_source/toolchain_what_is_needed.html.
- `python`: Version 3.8 or above. - `python`: Version 3.8 or above.
- `java`: For running closure compiler (optional) - `java`: For running closure compiler (optional)
The emsdk pre-compiled binaries are built against Ubuntu/Focal 20.04 LTS and The emsdk pre-compiled binaries are built against debian/stretch (for x86_64)
therefore depend on system libraries compatible with versions of `glibc` and and debian/bullseye (for arm64) sysroots and therefore depend on system
`libstdc++` present in that release. If your linux distribution is very old libraries compatible with the version of `glibc` (and other libraries) present
you may not be able to use the pre-compiled binaries packages. in those releases. If your linux distribution is very old you may not be able to
use the pre-compiled binaries packages. Note that `libc++` is statically linked
so there should be no issues with older versions of `libstdc++` or `libc++`.
### Windows ### Windows

View File

@@ -1,6 +1,6 @@
module( module(
name = "emsdk", name = "emsdk",
version = "4.0.20", version = "4.0.23",
) )
bazel_dep(name = "platforms", version = "0.0.11") bazel_dep(name = "platforms", version = "0.0.11")

View File

@@ -14,7 +14,6 @@ This wrapper currently serves the following purposes.
bazel path. bazel path.
""" """
from __future__ import print_function
import argparse import argparse
import os import os
@@ -24,7 +23,7 @@ import sys
# Only argument should be @path/to/parameter/file # Only argument should be @path/to/parameter/file
assert sys.argv[1][0] == '@', sys.argv assert sys.argv[1][0] == '@', sys.argv
param_filename = sys.argv[1][1:] param_filename = sys.argv[1][1:]
param_file_args = [line.strip() for line in open(param_filename, 'r').readlines()] param_file_args = [line.strip() for line in open(param_filename).readlines()]
# Re-write response file if needed. # Re-write response file if needed.
if any(' ' in a for a in param_file_args): if any(' ' in a for a in param_file_args):
@@ -151,7 +150,7 @@ if os.path.exists(wasm_base + '.debug.wasm') and os.path.exists(wasm_base):
'--add-section=external_debug_info=' + base_name + '_debugsection.tmp']) '--add-section=external_debug_info=' + base_name + '_debugsection.tmp'])
# Make sure we have at least one output file. # Make sure we have at least one output file.
if not len(files): if not files:
print('emcc.py did not appear to output any known files!') print('emcc.py did not appear to output any known files!')
sys.exit(1) sys.exit(1)

View File

@@ -2,6 +2,30 @@
# DO NOT MODIFY # DO NOT MODIFY
EMSCRIPTEN_TAGS = { EMSCRIPTEN_TAGS = {
"4.0.23": struct(
hash = "aaa43392544d695232b70eda706d751f18980c2a",
sha_linux = "5f1565fe45a1223cedf3b0300f5089c2c64954d2895b2aaedc85043c719be965",
sha_linux_arm64 = "d8ed075930b397d3aed8a1c7558db1918ade786349b07d5c042dfa7f65f78563",
sha_mac = "5823ef26fd45b5a960960fb53026513d43922eac7a1e3ba12d1344d7a94699f9",
sha_mac_arm64 = "54234e108d6612eca5dc9280d1779ccec3d49ad4d8c8562a6b2046b0a5a8d5d4",
sha_win = "c2e1b9a2eed20f9d5903780b559ce2b384132713f07936512e6d962dd5a5dae6",
),
"4.0.22": struct(
hash = "bebaf7e50e31865b0724f17eaa52e161e2dfef5a",
sha_linux = "81219e78defb2f46d12a67a2fa6d128344d850f1e4375b173a324036236b40ef",
sha_linux_arm64 = "5bff19114edb410863634b14e3f459e7d90dc5339f7e5c7bdd5a946356b1dd54",
sha_mac = "a40cfb7c4c4f8cac9c6521475abca80f20986c8c438d46ac745bb4316d838a30",
sha_mac_arm64 = "1a3fb183385682e790cf617824681dc72c2b30e8db2afc9189d0dadea9ccd466",
sha_win = "4a29b0bdc3d477ce39a9e6cd508f16dc19ea1bf861a66c1d715e0264ab550e45",
),
"4.0.21": struct(
hash = "d70a5da89b3e673bf6a482724478fc17e81e575e",
sha_linux = "e8516b903cd4dc16bf5aa2aacd826adcff5ff1d97d3d88e5e3871decd94cd8b2",
sha_linux_arm64 = "415024a22f84424c713b117c3a24cefb98ec03737e02063074010fdc8eaeb334",
sha_mac = "f17989b3528cd14971fe75ae9b2aa7d8cc4cc5bbb6d408660e059f822e108a46",
sha_mac_arm64 = "7960d8d33243f2f7acdac157136c6e93680550361ed71bb225fcfa25b6bbb2fb",
sha_win = "79b3a6b77cf8015cc07ad25353f17f1828e731b0d8757a046071fffbdd5aaf70",
),
"4.0.20": struct( "4.0.20": struct(
hash = "c387d7a7e9537d0041d2c3ae71b7538cc978104e", hash = "c387d7a7e9537d0041d2c3ae71b7538cc978104e",
sha_linux = "a06e7ddda0c168f7ad52e6e0509c98db3545dcb254d3b9052e9e6b8423eaee7d", sha_linux = "a06e7ddda0c168f7ad52e6e0509c98db3545dcb254d3b9052e9e6b8423eaee7d",

View File

@@ -3,8 +3,7 @@
# Emscripten version to build: Should match the version that has been already released. # Emscripten version to build: Should match the version that has been already released.
# i.e.: 1.39.18 # i.e.: 1.39.18
version = version =
alias = tag =
only_alias =
image_name ?= emscripten/emsdk image_name ?= emscripten/emsdk
@@ -22,14 +21,13 @@ test: test_dockerimage.sh .TEST
docker run --rm -u `id -u`:`id -g` -w /emsdk/docker --net=host --entrypoint /bin/bash ${image_name}:${version} $< docker run --rm -u `id -u`:`id -g` -w /emsdk/docker --net=host --entrypoint /bin/bash ${image_name}:${version} $<
push: .TEST push: .TEST
ifndef only_alias ifdef tag
docker push ${image_name}:${version} docker tag ${image_name}:${version} ${image_name}:${tag}
endif docker push ${image_name}:${tag}
ifdef alias
docker tag ${image_name}:${version} ${image_name}:${alias}
docker push ${image_name}:${alias}
endif endif
push-multiplatform: .TEST push-multiplatform: .TEST
docker manifest create ${image_name}:${version} $(foreach platform,x64 arm64,--amend ${image_name}:${version}-$(platform)) ifdef tag
docker manifest push ${image_name}:${version} docker manifest create ${image_name}:${tag} $(foreach platform,x64 arm64,--amend ${image_name}:${version}-$(platform))
docker manifest push ${image_name}:${tag}
endif

View File

@@ -1,6 +1,6 @@
{ {
"aliases": { "aliases": {
"latest": "4.0.20", "latest": "4.0.23",
"latest-sdk": "latest", "latest-sdk": "latest",
"latest-arm64-linux": "latest", "latest-arm64-linux": "latest",
"latest-64bit": "latest", "latest-64bit": "latest",
@@ -10,6 +10,12 @@
"latest-releases-upstream": "latest" "latest-releases-upstream": "latest"
}, },
"releases": { "releases": {
"4.0.23": "aaa43392544d695232b70eda706d751f18980c2a",
"4.0.23-asserts": "7b0b10e1a743dabe4b66759c90ff2bcbed0d3b8d",
"4.0.22": "bebaf7e50e31865b0724f17eaa52e161e2dfef5a",
"4.0.22-asserts": "64750c136",
"4.0.21": "d70a5da89b3e673bf6a482724478fc17e81e575e",
"4.0.21-asserts": "50deeb529cc8a08f952af8a3087d2e27e0f77c3e",
"4.0.20": "c387d7a7e9537d0041d2c3ae71b7538cc978104e", "4.0.20": "c387d7a7e9537d0041d2c3ae71b7538cc978104e",
"4.0.20-asserts": "d4fdf09ba6e7a2d75bc1f643370caf4519021e89", "4.0.20-asserts": "d4fdf09ba6e7a2d75bc1f643370caf4519021e89",
"4.0.19": "8b01e2ec3f33e6b94842096d7312ce4ef5f33f6c", "4.0.19": "8b01e2ec3f33e6b94842096d7312ce4ef5f33f6c",

280
emsdk.py
View File

@@ -5,7 +5,6 @@
# found in the LICENSE file. # found in the LICENSE file.
import copy import copy
from collections import OrderedDict
import errno import errno
import json import json
import multiprocessing import multiprocessing
@@ -20,16 +19,17 @@ import sys
import sysconfig import sysconfig
import tarfile import tarfile
import zipfile import zipfile
from collections import OrderedDict
if os.name == 'nt': if os.name == 'nt':
import winreg
import ctypes.wintypes import ctypes.wintypes
import winreg
from urllib.parse import urljoin from urllib.parse import urljoin
from urllib.request import urlopen from urllib.request import urlopen
import functools
if sys.version_info < (3, 0): if sys.version_info < (3, 2): # noqa: UP036
print(f'error: emsdk requires python 3.0 or above ({sys.executable} {sys.version})', file=sys.stderr) print(f'error: emsdk requires python 3.2 or above ({sys.executable} {sys.version})', file=sys.stderr)
sys.exit(1) sys.exit(1)
emsdk_packages_url = 'https://storage.googleapis.com/webassembly/emscripten-releases-builds/deps/' emsdk_packages_url = 'https://storage.googleapis.com/webassembly/emscripten-releases-builds/deps/'
@@ -51,7 +51,10 @@ extra_release_tag = None
# being run. Useful for debugging. # being run. Useful for debugging.
VERBOSE = int(os.getenv('EMSDK_VERBOSE', '0')) VERBOSE = int(os.getenv('EMSDK_VERBOSE', '0'))
QUIET = int(os.getenv('EMSDK_QUIET', '0')) QUIET = int(os.getenv('EMSDK_QUIET', '0'))
TTY_OUTPUT = not os.getenv('EMSDK_NOTTY', not sys.stdout.isatty()) if os.getenv('EMSDK_NOTTY'):
TTY_OUTPUT = False
else:
TTY_OUTPUT = sys.stdout.isatty()
def info(msg): def info(msg):
@@ -132,7 +135,7 @@ else:
# platform.machine() may return AMD64 on windows, so standardize the case. # platform.machine() may return AMD64 on windows, so standardize the case.
machine = os.getenv('EMSDK_ARCH', platform.machine().lower()) machine = os.getenv('EMSDK_ARCH', platform.machine().lower())
if machine.startswith('x64') or machine.startswith('amd64') or machine.startswith('x86_64'): if machine.startswith(('x64', 'amd64', 'x86_64')):
ARCH = 'x86_64' ARCH = 'x86_64'
elif machine.endswith('86'): elif machine.endswith('86'):
ARCH = 'x86' ARCH = 'x86'
@@ -203,17 +206,17 @@ def parse_github_url_and_refspec(url):
return ('', '', None) return ('', '', None)
if url.endswith(('/tree/', '/tree', '/commit/', '/commit')): if url.endswith(('/tree/', '/tree', '/commit/', '/commit')):
raise Exception('Malformed git URL and refspec ' + url + '!') raise Exception(f'Malformed git URL and refspec {url}!')
if '/tree/' in url: if '/tree/' in url:
if url.endswith('/'): if url.endswith('/'):
raise Exception('Malformed git URL and refspec ' + url + '!') raise Exception(f'Malformed git URL and refspec {url}!')
url, refspec = url.split('/tree/') url, refspec = url.split('/tree/')
remote_name = url.split('/')[-2] remote_name = url.split('/')[-2]
return (url, refspec, remote_name) return (url, refspec, remote_name)
elif '/commit/' in url: elif '/commit/' in url:
if url.endswith('/'): if url.endswith('/'):
raise Exception('Malformed git URL and refspec ' + url + '!') raise Exception(f'Malformed git URL and refspec {url}!')
url, refspec = url.split('/commit/') url, refspec = url.split('/commit/')
remote_name = url.split('/')[-2] remote_name = url.split('/')[-2]
return (url, refspec, remote_name) return (url, refspec, remote_name)
@@ -324,7 +327,7 @@ def remove_tree(d):
os.chmod(path, stat.S_IWRITE) os.chmod(path, stat.S_IWRITE)
func(path) func(path)
else: else:
raise raise exc_info[1]
shutil.rmtree(d, onerror=remove_readonly_and_try_again) shutil.rmtree(d, onerror=remove_readonly_and_try_again)
except Exception as e: except Exception as e:
debug_print('remove_tree threw an exception, ignoring: ' + str(e)) debug_print('remove_tree threw an exception, ignoring: ' + str(e))
@@ -340,13 +343,13 @@ def win_set_environment_variable_direct(key, value, system=True):
# Register locally from CURRENT USER section. # Register locally from CURRENT USER section.
folder = winreg.OpenKeyEx(winreg.HKEY_CURRENT_USER, 'Environment', 0, winreg.KEY_ALL_ACCESS) folder = winreg.OpenKeyEx(winreg.HKEY_CURRENT_USER, 'Environment', 0, winreg.KEY_ALL_ACCESS)
winreg.SetValueEx(folder, key, 0, winreg.REG_EXPAND_SZ, value) winreg.SetValueEx(folder, key, 0, winreg.REG_EXPAND_SZ, value)
debug_print('Set key=' + key + ' with value ' + value + ' in registry.') debug_print(f'Set key={key} with value {value} in registry.')
return True return True
except Exception as e: except Exception as e:
# 'Access is denied.' # 'Access is denied.'
if e.args[3] == 5: if e.args[3] == 5:
exit_with_error('failed to set the environment variable \'' + key + '\'! Setting environment variables permanently requires administrator access. Please rerun this command with administrative privileges. This can be done for example by holding down the Ctrl and Shift keys while opening a command prompt in start menu.') exit_with_error(f'failed to set the environment variable \'{key}\'! Setting environment variables permanently requires administrator access. Please rerun this command with administrative privileges. This can be done for example by holding down the Ctrl and Shift keys while opening a command prompt in start menu.')
errlog('Failed to write environment variable ' + key + ':') errlog(f'Failed to write environment variable {key}:')
errlog(str(e)) errlog(str(e))
return False return False
finally: finally:
@@ -384,7 +387,7 @@ def win_get_environment_variable(key, system=True, user=True, fallback=True):
# this catch is if both the registry key threw an exception and the key is not in os.environ # this catch is if both the registry key threw an exception and the key is not in os.environ
if e.args[0] != 2: if e.args[0] != 2:
# 'The system cannot find the file specified.' # 'The system cannot find the file specified.'
errlog('Failed to read environment variable ' + key + ':') errlog(f'Failed to read environment variable {key}:')
errlog(str(e)) errlog(str(e))
return None return None
return value return value
@@ -416,16 +419,16 @@ def win_set_environment_variable(key, value, system, user):
# Escape % signs so that we don't expand references to environment variables. # Escape % signs so that we don't expand references to environment variables.
value = value.replace('%', '^%') value = value.replace('%', '^%')
if len(value) >= 1024: if len(value) >= 1024:
exit_with_error('the new environment variable ' + key + ' is more than 1024 characters long! A value this long cannot be set via command line: please add the environment variable specified above to system environment manually via Control Panel.') exit_with_error(f'the new environment variable {key} is more than 1024 characters long! A value this long cannot be set via command line: please add the environment variable specified above to system environment manually via Control Panel.')
cmd = ['SETX', key, value] cmd = ['SETX', key, value]
debug_print(str(cmd)) debug_print(str(cmd))
retcode = subprocess.call(cmd, stdout=subprocess.PIPE) retcode = subprocess.call(cmd, stdout=subprocess.PIPE)
if retcode != 0: if retcode != 0:
errlog('ERROR! Failed to set environment variable ' + key + '=' + value + '. You may need to set it manually.') errlog(f'ERROR! Failed to set environment variable {key}={value}. You may need to set it manually.')
else: else:
return True return True
except Exception as e: except Exception as e:
errlog('ERROR! Failed to set environment variable ' + key + '=' + value + ':') errlog(f'ERROR! Failed to set environment variable {key}={value}:')
errlog(str(e)) errlog(str(e))
errlog('You may need to set it manually.') errlog('You may need to set it manually.')
@@ -467,7 +470,7 @@ def win_set_environment_variables(env_vars_to_add, system, user):
def win_delete_environment_variable(key, system=True, user=True): def win_delete_environment_variable(key, system=True, user=True):
debug_print('win_delete_environment_variable(key=' + key + ', system=' + str(system) + ')') debug_print(f'win_delete_environment_variable(key={key}, system={system})')
return win_set_environment_variable(key, None, system, user) return win_set_environment_variable(key, None, system, user)
@@ -481,19 +484,14 @@ def sdk_path(path):
# Removes a single file, suppressing exceptions on failure. # Removes a single file, suppressing exceptions on failure.
def rmfile(filename): def rmfile(filename):
debug_print('rmfile(' + filename + ')') debug_print(f'rmfile({filename})')
if os.path.lexists(filename): if os.path.lexists(filename):
os.remove(filename) os.remove(filename)
# http://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python
def mkdir_p(path): def mkdir_p(path):
debug_print('mkdir_p(' + path + ')') debug_print(f'mkdir_p({path})')
try: os.makedirs(path, exist_ok=True)
os.makedirs(path)
except OSError as exc: # Python >2.5
if exc.errno != errno.EEXIST or not os.path.isdir(path):
raise
def is_nonempty_directory(path): def is_nonempty_directory(path):
@@ -513,7 +511,7 @@ def run(cmd, cwd=None, quiet=False):
# http://pythonicprose.blogspot.fi/2009/10/python-extract-targz-archive.html # http://pythonicprose.blogspot.fi/2009/10/python-extract-targz-archive.html
def untargz(source_filename, dest_dir): def untargz(source_filename, dest_dir):
print("Unpacking '" + source_filename + "' to '" + dest_dir + "'") print(f"Unpacking '{source_filename}' to '{dest_dir}'")
mkdir_p(dest_dir) mkdir_p(dest_dir)
returncode = run(['tar', '-xvf' if VERBOSE else '-xf', sdk_path(source_filename), '--strip', '1'], cwd=dest_dir) returncode = run(['tar', '-xvf' if VERBOSE else '-xf', sdk_path(source_filename), '--strip', '1'], cwd=dest_dir)
# tfile = tarfile.open(source_filename, 'r:gz') # tfile = tarfile.open(source_filename, 'r:gz')
@@ -531,7 +529,7 @@ def fix_potentially_long_windows_pathname(pathname):
# Test if emsdk calls fix_potentially_long_windows_pathname() with long # Test if emsdk calls fix_potentially_long_windows_pathname() with long
# relative paths (which is problematic) # relative paths (which is problematic)
if not os.path.isabs(pathname) and len(pathname) > 200: if not os.path.isabs(pathname) and len(pathname) > 200:
errlog('Warning: Seeing a relative path "' + pathname + '" which is dangerously long for being referenced as a short Windows path name. Refactor emsdk to be able to handle this!') errlog(f'Warning: Seeing a relative path "{pathname}" which is dangerously long for being referenced as a short Windows path name. Refactor emsdk to be able to handle this!')
if pathname.startswith('\\\\?\\'): if pathname.startswith('\\\\?\\'):
return pathname return pathname
pathname = os.path.normpath(pathname.replace('/', '\\')) pathname = os.path.normpath(pathname.replace('/', '\\'))
@@ -554,7 +552,7 @@ def move_with_overwrite(src, dest):
# http://stackoverflow.com/questions/12886768/simple-way-to-unzip-file-in-python-on-all-oses # http://stackoverflow.com/questions/12886768/simple-way-to-unzip-file-in-python-on-all-oses
def unzip(source_filename, dest_dir): def unzip(source_filename, dest_dir):
print("Unpacking '" + source_filename + "' to '" + dest_dir + "'") print(f"Unpacking '{source_filename}' to '{dest_dir}'")
mkdir_p(dest_dir) mkdir_p(dest_dir)
common_subdir = None common_subdir = None
try: try:
@@ -609,11 +607,11 @@ def unzip(source_filename, dest_dir):
if common_subdir: if common_subdir:
remove_tree(unzip_to_dir) remove_tree(unzip_to_dir)
except zipfile.BadZipfile as e: except zipfile.BadZipfile as e:
errlog("Unzipping file '" + source_filename + "' failed due to reason: " + str(e) + "! Removing the corrupted zip file.") errlog(f"Unzipping file '{source_filename}' failed due to reason: {e}! Removing the corrupted zip file.")
rmfile(source_filename) rmfile(source_filename)
return False return False
except Exception as e: except Exception as e:
errlog("Unzipping file '" + source_filename + "' failed due to reason: " + str(e)) errlog(f"Unzipping file '{source_filename}' failed due to reason: {e}")
return False return False
return True return True
@@ -724,12 +722,12 @@ def download_with_urllib(url, file_name):
# On success, returns the filename on the disk pointing to the destination file that was produced # On success, returns the filename on the disk pointing to the destination file that was produced
# On failure, returns None. # On failure, returns None.
def download_file(url, dstpath, download_even_if_exists=False, def download_file(url, dstpath, download_even_if_exists=False,
filename_prefix='', silent=False): filename_prefix=''):
debug_print('download_file(url=' + url + ', dstpath=' + dstpath + ')') debug_print(f'download_file(url={url}, dstpath={dstpath})')
file_name = get_download_target(url, dstpath, filename_prefix) file_name = get_download_target(url, dstpath, filename_prefix)
if os.path.exists(file_name) and not download_even_if_exists: if os.path.exists(file_name) and not download_even_if_exists:
print("File '" + file_name + "' already downloaded, skipping.") print(f"File '{file_name}' already downloaded, skipping.")
return file_name return file_name
mkdir_p(os.path.dirname(file_name)) mkdir_p(os.path.dirname(file_name))
@@ -744,7 +742,7 @@ def download_file(url, dstpath, download_even_if_exists=False,
else: else:
download_with_urllib(url, file_name) download_with_urllib(url, file_name)
except Exception as e: except Exception as e:
errlog("Error: Downloading URL '" + url + "': " + str(e)) errlog(f"Error: Downloading URL '{url}': {e}")
return None return None
except KeyboardInterrupt: except KeyboardInterrupt:
rmfile(file_name) rmfile(file_name)
@@ -754,7 +752,7 @@ def download_file(url, dstpath, download_even_if_exists=False,
def run_get_output(cmd, cwd=None): def run_get_output(cmd, cwd=None):
debug_print('run_get_output(cmd=' + str(cmd) + ', cwd=' + str(cwd) + ')') debug_print(f'run_get_output(cmd={cmd}, cwd={cwd})')
process = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, env=os.environ.copy(), universal_newlines=True) process = subprocess.Popen(cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, env=os.environ.copy(), universal_newlines=True)
stdout, stderr = process.communicate() stdout, stderr = process.communicate()
return (process.returncode, stdout, stderr) return (process.returncode, stdout, stderr)
@@ -822,31 +820,31 @@ def get_git_remotes(repo_path):
def git_clone(url, dstpath, branch, remote_name='origin'): def git_clone(url, dstpath, branch, remote_name='origin'):
debug_print('git_clone(url=' + url + ', dstpath=' + dstpath + ')') debug_print(f'git_clone(url={url}, dstpath={dstpath})')
if os.path.isdir(os.path.join(dstpath, '.git')): if os.path.isdir(os.path.join(dstpath, '.git')):
remotes = get_git_remotes(dstpath) remotes = get_git_remotes(dstpath)
if remote_name in remotes: if remote_name in remotes:
debug_print('Repository ' + url + ' with remote "' + remote_name + '" already cloned to directory ' + dstpath + ', skipping.') debug_print(f'Repository {url} with remote "{remote_name}" already cloned to directory {dstpath}, skipping.')
return True return True
else: else:
debug_print('Repository ' + url + ' with remote "' + remote_name + '" already cloned to directory ' + dstpath + ', but remote has not yet been added. Creating.') debug_print(f'Repository {url} with remote "{remote_name}" already cloned to directory {dstpath}, but remote has not yet been added. Creating.')
return run([GIT(), 'remote', 'add', remote_name, url], cwd=dstpath) == 0 return run([GIT(), 'remote', 'add', remote_name, url], cwd=dstpath) == 0
mkdir_p(dstpath) mkdir_p(dstpath)
git_clone_args = ['--recurse-submodules', '--branch', branch] # Do not check out a branch (installer will issue a checkout command right after) git_clone_args = ['--recurse-submodules', '--branch', branch] # Do not check out a branch (installer will issue a checkout command right after)
if GIT_CLONE_SHALLOW: if GIT_CLONE_SHALLOW:
git_clone_args += ['--depth', '1'] git_clone_args += ['--depth', '1']
print('Cloning from ' + url + '...') print(f'Cloning from {url}...')
return run([GIT(), 'clone', '-o', remote_name] + git_clone_args + [url, dstpath]) == 0 return run([GIT(), 'clone', '-o', remote_name] + git_clone_args + [url, dstpath]) == 0
def git_pull(repo_path, branch_or_tag, remote_name='origin'): def git_pull(repo_path, branch_or_tag, remote_name='origin'):
debug_print('git_pull(repo_path=' + repo_path + ', branch/tag=' + branch_or_tag + ', remote_name=' + remote_name + ')') debug_print(f'git_pull(repo_path={repo_path}, branch/tag={branch_or_tag}, remote_name={remote_name})')
ret = run([GIT(), 'fetch', '--quiet', remote_name], repo_path) ret = run([GIT(), 'fetch', '--quiet', remote_name], repo_path)
if ret != 0: if ret != 0:
return False return False
try: try:
print("Fetching latest changes to the branch/tag '" + branch_or_tag + "' for '" + repo_path + "'...") print(f"Fetching latest changes to the branch/tag '{branch_or_tag}' for '{repo_path}'...")
ret = run([GIT(), 'fetch', '--quiet', remote_name], repo_path) ret = run([GIT(), 'fetch', '--quiet', remote_name], repo_path)
if ret != 0: if ret != 0:
return False return False
@@ -871,13 +869,13 @@ def git_pull(repo_path, branch_or_tag, remote_name='origin'):
except Exception: except Exception:
errlog('git operation failed!') errlog('git operation failed!')
return False return False
print("Successfully updated and checked out branch/tag '" + branch_or_tag + "' on repository '" + repo_path + "'") print(f"Successfully updated and checked out branch/tag '{branch_or_tag}' on repository '{repo_path}'")
print("Current repository version: " + git_repo_version(repo_path)) print("Current repository version: " + git_repo_version(repo_path))
return True return True
def git_clone_checkout_and_pull(url, dstpath, branch, override_remote_name='origin'): def git_clone_checkout_and_pull(url, dstpath, branch, override_remote_name='origin'):
debug_print('git_clone_checkout_and_pull(url=' + url + ', dstpath=' + dstpath + ', branch=' + branch + ', override_remote_name=' + override_remote_name + ')') debug_print(f'git_clone_checkout_and_pull(url={url}, dstpath={dstpath}, branch={branch}, override_remote_name={override_remote_name})')
# Make sure the repository is cloned first # Make sure the repository is cloned first
success = git_clone(url, dstpath, branch, override_remote_name) success = git_clone(url, dstpath, branch, override_remote_name)
@@ -940,19 +938,19 @@ def llvm_build_bin_dir(tool):
return os.path.join(build_dir, 'bin') return os.path.join(build_dir, 'bin')
def build_env(generator): def build_env():
build_env = os.environ.copy() env = os.environ.copy()
# To work around a build issue with older Mac OS X builds, add -stdlib=libc++ to all builds. # To work around a build issue with older Mac OS X builds, add -stdlib=libc++ to all builds.
# See https://groups.google.com/forum/#!topic/emscripten-discuss/5Or6QIzkqf0 # See https://groups.google.com/forum/#!topic/emscripten-discuss/5Or6QIzkqf0
if MACOS: if MACOS:
build_env['CXXFLAGS'] = ((build_env['CXXFLAGS'] + ' ') if hasattr(build_env, 'CXXFLAGS') else '') + '-stdlib=libc++' env['CXXFLAGS'] = ((env['CXXFLAGS'] + ' ') if hasattr(env, 'CXXFLAGS') else '') + '-stdlib=libc++'
if WINDOWS: if WINDOWS:
# MSBuild.exe has an internal mechanism to avoid N^2 oversubscription of threads in its two-tier build model, see # MSBuild.exe has an internal mechanism to avoid N^2 oversubscription of threads in its two-tier build model, see
# https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/ # https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/
build_env['UseMultiToolTask'] = 'true' env['UseMultiToolTask'] = 'true'
build_env['EnforceProcessCountAcrossBuilds'] = 'true' env['EnforceProcessCountAcrossBuilds'] = 'true'
return build_env return env
# Find path to cmake executable, as one of the activated tools, in PATH, or from installed tools. # Find path to cmake executable, as one of the activated tools, in PATH, or from installed tools.
@@ -970,13 +968,13 @@ def find_cmake():
if tool.id == 'cmake' and tool.is_active(): if tool.id == 'cmake' and tool.is_active():
cmake_exe = locate_cmake_from_tool(tool) cmake_exe = locate_cmake_from_tool(tool)
if cmake_exe: if cmake_exe:
info('Found installed+activated CMake tool at "' + cmake_exe + '"') info(f'Found installed+activated CMake tool at "{cmake_exe}"')
return cmake_exe return cmake_exe
# 2. If cmake already exists in PATH, then use that cmake to configure the build. # 2. If cmake already exists in PATH, then use that cmake to configure the build.
cmake_exe = which('cmake') cmake_exe = which('cmake')
if cmake_exe: if cmake_exe:
info('Found CMake from PATH at "' + cmake_exe + '"') info(f'Found CMake from PATH at "{cmake_exe}"')
return cmake_exe return cmake_exe
# 3. Finally, if user has installed a cmake tool, but has not activated that, then use # 3. Finally, if user has installed a cmake tool, but has not activated that, then use
@@ -987,14 +985,14 @@ def find_cmake():
if tool.id == 'cmake' and tool.is_installed(): if tool.id == 'cmake' and tool.is_installed():
cmake_exe = locate_cmake_from_tool(tool) cmake_exe = locate_cmake_from_tool(tool)
if cmake_exe: if cmake_exe:
info('Found installed CMake tool at "' + cmake_exe + '"') info(f'Found installed CMake tool at "{cmake_exe}"')
return cmake_exe return cmake_exe
exit_with_error('Unable to find "cmake" in PATH, or as installed/activated tool! Please install CMake first') exit_with_error('Unable to find "cmake" in PATH, or as installed/activated tool! Please install CMake first')
def make_build(build_root, build_type): def make_build(build_root, build_type):
debug_print('make_build(build_root=' + build_root + ', build_type=' + build_type + ')') debug_print(f'make_build(build_root={build_root}, build_type={build_type})')
if CPU_CORES > 1: if CPU_CORES > 1:
print('Performing a parallel build with ' + str(CPU_CORES) + ' cores.') print('Performing a parallel build with ' + str(CPU_CORES) + ' cores.')
else: else:
@@ -1016,9 +1014,9 @@ def make_build(build_root, build_type):
# Build # Build
try: try:
print('Running build: ' + str(make)) print('Running build: ' + str(make))
ret = subprocess.check_call(make, cwd=build_root, env=build_env(CMAKE_GENERATOR)) ret = subprocess.check_call(make, cwd=build_root, env=build_env())
if ret != 0: if ret != 0:
errlog('Build failed with exit code ' + ret + '!') errlog('Build failed with exit code {ret}!')
errlog('Working directory: ' + build_root) errlog('Working directory: ' + build_root)
return False return False
except Exception as e: except Exception as e:
@@ -1030,7 +1028,7 @@ def make_build(build_root, build_type):
return True return True
def cmake_configure(generator, build_root, src_root, build_type, extra_cmake_args=[]): def cmake_configure(generator, build_root, src_root, build_type, extra_cmake_args):
debug_print('cmake_configure(generator=' + str(generator) + ', build_root=' + str(build_root) + ', src_root=' + str(src_root) + ', build_type=' + str(build_type) + ', extra_cmake_args=' + str(extra_cmake_args) + ')') debug_print('cmake_configure(generator=' + str(generator) + ', build_root=' + str(build_root) + ', src_root=' + str(src_root) + ', build_type=' + str(build_type) + ', extra_cmake_args=' + str(extra_cmake_args) + ')')
# Configure # Configure
if not os.path.isdir(build_root): if not os.path.isdir(build_root):
@@ -1063,9 +1061,9 @@ def cmake_configure(generator, build_root, src_root, build_type, extra_cmake_arg
# Create a file 'recmake.bat/sh' in the build root that user can call to # Create a file 'recmake.bat/sh' in the build root that user can call to
# manually recmake the build tree with the previous build params # manually recmake the build tree with the previous build params
open(os.path.join(build_root, 'recmake.' + ('bat' if WINDOWS else 'sh')), 'w').write(' '.join(map(quote_parens, cmdline))) open(os.path.join(build_root, 'recmake.' + ('bat' if WINDOWS else 'sh')), 'w').write(' '.join(map(quote_parens, cmdline)))
ret = subprocess.check_call(cmdline, cwd=build_root, env=build_env(CMAKE_GENERATOR)) ret = subprocess.check_call(cmdline, cwd=build_root, env=build_env())
if ret != 0: if ret != 0:
errlog('CMake invocation failed with exit code ' + ret + '!') errlog('CMake invocation failed with exit code {ret}!')
errlog('Working directory: ' + build_root) errlog('Working directory: ' + build_root)
return False return False
except OSError as e: except OSError as e:
@@ -1091,9 +1089,7 @@ def cmake_configure(generator, build_root, src_root, build_type, extra_cmake_arg
def xcode_sdk_version(): def xcode_sdk_version():
try: try:
output = subprocess.check_output(['xcrun', '--show-sdk-version']) output = subprocess.check_output(['xcrun', '--show-sdk-version'], universal_newlines=True)
if sys.version_info >= (3,):
output = output.decode('utf8')
return output.strip().split('.') return output.strip().split('.')
except Exception: except Exception:
return subprocess.checkplatform.mac_ver()[0].split('.') return subprocess.checkplatform.mac_ver()[0].split('.')
@@ -1120,7 +1116,7 @@ def cmake_host_platform():
'arm64': 'ARM64', 'arm64': 'ARM64',
'arm': 'ARM', 'arm': 'ARM',
'x86_64': 'x64', 'x86_64': 'x64',
'x86': 'x86' 'x86': 'x86',
} }
return arch_to_cmake_host_platform[ARCH] return arch_to_cmake_host_platform[ARCH]
@@ -1158,7 +1154,7 @@ def build_llvm(tool):
enable_assertions = ENABLE_LLVM_ASSERTIONS.lower() == 'on' or (ENABLE_LLVM_ASSERTIONS == 'auto' and build_type.lower() != 'release' and build_type.lower() != 'minsizerel') enable_assertions = ENABLE_LLVM_ASSERTIONS.lower() == 'on' or (ENABLE_LLVM_ASSERTIONS == 'auto' and build_type.lower() != 'release' and build_type.lower() != 'minsizerel')
if ARCH == 'x86' or ARCH == 'x86_64': if ARCH in ('x86', 'x86_64'):
targets_to_build = 'WebAssembly;X86' targets_to_build = 'WebAssembly;X86'
elif ARCH == 'arm': elif ARCH == 'arm':
targets_to_build = 'WebAssembly;ARM' targets_to_build = 'WebAssembly;ARM'
@@ -1387,13 +1383,13 @@ def download_firefox(tool):
# Abort if detaching was not successful # Abort if detaching was not successful
if os.path.exists(mount_point): if os.path.exists(mount_point):
raise Exception('Previous mount of Firefox already exists at "' + mount_point + '", unable to proceed.') raise Exception(f'Previous mount of Firefox already exists at "{mount_point}", unable to proceed.')
# Mount the archive # Mount the archive
run(['hdiutil', 'attach', filename]) run(['hdiutil', 'attach', filename])
firefox_dir = os.path.join(mount_point, app_name) firefox_dir = os.path.join(mount_point, app_name)
if not os.path.isdir(firefox_dir): if not os.path.isdir(firefox_dir):
raise Exception('Unable to find Firefox directory "' + firefox_dir + '" inside app image.') raise Exception(f'Unable to find Firefox directory "{firefox_dir}" inside app image.')
# And install by copying the files from the archive # And install by copying the files from the archive
shutil.copytree(firefox_dir, root) shutil.copytree(firefox_dir, root)
@@ -1512,7 +1508,7 @@ def emscripten_npm_install(tool, directory):
# Binaryen build scripts: # Binaryen build scripts:
def binaryen_build_root(tool): def binaryen_build_root(tool):
build_root = tool.installation_path().strip() build_root = tool.installation_path().strip()
if build_root.endswith('/') or build_root.endswith('\\'): if build_root.endswith(('/', '\\')):
build_root = build_root[:-1] build_root = build_root[:-1]
generator_prefix = cmake_generator_prefix() generator_prefix = cmake_generator_prefix()
build_root = build_root + generator_prefix + '_' + str(tool.bitness) + 'bit_binaryen' build_root = build_root + generator_prefix + '_' + str(tool.bitness) + 'bit_binaryen'
@@ -1522,7 +1518,7 @@ def binaryen_build_root(tool):
def uninstall_binaryen(tool): def uninstall_binaryen(tool):
debug_print('uninstall_binaryen(' + str(tool) + ')') debug_print('uninstall_binaryen(' + str(tool) + ')')
build_root = binaryen_build_root(tool) build_root = binaryen_build_root(tool)
print("Deleting path '" + build_root + "'") print(f"Deleting path '{build_root}'")
remove_tree(build_root) remove_tree(build_root)
@@ -1563,23 +1559,22 @@ def build_binaryen_tool(tool):
def download_and_extract(archive, dest_dir, filename_prefix='', clobber=True): def download_and_extract(archive, dest_dir, filename_prefix='', clobber=True):
debug_print('download_and_extract(archive=' + archive + ', dest_dir=' + dest_dir + ')') debug_print('download_and_extract(archive={archive}, dest_dir={dest_dir})')
url = urljoin(emsdk_packages_url, archive) url = urljoin(emsdk_packages_url, archive)
def try_download(url, silent=False): def try_download(url):
return download_file(url, download_dir, not KEEP_DOWNLOADS, return download_file(url, download_dir, not KEEP_DOWNLOADS, filename_prefix)
filename_prefix, silent=silent)
# Special hack for the wasm-binaries we transitioned from `.bzip2` to # Special hack for the wasm-binaries we transitioned from `.bzip2` to
# `.xz`, but we can't tell from the version/url which one to use, so # `.xz`, but we can't tell from the version/url which one to use, so
# try one and then fall back to the other. # try one and then fall back to the other.
success = False success = False
if 'wasm-binaries' in archive and os.path.splitext(archive)[1] == '.xz': if 'wasm-binaries' in archive and os.path.splitext(archive)[1] == '.xz':
success = try_download(url, silent=True) success = try_download(url)
if not success: if not success:
alt_url = url.replace('.tar.xz', '.tbz2') alt_url = url.replace('.tar.xz', '.tbz2')
success = try_download(alt_url, silent=True) success = try_download(alt_url)
if success: if success:
url = alt_url url = alt_url
@@ -1653,7 +1648,7 @@ def load_em_config():
EM_CONFIG_DICT.clear() EM_CONFIG_DICT.clear()
lines = [] lines = []
try: try:
lines = open(EM_CONFIG_PATH, "r").read().split('\n') lines = open(EM_CONFIG_PATH).read().split('\n')
except Exception: except Exception:
pass pass
for line in lines: for line in lines:
@@ -1723,7 +1718,7 @@ def extract_newest_node_nightly_version(versions):
def download_node_nightly(tool): def download_node_nightly(tool):
nightly_versions = fetch_nightly_node_versions() nightly_versions = fetch_nightly_node_versions()
latest_nightly = extract_newest_node_nightly_version(nightly_versions) latest_nightly = extract_newest_node_nightly_version(nightly_versions)
print('Latest Node.js Nightly download available is "' + latest_nightly + '"') print('Latest Node.js Nightly download available is "{latest_nightly}"')
output_dir = os.path.abspath('node/nightly-' + latest_nightly) output_dir = os.path.abspath('node/nightly-' + latest_nightly)
# Node.js zip structure quirk: Linux and macOS archives have a /bin, # Node.js zip structure quirk: Linux and macOS archives have a /bin,
@@ -1794,9 +1789,9 @@ def generate_em_config(active_tools, permanently_activate, system):
for name, value in activated_config.items(): for name, value in activated_config.items():
if value.startswith('['): if value.startswith('['):
cfg += name + " = " + value + "\n" cfg += f'{name} = {value}\n'
else: else:
cfg += name + " = '" + value + "'\n" cfg += f"{name} = '{value}'\n"
emroot = find_emscripten_root(active_tools) emroot = find_emscripten_root(active_tools)
if emroot: if emroot:
@@ -1856,14 +1851,11 @@ def find_msbuild_dir():
return '' return ''
class Tool(object): class Tool:
def __init__(self, data): def __init__(self, data):
# Convert the dictionary representation of the tool in 'data' to members of # Convert the dictionary representation of the tool in 'data' to members of
# this class for convenience. # this class for convenience.
for key, value in data.items(): for key, value in data.items():
# Python2 compat, convert unicode to str
if sys.version_info < (3,) and isinstance(value, unicode): # noqa
value = value.encode('Latin-1')
setattr(self, key, value) setattr(self, key, value)
# Cache the name ID of this Tool (these are read very often) # Cache the name ID of this Tool (these are read very often)
@@ -1916,7 +1908,7 @@ class Tool(object):
for tool_name in self.uses: for tool_name in self.uses:
tool = find_tool(tool_name) tool = find_tool(tool_name)
if not tool: if not tool:
debug_print('Tool ' + str(self) + ' depends on ' + tool_name + ' which does not exist!') debug_print(f'Tool {self} depends on {tool_name} which does not exist!')
continue continue
if tool.needs_compilation(): if tool.needs_compilation():
return True return True
@@ -2008,14 +2000,13 @@ class Tool(object):
def is_installed_version(self): def is_installed_version(self):
version_file_path = self.get_version_file_path() version_file_path = self.get_version_file_path()
if os.path.isfile(version_file_path): if os.path.isfile(version_file_path):
with open(version_file_path, 'r') as version_file: with open(version_file_path) as version_file:
return version_file.read().strip() == self.name return version_file.read().strip() == self.name
return False return False
def update_installed_version(self): def update_installed_version(self):
with open(self.get_version_file_path(), 'w') as version_file: with open(self.get_version_file_path(), 'w') as version_file:
version_file.write(self.name + '\n') version_file.write(self.name + '\n')
return None
def is_installed(self, skip_version_check=False): def is_installed(self, skip_version_check=False):
# If this tool/sdk depends on other tools, require that all dependencies are # If this tool/sdk depends on other tools, require that all dependencies are
@@ -2024,7 +2015,7 @@ class Tool(object):
for tool_name in self.uses: for tool_name in self.uses:
tool = find_tool(tool_name) tool = find_tool(tool_name)
if tool is None: if tool is None:
errlog("Manifest error: No tool by name '" + tool_name + "' found! This may indicate an internal SDK error!") errlog(f"Manifest error: No tool by name '{tool_name}' found! This may indicate an internal SDK error!")
return False return False
if not tool.is_installed(): if not tool.is_installed():
return False return False
@@ -2072,7 +2063,7 @@ class Tool(object):
for key, value in activated_cfg.items(): for key, value in activated_cfg.items():
if key not in EM_CONFIG_DICT: if key not in EM_CONFIG_DICT:
debug_print(str(self) + ' is not active, because key="' + key + '" does not exist in .emscripten') debug_print(f'{self} is not active, because key="{key}" does not exist in .emscripten')
return False return False
# all paths are stored dynamically relative to the emsdk root, so # all paths are stored dynamically relative to the emsdk root, so
@@ -2080,7 +2071,7 @@ class Tool(object):
config_value = EM_CONFIG_DICT[key].replace("emsdk_path + '", "'" + EMSDK_PATH) config_value = EM_CONFIG_DICT[key].replace("emsdk_path + '", "'" + EMSDK_PATH)
config_value = config_value.strip("'") config_value = config_value.strip("'")
if config_value != value: if config_value != value:
debug_print(str(self) + ' is not active, because key="' + key + '" has value "' + config_value + '" but should have value "' + value + '"') debug_print(f'{self} is not active, because key="{key}" has value "{config_value}" but should have value "{value}"')
return False return False
return True return True
@@ -2090,7 +2081,7 @@ class Tool(object):
for env in envs: for env in envs:
key, value = parse_key_value(env) key, value = parse_key_value(env)
if key not in os.environ or to_unix_path(os.environ[key]) != to_unix_path(value): if key not in os.environ or to_unix_path(os.environ[key]) != to_unix_path(value):
debug_print(str(self) + ' is not active, because environment variable key="' + key + '" has value "' + str(os.getenv(key)) + '" but should have value "' + value + '"') debug_print(f'{self} is not active, because environment variable key="{key}" has value "{os.getenv(key)}" but should have value "{value}"')
return False return False
if hasattr(self, 'activated_path'): if hasattr(self, 'activated_path'):
@@ -2098,7 +2089,7 @@ class Tool(object):
for p in path: for p in path:
path_items = os.environ['PATH'].replace('\\', '/').split(ENVPATH_SEPARATOR) path_items = os.environ['PATH'].replace('\\', '/').split(ENVPATH_SEPARATOR)
if not normalized_contains(path_items, p): if not normalized_contains(path_items, p):
debug_print(str(self) + ' is not active, because environment variable PATH item "' + p + '" is not present (PATH=' + os.environ['PATH'] + ')') debug_print(f'{self} is not active, because environment variable PATH item "{p}" is not present (PATH={os.environ["PATH"]})')
return False return False
return True return True
@@ -2130,7 +2121,7 @@ class Tool(object):
already being installed. already being installed.
""" """
if self.can_be_installed() is not True: if self.can_be_installed() is not True:
exit_with_error("The tool '" + str(self) + "' is not available due to the reason: " + self.can_be_installed()) exit_with_error(f"The tool '{self}' is not available due to the reason: {self.can_be_installed()}")
if self.id == 'sdk': if self.id == 'sdk':
return self.install_sdk() return self.install_sdk()
@@ -2141,17 +2132,17 @@ class Tool(object):
"""Returns True if any SDK component was installed of False all componented """Returns True if any SDK component was installed of False all componented
were already installed. were already installed.
""" """
print("Installing SDK '" + str(self) + "'..") print(f"Installing SDK '{self}'..")
installed = False installed = False
for tool_name in self.uses: for tool_name in self.uses:
tool = find_tool(tool_name) tool = find_tool(tool_name)
if tool is None: if tool is None:
exit_with_error("manifest error: No tool by name '" + tool_name + "' found! This may indicate an internal SDK error!") exit_with_error(f"manifest error: No tool by name '{tool_name}' found! This may indicate an internal SDK error!")
installed |= tool.install() installed |= tool.install()
if not installed: if not installed:
print("All SDK components already installed: '" + str(self) + "'.") print(f"All SDK components already installed: '{self}'.")
return False return False
if getattr(self, 'custom_install_script', None) == 'emscripten_npm_install': if getattr(self, 'custom_install_script', None) == 'emscripten_npm_install':
@@ -2164,7 +2155,7 @@ class Tool(object):
if not emscripten_npm_install(self, emscripten_dir): if not emscripten_npm_install(self, emscripten_dir):
exit_with_error('post-install step failed: emscripten_npm_install') exit_with_error('post-install step failed: emscripten_npm_install')
print("Done installing SDK '" + str(self) + "'.") print(f"Done installing SDK '{self}'.")
return True return True
def install_tool(self): def install_tool(self):
@@ -2176,10 +2167,10 @@ class Tool(object):
# installed every time when requested, since the install step is then used to git # installed every time when requested, since the install step is then used to git
# pull the tool to a newer version. # pull the tool to a newer version.
if self.is_installed() and not hasattr(self, 'git_branch'): if self.is_installed() and not hasattr(self, 'git_branch'):
print("Skipped installing " + self.name + ", already installed.") print(f"Skipped installing {self.name}, already installed.")
return False return False
print("Installing tool '" + str(self) + "'..") print(f"Installing tool '{self}'..")
url = self.download_url() url = self.download_url()
custom_install_scripts = { custom_install_scripts = {
@@ -2187,7 +2178,7 @@ class Tool(object):
'build_ninja': build_ninja, 'build_ninja': build_ninja,
'build_ccache': build_ccache, 'build_ccache': build_ccache,
'download_node_nightly': download_node_nightly, 'download_node_nightly': download_node_nightly,
'download_firefox': download_firefox 'download_firefox': download_firefox,
} }
if hasattr(self, 'custom_install_script') and self.custom_install_script in custom_install_scripts: if hasattr(self, 'custom_install_script') and self.custom_install_script in custom_install_scripts:
success = custom_install_scripts[self.custom_install_script](self) success = custom_install_scripts[self.custom_install_script](self)
@@ -2227,12 +2218,12 @@ class Tool(object):
with open(emscripten_version_file_path, 'w') as f: with open(emscripten_version_file_path, 'w') as f:
f.write('"%s"\n' % version) f.write('"%s"\n' % version)
print("Done installing tool '" + str(self) + "'.") print(f"Done installing tool '{self}'.")
# Sanity check that the installation succeeded, and if so, remove unneeded # Sanity check that the installation succeeded, and if so, remove unneeded
# leftover installation files. # leftover installation files.
if not self.is_installed(skip_version_check=True): if not self.is_installed(skip_version_check=True):
exit_with_error("installation of '" + str(self) + "' failed, but no error was detected. Either something went wrong with the installation, or this may indicate an internal emsdk error.") exit_with_error(f"installation of '{self}' failed, but no error was detected. Either something went wrong with the installation, or this may indicate an internal emsdk error.")
self.cleanup_temp_install_files() self.cleanup_temp_install_files()
self.update_installed_version() self.update_installed_version()
@@ -2244,22 +2235,22 @@ class Tool(object):
url = self.download_url() url = self.download_url()
if url.endswith(ARCHIVE_SUFFIXES): if url.endswith(ARCHIVE_SUFFIXES):
download_target = get_download_target(url, download_dir, getattr(self, 'download_prefix', '')) download_target = get_download_target(url, download_dir, getattr(self, 'download_prefix', ''))
debug_print("Deleting temporary download: " + download_target) debug_print(f"Deleting temporary download: {download_target}")
rmfile(download_target) rmfile(download_target)
def uninstall(self): def uninstall(self):
if not self.is_installed(): if not self.is_installed():
print("Tool '" + str(self) + "' was not installed. No need to uninstall.") print(f"Tool '{self}' was not installed. No need to uninstall.")
return return
print("Uninstalling tool '" + str(self) + "'..") print(f"Uninstalling tool '{self}'..")
if hasattr(self, 'custom_uninstall_script'): if hasattr(self, 'custom_uninstall_script'):
if self.custom_uninstall_script == 'uninstall_binaryen': if self.custom_uninstall_script == 'uninstall_binaryen':
uninstall_binaryen(self) uninstall_binaryen(self)
else: else:
raise Exception('Unknown custom_uninstall_script directive "' + self.custom_uninstall_script + '"!') raise Exception(f'Unknown custom_uninstall_script directive "{self.custom_uninstall_script}"!')
print("Deleting path '" + self.installation_path() + "'") print(f"Deleting path '{self.installation_path()}'")
remove_tree(self.installation_path()) remove_tree(self.installation_path())
print("Done uninstalling '" + str(self) + "'.") print(f"Done uninstalling '{self}'.")
def dependencies(self): def dependencies(self):
if not hasattr(self, 'uses'): if not hasattr(self, 'uses'):
@@ -2412,22 +2403,13 @@ def get_emscripten_releases_tot():
def get_release_hash(arg, releases_info): def get_release_hash(arg, releases_info):
return releases_info.get(arg, None) or releases_info.get('sdk-' + arg + '-64bit') return releases_info.get(arg, None) or releases_info.get(f'sdk-{arg}-64bit')
def version_key(ver): def version_key(ver):
return tuple(map(int, re.split('[._-]', ver)[:3])) return tuple(map(int, re.split('[._-]', ver)[:3]))
# A sort function that is compatible with both Python 2 and Python 3 using a
# custom comparison function.
def python_2_3_sorted(arr, cmp):
if sys.version_info >= (3,):
return sorted(arr, key=functools.cmp_to_key(cmp))
else:
return sorted(arr, cmp=cmp)
def is_emsdk_sourced_from_github(): def is_emsdk_sourced_from_github():
return os.path.exists(os.path.join(EMSDK_PATH, '.git')) return os.path.exists(os.path.join(EMSDK_PATH, '.git'))
@@ -2443,11 +2425,11 @@ def update_emsdk():
# Lists all legacy (pre-emscripten-releases) tagged versions directly in the Git # Lists all legacy (pre-emscripten-releases) tagged versions directly in the Git
# repositories. These we can pull and compile from source. # repositories. These we can pull and compile from source.
def load_legacy_emscripten_tags(): def load_legacy_emscripten_tags():
return open(sdk_path('legacy-emscripten-tags.txt'), 'r').read().split('\n') return open(sdk_path('legacy-emscripten-tags.txt')).read().split('\n')
def load_legacy_binaryen_tags(): def load_legacy_binaryen_tags():
return open(sdk_path('legacy-binaryen-tags.txt'), 'r').read().split('\n') return open(sdk_path('legacy-binaryen-tags.txt')).read().split('\n')
def remove_prefix(s, prefix): def remove_prefix(s, prefix):
@@ -2479,7 +2461,7 @@ def load_file_index_list(filename):
def load_releases_info(): def load_releases_info():
if not hasattr(load_releases_info, 'cached_info'): if not hasattr(load_releases_info, 'cached_info'):
try: try:
text = open(sdk_path('emscripten-releases-tags.json'), 'r').read() text = open(sdk_path('emscripten-releases-tags.json')).read()
load_releases_info.cached_info = json.loads(text) load_releases_info.cached_info = json.loads(text)
except Exception as e: except Exception as e:
print('Error parsing emscripten-releases-tags.json!') print('Error parsing emscripten-releases-tags.json!')
@@ -2502,7 +2484,7 @@ def load_releases_tags():
tags = [] tags = []
info = load_releases_info() info = load_releases_info()
for version, sha in sorted(info['releases'].items(), key=lambda x: version_key(x[0])): for _version, sha in sorted(info['releases'].items(), key=lambda x: version_key(x[0])):
tags.append(sha) tags.append(sha)
if extra_release_tag: if extra_release_tag:
@@ -2524,15 +2506,9 @@ def load_releases_versions():
return versions return versions
def is_string(s):
if sys.version_info[0] >= 3:
return isinstance(s, str)
return isinstance(s, basestring) # noqa
def load_sdk_manifest(): def load_sdk_manifest():
try: try:
manifest = json.loads(open(sdk_path("emsdk_manifest.json"), "r").read()) manifest = json.loads(open(sdk_path("emsdk_manifest.json")).read())
except Exception as e: except Exception as e:
print('Error parsing emsdk_manifest.json!') print('Error parsing emsdk_manifest.json!')
print(str(e)) print(str(e))
@@ -2566,7 +2542,7 @@ def load_sdk_manifest():
return version_key(ver) == version_key(reference) return version_key(ver) == version_key(reference)
if cmp_operand == '!=': if cmp_operand == '!=':
return version_key(ver) != version_key(reference) return version_key(ver) != version_key(reference)
raise Exception('Invalid cmp_operand "' + cmp_operand + '"!') raise Exception(f'Invalid cmp_operand "{cmp_operand}"!')
def passes_filters(param, ver, filters): def passes_filters(param, ver, filters):
for v in filters: for v in filters:
@@ -2583,7 +2559,7 @@ def load_sdk_manifest():
t2 = copy.copy(t) t2 = copy.copy(t)
found_param = False found_param = False
for p, v in vars(t2).items(): for p, v in vars(t2).items():
if is_string(v) and param in v: if isinstance(v, str) and param in v:
t2.__dict__[p] = v.replace(param, ver) t2.__dict__[p] = v.replace(param, ver)
found_param = True found_param = True
if not found_param: if not found_param:
@@ -2703,7 +2679,7 @@ def set_active_tools(tools_to_activate, permanently_activate, system):
if tools_to_activate: if tools_to_activate:
tools = [x for x in tools_to_activate if not x.is_sdk] tools = [x for x in tools_to_activate if not x.is_sdk]
print('Setting the following tools as active:\n ' + '\n '.join(map(lambda x: str(x), tools))) print('Setting the following tools as active:\n ' + '\n '.join([str(t) for t in tools]))
print('') print('')
generate_em_config(tools_to_activate, permanently_activate, system) generate_em_config(tools_to_activate, permanently_activate, system)
@@ -2889,15 +2865,15 @@ def construct_env_with_vars(env_vars_to_add):
continue continue
info(key + ' = ' + value) info(key + ' = ' + value)
if POWERSHELL: if POWERSHELL:
env_string += '$env:' + key + '="' + value + '"\n' env_string += f'$env:{key}="{value}"\n'
elif CMD: elif CMD:
env_string += 'SET ' + key + '=' + value + '\n' env_string += f'SET {key}={value}\n'
elif CSH: elif CSH:
env_string += 'setenv ' + key + ' "' + value + '";\n' env_string += f'setenv {key} "{value}";\n'
elif FISH: elif FISH:
env_string += 'set -gx ' + key + ' "' + value + '";\n' env_string += f'set -gx {key} "{value}";\n'
elif BASH: elif BASH:
env_string += 'export ' + key + '="' + value + '";\n' env_string += f'export {key}="{value}";\n'
else: else:
assert False assert False
@@ -2913,9 +2889,9 @@ def construct_env_with_vars(env_vars_to_add):
# of the SDK but we want to remove that from the current environment # of the SDK but we want to remove that from the current environment
# if no such tool is active. # if no such tool is active.
# Ignore certain keys that are inputs to emsdk itself. # Ignore certain keys that are inputs to emsdk itself.
ignore_keys = set(['EMSDK_POWERSHELL', 'EMSDK_CSH', 'EMSDK_CMD', 'EMSDK_BASH', 'EMSDK_FISH', ignore_keys = {'EMSDK_POWERSHELL', 'EMSDK_CSH', 'EMSDK_CMD', 'EMSDK_BASH', 'EMSDK_FISH',
'EMSDK_NUM_CORES', 'EMSDK_NOTTY', 'EMSDK_KEEP_DOWNLOADS']) 'EMSDK_NUM_CORES', 'EMSDK_NOTTY', 'EMSDK_KEEP_DOWNLOADS'}
env_keys_to_add = set(pair[0] for pair in env_vars_to_add) env_keys_to_add = {pair[0] for pair in env_vars_to_add}
for key in os.environ: for key in os.environ:
if key.startswith('EMSDK_') or key in ('EM_CACHE', 'EM_CONFIG'): if key.startswith('EMSDK_') or key in ('EM_CACHE', 'EM_CONFIG'):
if key not in env_keys_to_add and key not in ignore_keys: if key not in env_keys_to_add and key not in ignore_keys:
@@ -2979,7 +2955,7 @@ def expand_sdk_name(name, activating):
return name return name
def main(args): def main(args): # noqa: C901, PLR0911, PLR0912, PLR0915
if not args: if not args:
errlog("Missing command; Type 'emsdk help' to get a list of commands.") errlog("Missing command; Type 'emsdk help' to get a list of commands.")
return 1 return 1
@@ -3162,11 +3138,11 @@ def main(args):
tool_name, url_and_refspec = forked_url.split('@') tool_name, url_and_refspec = forked_url.split('@')
t = find_tool(tool_name) t = find_tool(tool_name)
if not t: if not t:
errlog('Failed to find tool ' + tool_name + '!') errlog('Failed to find tool {tool_name}!')
return False return False
else: else:
t.url, t.git_branch, t.remote_name = parse_github_url_and_refspec(url_and_refspec) t.url, t.git_branch, t.remote_name = parse_github_url_and_refspec(url_and_refspec)
debug_print('Reading git repository URL "' + t.url + '" and git branch "' + t.git_branch + '" for Tool "' + tool_name + '".') debug_print(f'Reading git repository URL "{t.url}" and git branch "{t.git_branch}" for Tool "{tool_name}".')
forked_url = extract_string_arg('--override-repository') forked_url = extract_string_arg('--override-repository')
@@ -3179,7 +3155,7 @@ def main(args):
CMAKE_GENERATOR = build_generator.group(1) CMAKE_GENERATOR = build_generator.group(1)
args[i] = '' args[i] = ''
else: else:
errlog("Cannot parse CMake generator string: " + args[i] + ". Try wrapping generator string with quotes") errlog(f"Cannot parse CMake generator string: {args[i]}. Try wrapping generator string with quotes")
return 1 return 1
elif args[i].startswith('--build='): elif args[i].startswith('--build='):
build_type = re.match(r'^--build=(.+)$', args[i]) build_type = re.match(r'^--build=(.+)$', args[i])
@@ -3192,10 +3168,10 @@ def main(args):
CMAKE_BUILD_TYPE_OVERRIDE = build_types[build_type_index] CMAKE_BUILD_TYPE_OVERRIDE = build_types[build_type_index]
args[i] = '' args[i] = ''
except Exception: except Exception:
errlog('Unknown CMake build type "' + build_type + '" specified! Please specify one of ' + str(build_types)) errlog(f'Unknown CMake build type "{build_type}" specified! Please specify one of {build_types}')
return 1 return 1
else: else:
errlog("Invalid command line parameter " + args[i] + ' specified!') errlog(f'Invalid command line parameter {args[i]} specified!')
return 1 return 1
args = [x for x in args if x] args = [x for x in args if x]
@@ -3206,7 +3182,7 @@ def main(args):
sdk = find_sdk(name) sdk = find_sdk(name)
return 'INSTALLED' if sdk and sdk.is_installed() else '' return 'INSTALLED' if sdk and sdk.is_installed() else ''
if (LINUX or MACOS or WINDOWS) and (ARCH == 'x86' or ARCH == 'x86_64'): if (LINUX or MACOS or WINDOWS) and ARCH in ('x86', 'x86_64'):
print('The *recommended* precompiled SDK download is %s (%s).' % (find_latest_version(), find_latest_hash())) print('The *recommended* precompiled SDK download is %s (%s).' % (find_latest_version(), find_latest_hash()))
print() print()
print('To install/activate it use:') print('To install/activate it use:')
@@ -3301,7 +3277,7 @@ def main(args):
print('Items marked with * are activated for the current user.') print('Items marked with * are activated for the current user.')
if has_partially_active_tools[0]: if has_partially_active_tools[0]:
env_cmd = 'emsdk_env.bat' if WINDOWS else 'source ./emsdk_env.sh' env_cmd = 'emsdk_env.bat' if WINDOWS else 'source ./emsdk_env.sh'
print('Items marked with (*) are selected for use, but your current shell environment is not configured to use them. Type "' + env_cmd + '" to set up your current shell to use them' + (', or call "emsdk activate --permanent <name_of_sdk>" to permanently activate them.' if WINDOWS else '.')) print(f'Items marked with (*) are selected for use, but your current shell environment is not configured to use them. Type "{env_cmd}" to set up your current shell to use them' + (', or call "emsdk activate --permanent <name_of_sdk>" to permanently activate them.' if WINDOWS else '.'))
if not arg_old: if not arg_old:
print('') print('')
print("To access the historical archived versions, type 'emsdk list --old'") print("To access the historical archived versions, type 'emsdk list --old'")
@@ -3334,7 +3310,7 @@ def main(args):
elif cmd == 'update-tags': elif cmd == 'update-tags':
errlog('`update-tags` is not longer needed. To install the latest tot release just run `install tot`') errlog('`update-tags` is not longer needed. To install the latest tot release just run `install tot`')
return 0 return 0
elif cmd == 'activate' or cmd == 'deactivate': elif cmd in ('activate', 'deactivate'):
if arg_permanent: if arg_permanent:
print('Registering active Emscripten environment permanently') print('Registering active Emscripten environment permanently')
print('') print('')
@@ -3353,7 +3329,7 @@ def main(args):
print('Deactivating tool ' + str(tool) + '.') print('Deactivating tool ' + str(tool) + '.')
tools_to_activate.remove(tool) tools_to_activate.remove(tool)
else: else:
print('Tool "' + arg + '" was not active, no need to deactivate.') print(f'Tool "{arg}" was not active, no need to deactivate.')
if not tools_to_activate: if not tools_to_activate:
errlog('No tools/SDKs specified to activate! Usage:\n emsdk activate tool/sdk1 [tool/sdk2] [...]') errlog('No tools/SDKs specified to activate! Usage:\n emsdk activate tool/sdk1 [tool/sdk2] [...]')
return 1 return 1
@@ -3375,7 +3351,7 @@ def main(args):
CPU_CORES = int(multicore.group(1)) CPU_CORES = int(multicore.group(1))
args[i] = '' args[i] = ''
else: else:
errlog("Invalid command line parameter " + args[i] + ' specified!') errlog(f'Invalid command line parameter {args[i]} specified!')
return 1 return 1
elif args[i] == '--shallow': elif args[i] == '--shallow':
GIT_CLONE_SHALLOW = True GIT_CLONE_SHALLOW = True
@@ -3412,12 +3388,12 @@ def main(args):
return 1 return 1
tool = find_tool(args[0]) tool = find_tool(args[0])
if tool is None: if tool is None:
errlog("Error: Tool by name '" + args[0] + "' was not found.") errlog(f"Error: Tool by name '{args[0]}' was not found.")
return 1 return 1
tool.uninstall() tool.uninstall()
return 0 return 0
errlog("Unknown command '" + cmd + "' given! Type 'emsdk help' to get a list of commands.") errlog(f"Unknown command '{cmd}' given! Type 'emsdk help' to get a list of commands.")
return 1 return 1

74
pyproject.toml Normal file
View File

@@ -0,0 +1,74 @@
[project]
requires-python = ">=3.2"
[tool.ruff]
line-length = 100
exclude = [
"./cache/",
"./node_modules/",
"./site/source/_themes/",
"./site/source/conf.py",
"./system/lib/",
"./test/third_party/",
"./third_party/",
"./tools/filelock.py",
"./tools/scons/",
".git",
]
lint.select = [
"ARG",
"ASYNC",
"B",
"C4",
"C90",
"COM",
"E",
"F",
"I",
"PERF",
"PIE",
"PL",
"UP",
"W",
"YTT",
]
lint.external = [ "D" ]
lint.ignore = [
"B011", # See https://github.com/PyCQA/flake8-bugbear/issues/66
"B023",
"B026",
"E402",
"E501",
"E721",
"E741",
"PERF203",
"PERF401",
"PLC0415",
"PLR0915",
"PLR1704",
"PLR5501",
"PLW0602",
"PLW0603",
"PLW1510",
"PLW2901",
"UP030", # TODO
"UP031", # TODO
"UP032", # TODO
]
lint.per-file-ignores."emrun.py" = [ "PLE0704" ]
lint.per-file-ignores."tools/ports/*.py" = [ "ARG001", "ARG005" ]
lint.per-file-ignores."test/other/ports/*.py" = [ "ARG001" ]
lint.per-file-ignores."test/parallel_testsuite.py" = [ "ARG002" ]
lint.per-file-ignores."test/test_benchmark.py" = [ "ARG002" ]
lint.mccabe.max-complexity = 51 # Recommended: 10
lint.pylint.allow-magic-value-types = [
"bytes",
"float",
"int",
"str",
]
lint.pylint.max-args = 15 # Recommended: 5
lint.pylint.max-branches = 50 # Recommended: 12
lint.pylint.max-returns = 16 # Recommended: 6
lint.pylint.max-statements = 142 # Recommended: 50

View File

@@ -9,9 +9,10 @@ import hashlib
import json import json
import os import os
import re import re
import requests
import sys import sys
import requests
STORAGE_URL = 'https://storage.googleapis.com/webassembly/emscripten-releases-builds' STORAGE_URL = 'https://storage.googleapis.com/webassembly/emscripten-releases-builds'
EMSDK_ROOT = os.path.dirname(os.path.dirname(__file__)) EMSDK_ROOT = os.path.dirname(os.path.dirname(__file__))
@@ -51,7 +52,7 @@ def revisions_item(version, latest_hash):
def insert_revision(item): def insert_revision(item):
with open(BAZEL_REVISIONS_FILE, 'r') as f: with open(BAZEL_REVISIONS_FILE) as f:
lines = f.readlines() lines = f.readlines()
lines.insert(lines.index('EMSCRIPTEN_TAGS = {\n') + 1, item) lines.insert(lines.index('EMSCRIPTEN_TAGS = {\n') + 1, item)
@@ -61,7 +62,7 @@ def insert_revision(item):
def update_module_version(version): def update_module_version(version):
with open(BAZEL_MODULE_FILE, 'r') as f: with open(BAZEL_MODULE_FILE) as f:
content = f.read() content = f.read()
pattern = r'(module\(\s*name = "emsdk",\s*version = )"\d+.\d+.\d+",\n\)' pattern = r'(module\(\s*name = "emsdk",\s*version = )"\d+.\d+.\d+",\n\)'
@@ -74,7 +75,7 @@ def update_module_version(version):
f.write(content) f.write(content)
def main(argv): def main():
version, latest_hash = get_latest_info() version, latest_hash = get_latest_info()
update_module_version(version) update_module_version(version)
item = revisions_item(version, latest_hash) item = revisions_item(version, latest_hash)
@@ -84,4 +85,4 @@ def main(argv):
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main(sys.argv)) sys.exit(main())

View File

@@ -11,11 +11,12 @@ For the windows version we also alter the directory layout to add the 'bin'
directory. directory.
""" """
import urllib.request
import subprocess
import sys
import os import os
import shutil import shutil
import subprocess
import sys
import urllib.request
from zip import unzip_cmd, zip_cmd from zip import unzip_cmd, zip_cmd
# When adjusting this version, visit # When adjusting this version, visit

View File

@@ -26,11 +26,11 @@ import glob
import multiprocessing import multiprocessing
import os import os
import platform import platform
import urllib.request
import shutil import shutil
import subprocess
import sys import sys
import urllib.request
from subprocess import check_call from subprocess import check_call
from zip import unzip_cmd, zip_cmd from zip import unzip_cmd, zip_cmd
version = '3.13.3' version = '3.13.3'

View File

@@ -32,19 +32,18 @@ def listify(x):
return [x] return [x]
def check_call(cmd, **args): def check_call(cmd, **kwargs):
if type(cmd) is not list: if type(cmd) is not list:
cmd = cmd.split() cmd = cmd.split()
print('running: %s' % cmd) print('running: %s' % cmd)
args['universal_newlines'] = True subprocess.run(cmd, check=True, text=True, **kwargs)
subprocess.check_call(cmd, **args)
def checked_call_with_output(cmd, expected=None, unexpected=None, stderr=None, env=None): def checked_call_with_output(cmd, expected=None, unexpected=None, stderr=None, env=None):
cmd = cmd.split(' ') cmd = cmd.split(' ')
print('running: %s' % cmd) print('running: %s' % cmd)
try: try:
stdout = subprocess.check_output(cmd, stderr=stderr, universal_newlines=True, env=env) stdout = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=stderr, check=True, text=True, env=env).stdout
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
print(e.stderr) print(e.stderr)
print(e.stdout) print(e.stdout)
@@ -59,8 +58,9 @@ def checked_call_with_output(cmd, expected=None, unexpected=None, stderr=None, e
def failing_call_with_output(cmd, expected, env=None): def failing_call_with_output(cmd, expected, env=None):
proc = subprocess.Popen(cmd.split(' '), stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, env=env) proc = subprocess.run(cmd.split(' '), capture_output=True, text=True, env=env)
stdout, stderr = proc.communicate() stdout = proc.stdout
stderr = proc.stderr
if WINDOWS: if WINDOWS:
print('warning: skipping part of failing_call_with_output() due to error codes not being propagated (see #592)') print('warning: skipping part of failing_call_with_output() due to error codes not being propagated (see #592)')
else: else: