diff --git a/.github/workflows/scripts/build.py b/.github/workflows/scripts/build.py
new file mode 100755
index 0000000000000..1c629b5b0d52f
--- /dev/null
+++ b/.github/workflows/scripts/build.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python3
+
+# -- prioritized --
+import ci_common # isort: skip, early initialization happens here
+
+# -- stdlib --
+import glob
+import os
+import platform
+
+# -- third party --
+# -- own --
+from ci_common.dep import download_dep
+from ci_common.misc import banner, get_cache_home, is_manylinux2014
+from ci_common.python import setup_python
+from ci_common.sccache import setup_sccache
+from ci_common.tinysh import Command, environ, git, sh
+
+
+# -- code --
+@banner('Setup LLVM')
+def setup_llvm(env_out: dict) -> None:
+ '''
+ Download and install LLVM.
+ '''
+ u = platform.uname()
+ if u.system == 'Linux':
+ if 'AMDGPU_TEST' in os.environ:
+ # FIXME: AMDGPU bots are currently maintained separately,
+ # we should unify them with the rest of the bots.
+ lnsf = sh.sudo.ln.bake('-sf')
+ lnsf('/usr/bin/clang++-10', '/usr/bin/clang++')
+ lnsf('/usr/bin/clang-10', '/usr/bin/clang')
+ lnsf('/usr/bin/ld.lld-10', '/usr/bin/ld.lld')
+ env_out['LLVM_DIR'] = '/taichi-llvm-15'
+ return
+ elif is_manylinux2014():
+ # FIXME: prebuilt llvm15 on ubuntu didn't work on manylinux2014 image of centos. Once that's fixed, remove this hack.
+ out = get_cache_home() / 'llvm15-manylinux2014'
+ url = 'https://github.com/ailzhang/torchhub_example/releases/download/0.3/taichi-llvm-15-linux.zip'
+ else:
+ out = get_cache_home() / 'llvm15'
+ url = 'https://github.com/taichi-dev/taichi_assets/releases/download/llvm15/taichi-llvm-15-linux.zip'
+ elif (u.system, u.machine) == ('Darwin', 'arm64'):
+ out = get_cache_home() / 'llvm15-m1'
+ url = 'https://github.com/taichi-dev/taichi_assets/releases/download/llvm15/taichi-llvm-15-m1.zip'
+ elif (u.system, u.machine) == ('Darwin', 'x86_64'):
+ out = get_cache_home() / 'llvm15-mac'
+ url = 'https://github.com/taichi-dev/taichi_assets/releases/download/llvm15/llvm-15-mac10.15.zip'
+ else:
+ raise RuntimeError(f'Unsupported platform: {u.system} {u.machine}')
+
+ download_dep(url, out, strip=1)
+ env_out['LLVM_DIR'] = str(out)
+
+
+@banner('Build Taichi Wheel')
+def build_wheel(python: Command, pip: Command, env: dict) -> None:
+ '''
+ Build the Taichi wheel
+ '''
+ pip.install('-r', 'requirements_dev.txt')
+ git.fetch('origin', 'master', '--tags')
+ proj = env['PROJECT_NAME']
+ proj_tags = []
+ extra = []
+
+ if proj == 'taichi-nightly':
+ proj_tags.extend(['egg_info', '--tag-date'])
+ # Include C-API in nightly builds
+ os.environ['TAICHI_CMAKE_ARGS'] += ' -DTI_WITH_C_API=ON'
+
+ if platform.system() == 'Linux':
+ if is_manylinux2014():
+ extra.extend(['-p', 'manylinux2014_x86_64'])
+ else:
+ extra.extend(['-p', 'manylinux_2_27_x86_64'])
+
+ python('misc/make_changelog.py', '--ver', 'origin/master', '--repo_dir',
+ './', '--save')
+
+ with environ(env):
+ python('setup.py', *proj_tags, 'bdist_wheel', *extra)
+
+
+def main() -> None:
+ env = {
+ 'TAICHI_CMAKE_ARGS': os.environ.get('TAICHI_CMAKE_ARGS', ''),
+ 'PROJECT_NAME': os.environ.get('PROJECT_NAME', 'taichi'),
+ }
+ setup_llvm(env)
+ sccache = setup_sccache(env)
+
+ # NOTE: We use conda/venv to build wheels, which may not be the same python
+ # running this script.
+ python, pip = setup_python(os.environ['PY'])
+ build_wheel(python, pip, env)
+
+ sccache('-s')
+
+ distfiles = glob.glob('dist/*.whl')
+ if len(distfiles) != 1:
+ raise RuntimeError(
+ f'Failed to produce exactly one wheel file: {distfiles}')
+
+
+if __name__ == '__main__':
+ main()
diff --git a/.github/workflows/scripts/ci_common/__init__.py b/.github/workflows/scripts/ci_common/__init__.py
new file mode 100644
index 0000000000000..484102f1f383b
--- /dev/null
+++ b/.github/workflows/scripts/ci_common/__init__.py
@@ -0,0 +1,2 @@
+from .bootstrap import early_init
+early_init()
diff --git a/.github/workflows/scripts/ci_common/bootstrap.py b/.github/workflows/scripts/ci_common/bootstrap.py
new file mode 100644
index 0000000000000..17c0f486b3aea
--- /dev/null
+++ b/.github/workflows/scripts/ci_common/bootstrap.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+
+# -- stdlib --
+import importlib
+import os
+import sys
+from pathlib import Path
+
+# -- third party --
+# -- own --
+
+
+# -- code --
+def is_in_venv() -> bool:
+ '''
+ Are we in a virtual environment?
+ '''
+ return hasattr(sys, 'real_prefix') or (hasattr(sys, 'base_prefix')
+ and sys.base_prefix != sys.prefix)
+
+
+def ensure_dependencies():
+ '''
+ Automatically install dependencies if they are not installed.
+ '''
+ p = Path(__file__).parent.parent / 'requirements.txt'
+ if not p.exists():
+ raise RuntimeError(f'Cannot find {p}')
+
+ user = '' if is_in_venv() else '--user'
+
+ with open(p) as f:
+ deps = [i.strip().split('=')[0] for i in f.read().splitlines()]
+
+ try:
+ for dep in deps:
+ importlib.import_module(dep)
+ except ModuleNotFoundError:
+ print('Installing dependencies...')
+ if os.system(f'{sys.executable} -m pip install {user} -U pip'):
+ raise Exception('Unable to upgrade pip!')
+ if os.system(f'{sys.executable} -m pip install {user} -U -r {p}'):
+ raise Exception('Unable to install dependencies!')
+ os.execl(sys.executable, sys.executable, *sys.argv)
+
+
+def chdir_to_root():
+ '''
+ Change working directory to the root of the repository
+ '''
+ root = Path('/')
+ p = Path(__file__).resolve()
+ while p != root:
+ if (p / '.git').exists():
+ os.chdir(p)
+ break
+ p = p.parent
+
+
+def set_common_env():
+ '''
+ Set common environment variables.
+ '''
+ os.environ['TI_CI'] = '1'
+
+
+_Environ = os.environ.__class__
+
+
+class _EnvironWrapper(_Environ):
+ def __setitem__(self, name: str, value: str) -> None:
+ orig = self.get(name)
+ _Environ.__setitem__(self, name, value)
+ new = self[name]
+
+ if orig == new:
+ return
+
+ from .escapes import escape_codes
+
+ G = escape_codes['bold_green']
+ R = escape_codes['bold_red']
+ N = escape_codes['reset']
+ print(f'{R}:: ENV -{name}={orig}{N}', file=sys.stderr, flush=True)
+ print(f'{G}:: ENV +{name}={new}{N}', file=sys.stderr, flush=True)
+
+
+def monkey_patch_environ():
+ '''
+ Monkey patch os.environ to print changes.
+ '''
+ os.environ.__class__ = _EnvironWrapper
+
+
+def early_init():
+ '''
+ Do early initialization.
+ This must be called before any other non-stdlib imports.
+ '''
+ ensure_dependencies()
+ chdir_to_root()
+ monkey_patch_environ()
+ set_common_env()
diff --git a/.github/workflows/scripts/ci_common/dep.py b/.github/workflows/scripts/ci_common/dep.py
new file mode 100644
index 0000000000000..be99f6885c7f5
--- /dev/null
+++ b/.github/workflows/scripts/ci_common/dep.py
@@ -0,0 +1,100 @@
+# -*- coding: utf-8 -*-
+
+# -- stdlib --
+from pathlib import Path
+from urllib.parse import urlparse
+import zipfile
+import shutil
+
+# -- third party --
+import requests
+
+# -- own --
+from .misc import get_cache_home
+from .tinysh import tar
+
+
+# -- code --
+def unzip(filename, extract_dir, strip=0):
+ '''
+ Unpack zip `filename` to `extract_dir`, optionally stripping `strip` components.
+ '''
+ if not zipfile.is_zipfile(filename):
+ raise Exception(f"{filename} is not a zip file")
+
+ extract_dir = Path(extract_dir)
+
+ ar = zipfile.ZipFile(filename)
+ try:
+ for info in ar.infolist():
+ name = info.filename
+
+ # don't extract absolute paths or ones with .. in them
+ if name.startswith('/') or '..' in name:
+ continue
+
+ target = extract_dir.joinpath(*name.split('/')[strip:]).resolve()
+ if not target:
+ continue
+
+ target.parent.mkdir(parents=True, exist_ok=True)
+ if not name.endswith('/'):
+ # file
+ data = ar.read(info.filename)
+ f = open(target, 'wb')
+ try:
+ f.write(data)
+ finally:
+ f.close()
+ del data
+ finally:
+ ar.close()
+
+
+def download_dep(url, outdir, *, strip=0, force=False):
+ '''
+ Download a dependency archive from `url` and expand it to `outdir`,
+ optionally stripping `strip` components.
+ '''
+ outdir = Path(outdir)
+ if outdir.exists() and len(list(outdir.glob('*'))) > 0 and not force:
+ return
+
+ shutil.rmtree(outdir, ignore_errors=True)
+
+ parsed = urlparse(url)
+ name = Path(parsed.path).name
+ escaped = url.replace('/', '_').replace(':', '_')
+ depcache = get_cache_home() / 'deps'
+ depcache.mkdir(parents=True, exist_ok=True)
+ local_cached = depcache / escaped
+
+ if not local_cached.exists():
+ cached_url = f'http://botmaster.tgr:9000/misc/depcache/{escaped}/{name}'
+ try:
+ resp = requests.head(cached_url, timeout=1)
+ if resp.ok:
+ print('Using near cache: ', cached_url)
+ url = cached_url
+ except Exception:
+ pass
+
+ import tqdm
+
+ with requests.get(url, stream=True) as r:
+ r.raise_for_status()
+ total_size = int(r.headers.get('content-length', 0))
+ prog = tqdm.tqdm(unit="B", unit_scale=True, unit_divisor=1024, total=total_size, desc=name)
+ with prog, open(local_cached, 'wb') as f:
+ for chunk in r.iter_content(chunk_size=8192):
+ sz = f.write(chunk)
+ prog.update(sz)
+
+ outdir.mkdir(parents=True, exist_ok=True)
+
+ if name.endswith('.zip'):
+ unzip(local_cached, outdir, strip=strip)
+ elif name.endswith('.tar.gz') or name.endswith('.tgz'):
+ tar('-xzf', local_cached, '-C', outdir, f'--strip-components={strip}')
+ else:
+ raise RuntimeError(f'Unknown file type: {name}')
diff --git a/.github/workflows/scripts/ci_common/escapes.py b/.github/workflows/scripts/ci_common/escapes.py
new file mode 100644
index 0000000000000..8cb327f9965b3
--- /dev/null
+++ b/.github/workflows/scripts/ci_common/escapes.py
@@ -0,0 +1,60 @@
+"""
+Generates a dictionary of ANSI escape codes.
+
+http://en.wikipedia.org/wiki/ANSI_escape_code
+
+Uses colorama as an optional dependency to support color on Windows
+
+---
+Copied from colorlog
+---
+
+This file is currently only used to display colored banner.
+"""
+
+__all__ = ('escape_codes', 'parse_colors')
+
+
+# Returns escape codes from format codes
+def esc(*x):
+ return '\033[' + ';'.join(x) + 'm'
+
+
+# The initial list of escape codes
+escape_codes = {
+ 'reset': esc('0'),
+ 'bold': esc('01'),
+ 'thin': esc('02')
+}
+
+# The color names
+COLORS = [
+ 'black',
+ 'red',
+ 'green',
+ 'yellow',
+ 'blue',
+ 'purple',
+ 'cyan',
+ 'white'
+]
+
+PREFIXES = [
+ # Foreground without prefix
+ ('3', ''), ('01;3', 'bold_'), ('02;3', 'thin_'),
+
+ # Foreground with fg_ prefix
+ ('3', 'fg_'), ('01;3', 'fg_bold_'), ('02;3', 'fg_thin_'),
+
+ # Background with bg_ prefix - bold/light works differently
+ ('4', 'bg_'), ('10', 'bg_bold_'),
+]
+
+for prefix, prefix_name in PREFIXES:
+ for code, name in enumerate(COLORS):
+ escape_codes[prefix_name + name] = esc(prefix + str(code))
+
+
+def parse_colors(sequence):
+ """Return escape codes from a color sequence."""
+ return ''.join(escape_codes[n] for n in sequence.split(',') if n)
diff --git a/.github/workflows/scripts/ci_common/misc.py b/.github/workflows/scripts/ci_common/misc.py
new file mode 100644
index 0000000000000..5d29636fa2c75
--- /dev/null
+++ b/.github/workflows/scripts/ci_common/misc.py
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+
+# -- stdlib --
+from pathlib import Path
+from typing import Callable
+import inspect
+import os
+import platform
+import sys
+
+# -- third party --
+# -- own --
+from .escapes import escape_codes
+
+
+# -- code --
+def is_manylinux2014() -> bool:
+ '''
+ Are we in a manylinux2014 environment?
+ This means a particular CentOS docker image.
+ '''
+ return platform.system() == 'Linux' and Path('/etc/centos-release').exists()
+
+
+def get_cache_home() -> Path:
+ '''
+ Get the cache home directory. All intermediate files should be stored here.
+ '''
+ if platform.system() == 'Windows':
+ return Path(os.environ['LOCALAPPDATA']) / 'build-cache'
+ else:
+ return Path.home() / '.cache' / 'build-cache'
+
+
+def banner(msg: str) -> Callable:
+ '''
+ Decorate a function to print a banner before and after it.
+ '''
+ def decorate(f: Callable) -> Callable:
+ sig = inspect.signature(f)
+ C = escape_codes['bold_cyan']
+ R = escape_codes['bold_red']
+ N = escape_codes['reset']
+ def wrapper(*args, **kwargs):
+ _args = sig.bind(*args, **kwargs)
+ print(f'{C}:: -----BEGIN {msg}-----{N}'.format(**_args.arguments), file=sys.stderr, flush=True)
+ try:
+ ret = f(*args, **kwargs)
+ print(f'{C}:: -----END {msg}-----{N}'.format(**_args.arguments), file=sys.stderr, flush=True)
+ return ret
+ except BaseException as e:
+ print(f'{R}!! -----EXCEPTION {msg}-----{N}'.format(**_args.arguments), file=sys.stderr, flush=True)
+ raise
+
+ return wrapper
+
+ return decorate
diff --git a/.github/workflows/scripts/ci_common/python.py b/.github/workflows/scripts/ci_common/python.py
new file mode 100644
index 0000000000000..969c0927c55db
--- /dev/null
+++ b/.github/workflows/scripts/ci_common/python.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+
+# -- stdlib --
+from pathlib import Path
+from typing import Optional, Tuple
+import os
+import sys
+
+# -- third party --
+# -- own --
+from .misc import banner
+from .tinysh import Command, sh
+
+
+# -- code --
+@banner('Setup Python {version}')
+def setup_python(version: Optional[str] = None) -> Tuple[Command, Command]:
+ '''
+ Find the required Python environment and return the `python` and `pip` commands.
+ '''
+ assert version
+
+ home = Path.home().resolve()
+
+ for d in ['miniconda', 'miniconda3', 'miniforge3']:
+ env = home / d / 'envs' / version
+ exe = env / 'bin' / 'python'
+ if not exe.exists():
+ continue
+
+ os.environ['PATH'] = f'{env / "bin"}:{os.environ["PATH"]}'
+ python = sh.bake(str(exe))
+ pip = python.bake('-m', 'pip')
+ break
+ else:
+ v = sys.version_info
+ if f'{v.major}.{v.minor}' == version:
+ python = sh.bake(sys.executable)
+ pip = python.bake('-m', 'pip')
+ else:
+ raise ValueError(f'No python {version} found')
+
+ pip.install('-U', 'pip')
+ pip.uninstall('-y', 'taichi', 'taichi-nightly')
+
+ return python, pip
diff --git a/.github/workflows/scripts/ci_common/sccache.py b/.github/workflows/scripts/ci_common/sccache.py
new file mode 100644
index 0000000000000..b9f7cb5c49b39
--- /dev/null
+++ b/.github/workflows/scripts/ci_common/sccache.py
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+
+# -- stdlib --
+import os
+import platform
+
+# -- third party --
+# -- own --
+from .dep import download_dep
+from .misc import banner, get_cache_home
+from .tinysh import Command, sh
+
+
+# -- code --
+@banner("Setup sccache")
+def setup_sccache(env_out: dict) -> Command:
+ """
+ Download and install sccache, setup compiler wrappers, and return the `sccache` command.
+ """
+ root = get_cache_home() / "sccache"
+ bin = root / "bin"
+
+ u = platform.uname()
+ if u.system in ("Linux", "Darwin"):
+ exe = bin / "sccache"
+ elif u.system == "Windows":
+ exe = bin / "sccache.exe"
+ else:
+ raise RuntimeError(f"Unsupported platform: {u.system} {u.machine}")
+
+ if not exe.exists():
+ if u.system == "Linux":
+ download_dep(
+ "https://github.com/mozilla/sccache/releases/download/v0.3.1/sccache-v0.3.1-x86_64-unknown-linux-musl.tar.gz",
+ bin,
+ strip=1,
+ )
+ elif (u.system, u.machine) == ("Darwin", "arm64"):
+ download_dep(
+ "https://github.com/mozilla/sccache/releases/download/v0.3.1/sccache-v0.3.1-aarch64-apple-darwin.tar.gz",
+ bin,
+ strip=1,
+ )
+ elif (u.system, u.machine) == ("Darwin", "x86_64"):
+ download_dep(
+ "https://github.com/mozilla/sccache/releases/download/v0.3.1/sccache-v0.3.1-x86_64-apple-darwin.tar.gz",
+ bin,
+ strip=1,
+ )
+ elif u.system == "Windows":
+ download_dep(
+ "https://github.com/mozilla/sccache/releases/download/v0.3.1/sccache-v0.3.1-x86_64-pc-windows-msvc.tar.gz",
+ bin,
+ strip=1,
+ )
+ else:
+ raise RuntimeError(f"Unsupported platform: {u.system} {u.machine}")
+
+ exe.chmod(0o755)
+
+ env_out["SCCACHE_LOG"] = "error"
+ env_out[
+ "TAICHI_CMAKE_ARGS"] += f" -DCMAKE_C_COMPILER_LAUNCHER={exe} -DCMAKE_CXX_COMPILER_LAUNCHER={exe}"
+
+ #
+ cache = root / "cache"
+ cache.mkdir(parents=True, exist_ok=True)
+ env_out["SCCACHE_DIR"] = str(cache)
+ env_out["SCCACHE_CACHE_SIZE"] = "40G"
+ #
+
+ return sh.bake(str(exe))
diff --git a/.github/workflows/scripts/ci_common/tinysh.py b/.github/workflows/scripts/ci_common/tinysh.py
new file mode 100644
index 0000000000000..606783568b822
--- /dev/null
+++ b/.github/workflows/scripts/ci_common/tinysh.py
@@ -0,0 +1,135 @@
+# -*- coding: utf-8 -*-
+
+# -- stdlib --
+import os
+import platform
+from contextlib import contextmanager
+from typing import Any, Mapping, Sequence
+
+# -- third party --
+# -- own --
+
+# -- code --
+
+# A minimal and naive imitiation of the sh library, which can work on Windows.
+# NOT written as a general purpose library, wild assumptions are made.
+
+IS_WINDOWS = platform.system() == 'Windows'
+
+if IS_WINDOWS:
+ import mslex
+ quote = mslex.quote
+else:
+ import shlex
+ quote = shlex.quote
+
+
+class CommandFailed(Exception):
+ def __init__(self, cmd, code):
+ self.cmd = cmd
+ self.code = code
+
+ def __str__(self):
+ return f'Command {self.cmd} failed with code {self.code}'
+
+
+ENVIRON_STACK = []
+PREFIX_STACK = []
+
+
+class Command:
+ def __init__(self, *args: str):
+ self.args = list((map(str, args)))
+
+ def __getattribute__(self, name: str) -> Any:
+ if name in ('args', 'bake') or name.startswith('__'):
+ return object.__getattribute__(self, name)
+
+ return self.bake(name)
+
+ def bake(self, *moreargs: Sequence[str]) -> 'Command':
+ args = object.__getattribute__(self, 'args')
+ cls = object.__getattribute__(self, '__class__')
+ return cls(*args, *moreargs)
+
+ def __call__(self, *moreargs: Sequence[str]) -> None:
+ args = object.__getattribute__(self, 'args')
+ args = args + list(map(str, moreargs))
+
+ prefixes = []
+ for v in PREFIX_STACK:
+ prefixes.extend(v)
+
+ env = os.environ.copy()
+ for v in ENVIRON_STACK:
+ env.update(v)
+
+ args = prefixes + args
+
+ code = os.spawnvpe(os.P_WAIT, args[0], args, env)
+ if code:
+ cmd = ' '.join([quote(v) for v in args])
+ raise CommandFailed(cmd, code)
+
+ def __repr__(self) -> str:
+ return f""
+
+
+@contextmanager
+def environ(*envs: Mapping[str, str]):
+ '''
+ Set command environment variables.
+ '''
+ global ENVIRON_STACK
+
+ this = {}
+ for env in envs:
+ this.update(env)
+
+ try:
+ ENVIRON_STACK.append(this)
+ yield
+ finally:
+ assert ENVIRON_STACK[-1] is this
+ ENVIRON_STACK.pop()
+
+
+@contextmanager
+def prefix(*args: str):
+ '''
+ Set command prefixes.
+ '''
+ global PREFIX_STACK
+
+ l = list(map(str, args))
+
+ try:
+ PREFIX_STACK.insert(0, l)
+ yield
+ finally:
+ assert PREFIX_STACK[0] is l
+ PREFIX_STACK.pop(0)
+
+
+@contextmanager
+def _nop_contextmanager():
+ yield
+
+
+def sudo():
+ '''
+ Wrap a command with sudo.
+ '''
+ if IS_WINDOWS:
+ return _nop_contextmanager()
+ else:
+ return prefix('sudo')
+
+
+sh = Command()
+git = sh.git
+# Use setup_python !
+# python = sh.bake(sys.executable)
+# pip = python.bake('-m', 'pip')
+sccache = sh.sccache
+tar = sh.tar
diff --git a/.github/workflows/scripts/requirements.txt b/.github/workflows/scripts/requirements.txt
new file mode 100644
index 0000000000000..2a588b2e533cc
--- /dev/null
+++ b/.github/workflows/scripts/requirements.txt
@@ -0,0 +1,4 @@
+pip
+tqdm
+requests
+mslex
diff --git a/.github/workflows/scripts/unix-build.sh b/.github/workflows/scripts/unix-build.sh
deleted file mode 100755
index 31cd8546c3279..0000000000000
--- a/.github/workflows/scripts/unix-build.sh
+++ /dev/null
@@ -1,86 +0,0 @@
-#!/bin/bash
-
-set -ex
-
-. $(dirname $0)/common-utils.sh
-
-[[ "$IN_DOCKER" == "true" ]] && cd taichi
-
-if [[ $OSTYPE == "linux-"* ]]; then
- if [ ! -z "$AMDGPU_TEST" ]; then
- sudo ln -s /usr/bin/clang++-10 /usr/bin/clang++
- sudo ln -s /usr/bin/clang-10 /usr/bin/clang
- sudo ln -s /usr/bin/ld.lld-10 /usr/bin/ld.lld
- export LLVM_DIR="/taichi-llvm-15.0.0-linux"
- else
- if [ ! -d ~/taichi-llvm-15 ]; then
- pushd ~
- if [ -f /etc/centos-release ] ; then
- # FIXIME: prebuilt llvm15 on ubuntu didn't work on manylinux image of centos. Once that's fixed, remove this hack.
- wget https://github.com/ailzhang/torchhub_example/releases/download/0.3/taichi-llvm-15-linux.zip
- else
- wget https://github.com/taichi-dev/taichi_assets/releases/download/llvm15/taichi-llvm-15-linux.zip
- fi
- unzip taichi-llvm-15-linux.zip && rm taichi-llvm-15-linux.zip
- popd
- fi
- export LLVM_DIR="$HOME/taichi-llvm-15"
- fi
-
-elif [ "$(uname -s):$(uname -m)" == "Darwin:arm64" ]; then
- # The following commands are done manually to save time.
- if [ ! -d ~/taichi-llvm-15-m1 ]; then
- pushd ~
- wget https://github.com/taichi-dev/taichi_assets/releases/download/llvm15/taichi-llvm-15-m1.zip
- unzip taichi-llvm-15-m1.zip && rm taichi-llvm-15-m1.zip
- popd
- fi
-
- export LLVM_DIR="$HOME/taichi-llvm-15-m1"
-elif [ "$(uname -s):$(uname -m)" == "Darwin:x86_64" ]; then
- # The following commands are done manually to save time.
- if [ ! -d ~/llvm-15-mac10.15 ]; then
- pushd ~
- wget https://github.com/taichi-dev/taichi_assets/releases/download/llvm15/llvm-15-mac10.15.zip
- unzip llvm-15-mac10.15.zip && rm llvm-15-mac10.15.zip
- popd
- fi
-
- export LLVM_DIR="$HOME/llvm-15-mac10.15/"
-fi
-
-build_taichi_wheel() {
- python3 -m pip install -r requirements_dev.txt
- git fetch origin master --tags
- PROJECT_TAGS=""
- EXTRA_ARGS=""
- if [ "$PROJECT_NAME" = "taichi-nightly" ]; then
- PROJECT_TAGS="egg_info --tag-date"
- # Include C-API in nightly builds
- TAICHI_CMAKE_ARGS="$TAICHI_CMAKE_ARGS -DTI_WITH_C_API:BOOL=ON"
- fi
-
- if [[ $OSTYPE == "linux-"* ]]; then
- if [ -f /etc/centos-release ] ; then
- EXTRA_ARGS="-p manylinux2014_x86_64"
- else
- EXTRA_ARGS="-p manylinux_2_27_x86_64"
- fi
- fi
- python3 misc/make_changelog.py --ver origin/master --repo_dir ./ --save
-
- python3 setup.py $PROJECT_TAGS bdist_wheel $EXTRA_ARGS
- sccache -s || true
-}
-
-fix-build-cache-permission
-
-setup-sccache-local
-setup_python
-
-build_taichi_wheel
-NUM_WHL=$(ls dist/*.whl | wc -l)
-if [ $NUM_WHL -ne 1 ]; then echo "ERROR: created more than 1 whl." && exit 1; fi
-
-chmod -R 777 "$SCCACHE_DIR"
-rm -f python/CHANGELOG.md
diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml
index 00691b8c09e12..20afd1fd1a720 100644
--- a/.github/workflows/testing.yml
+++ b/.github/workflows/testing.yml
@@ -140,7 +140,7 @@ jobs:
run: |
# Use the molten-vk v1.1.10 downloaded from taichi assets
brew uninstall molten-vk -f
- .github/workflows/scripts/unix-build.sh
+ .github/workflows/scripts/build.py
env:
CXX: clang++
TAICHI_CMAKE_ARGS: >-
@@ -203,7 +203,7 @@ jobs:
ci-docker-run-gpu --name taichi-build \
registry.taichigraphics.com/taichidev-ubuntu18.04:v0.3.4 \
- /home/dev/taichi/.github/workflows/scripts/unix-build.sh
+ /home/dev/taichi/.github/workflows/scripts/build.py
env:
PY: py38
@@ -292,7 +292,7 @@ jobs:
ci-docker-run-amdgpu --name taichi-build \
registry.taichigraphics.com/taichidev-ubuntu18.04.amdgpu:v0.0.3 \
- /home/dev/taichi/.github/workflows/scripts/unix-build.sh
+ /home/dev/taichi/.github/workflows/scripts/build.py
env:
PY: py38
@@ -421,7 +421,7 @@ jobs:
prepare-build-cache
brew install molten-vk
brew install llvm@15
- .github/workflows/scripts/unix-build.sh
+ .github/workflows/scripts/build.py
env:
PY: ${{ matrix.python }}
CXX: clang++
@@ -511,7 +511,7 @@ jobs:
ci-docker-run --name taichi-build-host \
-v $TAICHI_WHEEL_DIR:/home/dev/taichi/dist \
registry.taichigraphics.com/taichidev-ubuntu18.04:v0.3.4 \
- /home/dev/taichi/.github/workflows/scripts/unix-build.sh
+ /home/dev/taichi/.github/workflows/scripts/build.py
env:
TAICHI_CMAKE_ARGS: >-
-DTI_WITH_OPENGL:BOOL=ON