vendor: EMSDK 6.0.6 scripts at e26beb67ef18a37d71d522d8b7096b20a4d3d0f9
This commit is contained in:
Executable
+386
@@ -0,0 +1,386 @@
|
||||
#!/usr/bin/env python3
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import stat
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
WINDOWS = sys.platform.startswith('win')
|
||||
MACOS = sys.platform == 'darwin'
|
||||
MACOS_ARM64 = MACOS and platform.machine() == 'arm64'
|
||||
|
||||
emconfig = os.path.abspath('.emscripten')
|
||||
assert os.path.exists(emconfig)
|
||||
|
||||
if WINDOWS:
|
||||
emsdk = 'emsdk.bat'
|
||||
else:
|
||||
emsdk = './emsdk'
|
||||
|
||||
# Utilities
|
||||
|
||||
|
||||
def listify(x):
|
||||
if type(x) in {list, tuple}:
|
||||
return x
|
||||
return [x]
|
||||
|
||||
|
||||
def copy_emsdk_to(targetdir):
|
||||
for filename in os.listdir('.'):
|
||||
if not filename.startswith('.') and not os.path.isdir(filename):
|
||||
shutil.copy2(filename, os.path.join(targetdir, filename))
|
||||
|
||||
|
||||
def check_call(cmd, **kwargs):
|
||||
if type(cmd) is not list:
|
||||
cmd = cmd.split()
|
||||
print('running: %s' % cmd)
|
||||
subprocess.run(cmd, check=True, text=True, **kwargs)
|
||||
|
||||
|
||||
def checked_call_with_output(cmd, expected=None, unexpected=None, stderr=None, env=None):
|
||||
cmd = cmd.split(' ')
|
||||
print('running: %s' % cmd)
|
||||
try:
|
||||
stdout = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=stderr, check=True, text=True, env=env).stdout
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(e.stderr)
|
||||
print(e.stdout)
|
||||
raise e
|
||||
|
||||
if expected:
|
||||
for x in listify(expected):
|
||||
assert x in stdout, 'expected output missing: ' + stdout + '\n[[[' + x + ']]]'
|
||||
if unexpected:
|
||||
for x in listify(unexpected):
|
||||
assert x not in stdout, 'unexpected output present: ' + stdout + '\n[[[' + x + ']]]'
|
||||
|
||||
|
||||
def failing_call_with_output(cmd, expected, env=None):
|
||||
proc = subprocess.run(cmd.split(' '), capture_output=True, text=True, env=env)
|
||||
stdout = proc.stdout
|
||||
stderr = proc.stderr
|
||||
if WINDOWS:
|
||||
print('warning: skipping part of failing_call_with_output() due to error codes not being propagated (see #592)')
|
||||
else:
|
||||
assert proc.returncode, 'call must have failed: ' + str([stdout, '\n========\n', stderr])
|
||||
assert expected in stdout or expected in stderr, 'call did not have the expected output: %s: %s' % (expected, str([stdout, '\n========\n', stderr]))
|
||||
|
||||
|
||||
def hack_emsdk(marker, replacement):
|
||||
with open('emsdk.py') as f:
|
||||
src = f.read()
|
||||
assert marker in src
|
||||
src = src.replace(marker, replacement)
|
||||
name = '__test_emsdk'
|
||||
with open(name, 'w') as f:
|
||||
f.write(src)
|
||||
return name
|
||||
|
||||
|
||||
def get_longest_path_in_dir(dirname):
|
||||
longest = ''
|
||||
for root, _dirs, files in os.walk(dirname):
|
||||
for f in files:
|
||||
fullname = os.path.join(root, f)
|
||||
if len(fullname) > len(longest):
|
||||
longest = fullname
|
||||
return longest
|
||||
|
||||
|
||||
def remove_file(filename):
|
||||
if os.path.exists(filename):
|
||||
os.remove(filename)
|
||||
|
||||
|
||||
def remove_tree(path):
|
||||
if not os.path.exists(path):
|
||||
return
|
||||
if WINDOWS:
|
||||
path = '\\\\?\\' + path
|
||||
|
||||
def remove_readonly(func, path2, _):
|
||||
os.chmod(path2, stat.S_IRWXU)
|
||||
func(path2)
|
||||
|
||||
shutil.rmtree(path, onerror=remove_readonly)
|
||||
|
||||
|
||||
# Set up
|
||||
|
||||
TAGS = json.loads(open('emscripten-releases-tags.json').read())
|
||||
|
||||
# Tests
|
||||
|
||||
|
||||
def do_lib_building(emcc):
|
||||
cache_building_messages = ['generating system library: ']
|
||||
|
||||
def do_build(args, is_expected=None):
|
||||
unexpected = None
|
||||
expected = None
|
||||
if is_expected is True:
|
||||
expected = cache_building_messages
|
||||
elif is_expected is False:
|
||||
unexpected = cache_building_messages
|
||||
checked_call_with_output(emcc + ' hello_world.c' + args,
|
||||
expected=expected,
|
||||
unexpected=unexpected,
|
||||
stderr=subprocess.STDOUT)
|
||||
|
||||
# The emsdk ships all system libraries so we don't expect to see any
|
||||
# cache population unless we explicly --clear-cache.
|
||||
do_build('', is_expected=False)
|
||||
check_call(emcc + ' --clear-cache')
|
||||
do_build(' -O2', is_expected=True)
|
||||
# Do another build at -O0. In nwers SDK versions this generates
|
||||
# different libs, but not in older ones so don't assert here.
|
||||
do_build('')
|
||||
# Now verify that libs are *not* build
|
||||
do_build(' -s WASM=0', is_expected=False)
|
||||
do_build(' -O2 -s WASM=0', is_expected=False)
|
||||
|
||||
|
||||
def run_emsdk(cmd):
|
||||
if type(cmd) is not list:
|
||||
cmd = cmd.split()
|
||||
check_call([emsdk, *cmd])
|
||||
|
||||
|
||||
def upstream_emcc(root='.'):
|
||||
emcc = os.path.join(root, 'upstream', 'emscripten', 'emcc')
|
||||
if WINDOWS:
|
||||
if os.path.exists(emcc + '.exe'):
|
||||
return emcc + '.exe'
|
||||
else:
|
||||
return emcc + '.bat'
|
||||
return emcc
|
||||
|
||||
|
||||
class Emsdk(unittest.TestCase):
|
||||
def setUp(self):
|
||||
run_emsdk('install latest')
|
||||
run_emsdk('activate latest')
|
||||
with open('hello_world.c', 'w') as f:
|
||||
f.write('''\
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("Hello, world!\\n");
|
||||
return 0;
|
||||
}
|
||||
''')
|
||||
self.addCleanup(remove_file, 'hello_world.c')
|
||||
|
||||
def tearDown(self):
|
||||
for f in glob.glob('a.out*'):
|
||||
os.remove(f)
|
||||
|
||||
def test_extrememly_long_filenames(self):
|
||||
# We have special support for filenames longer than 256 on windows. This
|
||||
# test installs emsdk in path that exceeds this limit in order to test
|
||||
# this handling.
|
||||
longpath = os.path.abspath('very_long_filename_indeed')
|
||||
|
||||
additional = 140 - len(longpath)
|
||||
longpath += 'x' * additional
|
||||
|
||||
remove_tree(longpath)
|
||||
self.addCleanup(remove_tree, longpath)
|
||||
|
||||
os.makedirs(longpath)
|
||||
copy_emsdk_to(longpath)
|
||||
|
||||
emsdk = os.path.join(longpath, 'emsdk')
|
||||
if WINDOWS:
|
||||
emsdk += '.bat'
|
||||
self.assertTrue(os.path.exists(emsdk))
|
||||
|
||||
check_call([emsdk, 'install', 'latest'])
|
||||
check_call([emsdk, 'activate', 'latest'])
|
||||
|
||||
# Check that emcc exists in the expected location
|
||||
emcc = upstream_emcc(longpath)
|
||||
print(emcc)
|
||||
self.assertTrue(os.path.exists(emcc))
|
||||
|
||||
# Find the longest installed path and assert this is longer than 256
|
||||
longest_path = get_longest_path_in_dir(longpath)
|
||||
print(f'longest ({len(longest_path)}: {longest_path})')
|
||||
self.assertGreater(len(longest_path), 256)
|
||||
|
||||
# Finally make sure we can actaully compile something
|
||||
check_call([emcc, 'hello_world.c'])
|
||||
|
||||
def test_unknown_arch(self):
|
||||
env = os.environ.copy()
|
||||
env['EMSDK_ARCH'] = 'mips'
|
||||
failing_call_with_output(emsdk + ' install latest',
|
||||
expected='unknown machine architecture: mips',
|
||||
env=env)
|
||||
|
||||
def test_wrong_bitness(self):
|
||||
env = os.environ.copy()
|
||||
env['EMSDK_ARCH'] = 'x86'
|
||||
failing_call_with_output(emsdk + ' install sdk-latest-64bit',
|
||||
expected='is only provided for 64-bit OSe',
|
||||
env=env)
|
||||
|
||||
def test_already_installed(self):
|
||||
# Test we don't re-download unnecessarily
|
||||
checked_call_with_output(emsdk + ' install latest', expected='already installed', unexpected='Downloading:')
|
||||
|
||||
def test_list(self):
|
||||
# Test we report installed tools properly. The latest version should be
|
||||
# installed, but not some random old one.
|
||||
checked_call_with_output(emsdk + ' list', expected=TAGS['aliases']['latest'] + ' INSTALLED', unexpected='1.39.15 INSTALLED:')
|
||||
|
||||
def test_config_contents(self):
|
||||
print('test .emscripten contents')
|
||||
run_emsdk('install 6.0.3')
|
||||
run_emsdk('activate 6.0.3')
|
||||
with open(emconfig) as f:
|
||||
config = f.read()
|
||||
self.assertIn('upstream', config)
|
||||
|
||||
# Older version of emscripten (prior to 6.0.3) don't support $CFGDIR
|
||||
self.assertIn('import os', config)
|
||||
self.assertIn('emsdk_path + ', config)
|
||||
self.assertNotIn('$CFGDIR', config)
|
||||
|
||||
# For newer versions we use $CFGDIR
|
||||
version_file = os.path.join('upstream', 'emscripten', 'emscripten-version.txt')
|
||||
with open(version_file) as f:
|
||||
old_ver = f.read()
|
||||
try:
|
||||
# Hack the version file to contain 6.0.4
|
||||
with open(version_file, 'w') as f:
|
||||
f.write('6.0.4\n')
|
||||
# Re-activate 6.0.3 but with the hacked version file which makes it
|
||||
# appear to contain 6.0.4.
|
||||
run_emsdk('activate 6.0.3')
|
||||
with open(emconfig) as f:
|
||||
config = f.read()
|
||||
self.assertNotIn('import os', config)
|
||||
self.assertNotIn('emsdk_path', config)
|
||||
self.assertIn('$CFGDIR', config)
|
||||
finally:
|
||||
with open(version_file, 'w') as f:
|
||||
f.write(old_ver)
|
||||
run_emsdk('activate 6.0.3')
|
||||
|
||||
def test_lib_building(self):
|
||||
print('building proper system libraries')
|
||||
do_lib_building(upstream_emcc())
|
||||
|
||||
def test_redownload(self):
|
||||
print('go back to using upstream')
|
||||
run_emsdk('activate latest')
|
||||
|
||||
# Test the normal tools like node don't re-download on re-install
|
||||
print('another install must re-download')
|
||||
checked_call_with_output(emsdk + ' uninstall node-24.19.0-64bit')
|
||||
checked_call_with_output(emsdk + ' install node-24.19.0-64bit', expected='Downloading:', unexpected='already installed')
|
||||
checked_call_with_output(emsdk + ' install node-24.19.0-64bit', unexpected='Downloading:', expected='already installed')
|
||||
|
||||
def test_tot_upstream(self):
|
||||
print('test tot-upstream')
|
||||
run_emsdk('install tot-upstream')
|
||||
with open(emconfig) as f:
|
||||
config = f.read()
|
||||
run_emsdk('activate tot-upstream')
|
||||
self.addCleanup(remove_file, emconfig + '.old')
|
||||
with open(emconfig + '.old') as f:
|
||||
old_config = f.read()
|
||||
self.assertEqual(config, old_config)
|
||||
# TODO; test on latest as well
|
||||
check_call(upstream_emcc() + ' hello_world.c')
|
||||
|
||||
def test_closure(self):
|
||||
# Specifically test with `--closure` so we know that node_modules is working
|
||||
check_call(upstream_emcc() + ' hello_world.c --closure=1')
|
||||
|
||||
def test_specific_version(self):
|
||||
if MACOS_ARM64:
|
||||
self.skipTest('Old sdk versions do not have ARM64 binaries')
|
||||
print('test specific release (new, short name)')
|
||||
run_emsdk('install 1.38.33')
|
||||
print('another install, but no need for re-download')
|
||||
checked_call_with_output(emsdk + ' install 1.38.33', expected='Skipped', unexpected='Downloading:')
|
||||
run_emsdk('activate 1.38.33')
|
||||
|
||||
def test_specific_version_full(self):
|
||||
if MACOS_ARM64:
|
||||
self.skipTest('Old sdk versions do not have ARM64 binaries')
|
||||
print('test specific release (new, full name)')
|
||||
run_emsdk('install sdk-1.38.33-64bit')
|
||||
run_emsdk('activate sdk-1.38.33-64bit')
|
||||
print('test specific release (new, tag name)')
|
||||
run_emsdk('install sdk-tag-1.38.33-64bit')
|
||||
run_emsdk('activate sdk-tag-1.38.33-64bit')
|
||||
|
||||
def test_binaryen_from_source(self):
|
||||
if WINDOWS:
|
||||
# It takes over 30 mins to build binaryen using Visual Studio in CI
|
||||
self.skipTest('test is too slow under windows')
|
||||
run_emsdk(['install', '--build=Release', 'binaryen-main-64bit'])
|
||||
|
||||
def test_no_32bit(self):
|
||||
print('test 32-bit error')
|
||||
emsdk_hacked = hack_emsdk('not is_os_64bit()', 'True')
|
||||
self.addCleanup(remove_file, emsdk_hacked)
|
||||
failing_call_with_output('%s %s install latest' % (sys.executable, emsdk_hacked),
|
||||
'this tool is only provided for 64-bit OSes')
|
||||
|
||||
def test_update_no_git(self):
|
||||
print('test non-git update')
|
||||
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
self.addCleanup(remove_tree, temp_dir)
|
||||
copy_emsdk_to(temp_dir)
|
||||
|
||||
olddir = os.getcwd()
|
||||
try:
|
||||
os.chdir(temp_dir)
|
||||
run_emsdk('update')
|
||||
|
||||
print('second time')
|
||||
run_emsdk('update')
|
||||
finally:
|
||||
os.chdir(olddir)
|
||||
|
||||
def test_install_arbitrary(self):
|
||||
# Test that its possible to install arbrary emscripten-releases SDKs
|
||||
run_emsdk('install 1b7f7bc6002a3ca73647f41fc10e1fac7f06f804')
|
||||
|
||||
# Check that its not re-downloaded
|
||||
checked_call_with_output(emsdk + ' install 1b7f7bc6002a3ca73647f41fc10e1fac7f06f804', expected='Skipped', unexpected='Downloading:')
|
||||
|
||||
def test_install_tool(self):
|
||||
# Test that its possible to install emscripten as tool instead of SDK
|
||||
checked_call_with_output(emsdk + ' install releases-77b065ace39e6ab21446e13f92897f956c80476a', unexpected='Installing SDK')
|
||||
|
||||
def test_activate_missing(self):
|
||||
run_emsdk('install latest')
|
||||
failing_call_with_output(emsdk + ' activate 2.0.1', expected="error: tool is not installed and therefore cannot be activated: 'releases-13e29bd55185e3c12802bc090b4507901856b2ba-64bit'")
|
||||
|
||||
def test_keep_downloads(self):
|
||||
env = os.environ.copy()
|
||||
env['EMSDK_KEEP_DOWNLOADS'] = '1'
|
||||
# With EMSDK_KEEP_DOWNLOADS the downloading should happen on the first
|
||||
# install of 2.0.28, and again when we install 2.0.29, but not on the
|
||||
# second install of 2.0.28 because the zip should already be local.
|
||||
shutil.rmtree('downloads')
|
||||
checked_call_with_output(emsdk + ' install 3.1.54', expected='Downloading:', env=env)
|
||||
checked_call_with_output(emsdk + ' install 3.1.55', expected='Downloading:', env=env)
|
||||
checked_call_with_output(emsdk + ' install 3.1.54', expected='already downloaded, skipping', unexpected='Downloading:', env=env)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(verbosity=2)
|
||||
Reference in New Issue
Block a user