Created
December 9, 2023 17:43
-
-
Save andy0130tw/1e560dfae7eedc11a1a371e1c56d71a9 to your computer and use it in GitHub Desktop.
A slim re-implementation of setup.sh in ghc-wasm-meta
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import subprocess | |
import shlex | |
import shutil | |
import sys | |
import json | |
if shutil.which('curl') is None: | |
print('This script requires curl') | |
sys.exit(1) | |
if shutil.which('unzip') is None: | |
print('This script requires unzip') | |
sys.exit(1) | |
def run_cmd(*args, shell=True, **kwargs): | |
print(args, kwargs) | |
return subprocess.check_output( | |
*args, **kwargs, shell=shell, universal_newlines=True | |
).strip() | |
def jq_autogen(name): | |
# cmd = f'''jq -r '."{name}".url' {REPO}/autogen.json''' | |
# return run_cmd(cmd) | |
with open(f'{REPO}/autogen.json') as f: | |
data = json.load('autogen.json') | |
return data[name]['url'] | |
def run_curl(url, dest, *, pipe_to=None): | |
cmd = f'curl -f -L --retry 5 {shlex.quote(url)}' | |
tail = '-o %s' | |
if pipe_to is not None: | |
tail = '| ' + pipe_to | |
run_cmd(cmd + ' ' + (tail % shlex.quote(dest))) | |
# FLAVOUR = os.environ.get('FLAVOUR', 'gmp') | |
PREFIX = os.environ.get('PREFIX', run_cmd('realpath ' + shlex.quote(os.path.expandvars('$HOME/.ghc-wasm')))) | |
REPO = os.environ['PWD'] | |
# print(f'{FLAVOUR=}') | |
print(f'{PREFIX=}') | |
print(f'{REPO=}') | |
print('--- Setting up WASI SDK ---') | |
wasi_sdk_dest = f'{PREFIX}/wasi-sdk' | |
if os.path.exists(wasi_sdk_dest): | |
print(f'Found "{shlex.quote(wasi_sdk_dest)}", skip downloading...') | |
else: | |
run_cmd(f'mkdir -p {shlex.quote(wasi_sdk_dest)}') | |
wasi_sdk_url = jq_autogen('wasi-sdk_darwin') | |
run_curl(wasi_sdk_url, wasi_sdk_dest, pipe_to='tar xz -C %s --strip-components=1') | |
print('--- Setting up ffi-wasm ---') | |
run_curl(jq_autogen('libffi-wasm'), f'libffi-wasm.zip') | |
run_cmd('unzip libffi-wasm.zip') | |
run_cmd(['cp', '-a', | |
'out/libffi-wasm/include/.', | |
f'{PREFIX}/wasi-sdk/share/wasi-sysroot/include'], shell=False) | |
run_cmd(['cp', '-a', | |
'out/libffi-wasm/lib/.', | |
f'{PREFIX}/wasi-sdk/share/wasi-sysroot/lib/wasm32-wasi'], shell=False) | |
# TODO: setup proot -- https://github.com/proot-me/proot | |
# but does it make sense in mac? | |
# print('--- Setting up proot ---') | |
# run_cmd(['mkdir', '-p', f'{PREFIX}/proot/bin'], shell=False) | |
# proot_url = jq_autogen('proot') | |
# run_curl(proot_url, f'{PREFIX}/proot/bin/proot', 'cat > %s') | |
# run_cmd(['chmod', '755', f'{PREFIX}/proot/bin/proot'], shell=False) | |
# print('--- Setting up wasm-run ---') | |
# run_cmd(['mkdir', '-p', f'{PREFIX}/wasm-run/bin'], shell=True) | |
# run_cmd(['cp', '-a', | |
# f'{REPO}/wasm-run/*.js', | |
# f'{REPO}/wasm-run/*.mjs', | |
# f'{REPO}/wasm-run/*.sh', | |
# f'{PREFIX}/wasm-run/bin'], shell=False) | |
# run_cmd(['cc', | |
# f'-DWASM_RUN="\"{PREFIX}/wasm-run/bin/wasm-run.js\""', | |
# '-Wall', '-O3', | |
# f"{REPO}/wasm-run/qemu-system-wasm32.c", | |
# '-o', f'{PREFIX}/wasm-run/bin/qemu-system-wasm32'], shell=True) | |
# run_cmd(f'echo "#!/bin/sh" >> {shlex.quote(f"{PREFIX}/wasm-run/bin/wasm-run")}') | |
# with open(f'{PREFIX}/wasm-run/bin/wasm-run', 'a') as f: | |
# proot_exec = f'{PREFIX}/proot/bin/proot' | |
# qemu_exec = f'{PREFIX}/wasm-run/bin/qemu-system-wasm32' | |
# rest = '${1+"$@"}' | |
# f.write(f'exec {shlex.quote(proot_exec)} -q {shlex.quote(qemu_exec)} \'{rest}\'') | |
# run_cmd(f'chmod 755 {shlex.quote(f"{PREFIX}/wasm-run/bin/wasm-run")}') | |
# run_cmd(['gsed', | |
# '-i', 's@wasmtime@$PREFIX/wasmtime/bin/wasmtime@', | |
# f'{PREFIX}wasm-run/bin/wasmtime.sh'], shell=False) | |
envs = { | |
'AR': shutil.which('llvm-ar'), | |
'CC': shutil.which('clang'), | |
'CC_FOR_BUILD': 'cc', | |
'CXX': shutil.which('clang++'), | |
'LD': shutil.which('wasm-ld'), | |
'NM': shutil.which('llvm-nm'), | |
'OBJCOPY': shutil.which('llvm-objcopy'), | |
'OBJDUMP': shutil.which('llvm-objdump'), | |
'RANLIB': shutil.which('llvm-ranlib'), | |
'SIZE': shutil.which('llvm-size'), | |
'STRINGS': shutil.which('llvm-strings'), | |
'STRIP': shutil.which('llvm-strip'), | |
# but why? | |
'LLC': shutil.which('false'), | |
'OPT': shutil.which('false'), | |
} | |
env_ok = True | |
print('--- Checking compilers ---') | |
for env, path in envs.items(): | |
print(f'Checking {env:14s}: ', end='') | |
if path is None: | |
print('[N/A]') | |
env_ok = False | |
print(path) | |
if not env_ok: | |
print('Aborting due to missing executables.') | |
sys.exit(1) | |
# should sync with setup.sh | |
cc_opts = '-Wno-error=int-conversion -Wno-error=strict-prototypes -Wno-error=implicit-function-declaration -Oz -msimd128 -mnontrapping-fptoint -msign-ext -mbulk-memory -mmutable-globals -mmultivalue -mreference-types' | |
cxx_opts = '-Wno-error=int-conversion -Wno-error=strict-prototypes -Wno-error=implicit-function-declaration -fno-exceptions -Oz -msimd128 -mnontrapping-fptoint -msign-ext -mbulk-memory -mmutable-globals -mmultivalue -mreference-types' | |
ld_opts = '-Wl,--compress-relocations,--error-limit=0,--growable-table,--stack-first,--strip-debug' | |
_EXTRA_ENVS = { | |
'CONF_CC_OPTS_STAGE2': cc_opts, | |
'CONF_CXX_OPTS_STAGE2': cxx_opts, | |
'CONF_GCC_LINKER_OPTS_STAGE2': ld_opts, | |
'CONF_CC_OPTS_STAGE1': cc_opts, | |
'CONF_CXX_OPTS_STAGE1': cxx_opts, | |
'CONF_GCC_LINKER_OPTS_STAGE1': ld_opts, | |
# 'CONFIGURE_ARGS': "", | |
# 'CROSS_EMULATOR': f'{PREFIX}/wasm-run/bin/wasmtime.sh', | |
} | |
print('--- Writing the env file ---') | |
# TODO: different implementation of gmp (the "flavour") | |
configure_args = '--host=aarch64-apple-darwin --target=wasm32-wasi --with-intree-gmp --with-system-libffi' | |
# FIXME: --prefix=? | |
with open(f'{PREFIX}/env', 'w') as envfile: | |
for env, value in envs.items(): | |
envfile.write(f'export {env}={value}\n') | |
# TODO: add_to_github_path.sh | |
for env, value in _EXTRA_ENVS.items(): | |
override = os.environ.get(env) | |
if override is not None: | |
value = override | |
envfile.write(f'export {env}={shlex.quote(value)}\n') | |
print('Done.') | |
print(f'Source "{PREFIX}/env" and then configure ghc with:') | |
print(f' ./configure {configure_args}') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment