forked from flagos-ai/FlagGems
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsetup.sh
More file actions
executable file
·274 lines (232 loc) · 9.85 KB
/
Copy pathsetup.sh
File metadata and controls
executable file
·274 lines (232 loc) · 9.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
#!/bin/bash
# Copyright 2026 FlagOS Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
ok() { printf " ${GREEN}[OK]${NC}\n"; }
fail() { printf " ${RED}[FAILED]${NC}\n"; exit 1; }
BACKENDS_YAML="src/flag_gems/backends.yaml"
# ── Validate argument ─────────────────────────────────────────
[ "$#" -eq 1 ] || { echo "Usage: $0 <BACKEND>"; exit 1; }
BACKEND="${1}"
# ── Read config from backends.yaml ────────────────────────────
if [ ! -f "$BACKENDS_YAML" ]; then
echo "Error: $BACKENDS_YAML not found. Run from the FlagGems repo root."
exit 1
fi
# Phase 1: Extract only python version and vendor using grep/awk
# (no pyyaml dependency — runs before venv creation)
PYTHON_VERSION=$(awk "/^ ${BACKEND}:/{found=1} found && /python:/{print \$2; exit}" "$BACKENDS_YAML" | tr -d '"')
if [ -z "${PYTHON_VERSION}" ]; then
echo "Error: unknown backend '${BACKEND}'"
echo "Available backends:"
awk '/^ [a-z].*:$/{gsub(/:$/,""); print " "$1}' "$BACKENDS_YAML"
exit 1
fi
VENDOR=$(echo "${BACKEND}" | sed 's/-[^-]*$//')
[ "${VENDOR}" = "${BACKEND}" ] && VENDOR="${BACKEND}"
PYPI_BASE=$(grep '^pypi_base:' "$BACKENDS_YAML" | sed 's/^pypi_base: *"//;s/"$//')
FLAGOS_PYPI=$(echo "${PYPI_BASE}" | sed "s/{vendor}/${VENDOR}/")
MIRROR=$(grep '^mirror:' "$BACKENDS_YAML" | sed 's/^mirror: *"//;s/"$//')
printf "Backend: ${BACKEND} (vendor: ${VENDOR})"
ok
# ── Detect or install uv ─────────────────────────────────────
UV_VERSION="0.11.22"
UV_MIRROR="https://resource.flagos.net/repository/flagos-filestore/utils"
printf "Checking uv ..."
export PATH="${HOME}/.local/bin:$PATH"
if command -v uv &>/dev/null; then
printf " $(uv --version)"
ok
else
printf " not found, installing ...\n"
ARCH=$(uname -m)
mkdir -p "$HOME/.local/bin"
curl -sSf "${UV_MIRROR}/uv-${ARCH}-${UV_VERSION}-linux-gnu.tar.gz" \
| tar xz -C "$HOME/.local/bin" 2>/dev/null \
|| { curl -LsSf https://astral.sh/uv/install.sh | sh; }
command -v uv &>/dev/null || { printf "uv installation"; fail; }
printf "Installed $(uv --version)"
ok
fi
# Persist PATH for subsequent GitHub Actions steps
[ -n "${GITHUB_PATH:-}" ] && echo "$HOME/.local/bin" >> "$GITHUB_PATH"
# ── Install Python via uv ────────────────────────────────────
printf "Installing Python ${PYTHON_VERSION} ..."
uv python install "${PYTHON_VERSION}" --python-preference only-managed -q || fail
ok
# ── Create virtual environment ────────────────────────────────
printf "Creating virtual environment ..."
uv venv .venv --python "${PYTHON_VERSION}" --python-preference only-managed -q || fail
ok
source .venv/bin/activate
printf "Python: $(python --version)"
ok
# ── Source vendor environment ─────────────────────────────────
export USE_TRITON="${USE_TRITON:-}"
source tools/env.sh "${BACKEND}"
# ── Install build tools ──────────────────────────────────────
printf "Installing build tools ..."
uv pip install -q \
"wheel==0.45.0" \
"setuptools>=64.0,<77" \
"setuptools-scm>=8,<10" \
"scikit-build-core==0.12.2" \
"pybind11==3.0.3" \
"cmake>=3.20,<4" \
"ninja==1.13.0" \
"PyYAML==6.0.3" \
--index "${MIRROR}" \
|| fail
ok
# ── Phase 2: Full YAML parse (pyyaml now available in venv) ──
eval $(python3 -c "
import yaml, sys
cfg = yaml.safe_load(open('${BACKENDS_YAML}'))
b = cfg['backends']['${BACKEND}']
cmake_backend = b.get('cmake_backend', '')
print(f'CMAKE_BACKEND={cmake_backend}')
ft = b.get('flagtree', '')
if isinstance(ft, list):
ft = ' '.join(ft)
print(f'FLAGTREE_PKGS=\"{ft}\"')
tr = b.get('triton', '')
if isinstance(tr, list):
tr = ' '.join(tr)
print(f'TRITON_PKGS=\"{tr}\"')
triton_post = []
for item in b.get('triton_post_install', []):
if isinstance(item, str):
triton_post.append(item)
print(f'TRITON_POST_INSTALL=\"{\" \".join(triton_post)}\"')
")
# ── C++ extensions ───────────────────────────────────────────
# Set ENABLE_CPP=1 to build C++ wrapped operators.
# Default: OFF (C++ extensions require vendor SDK and toolchain).
# The main package is pure Python; when ENABLE_CPP=1 the native extension is
# built and installed separately from the cpp/ subdirectory (see below).
if [ "${ENABLE_CPP:-0}" = "1" ]; then
if [ -z "${CMAKE_BACKEND}" ]; then
echo "Error: ENABLE_CPP=1 but backend '${BACKEND}' does not support C++ extensions"
exit 1
fi
printf "C++ extensions: ON (${CMAKE_BACKEND})"
ok
else
printf "C++ extensions: OFF"
ok
fi
# ── Install FlagGems ──────────────────────────────────────────
# Use --no-build-isolation so the build process reuses the build tools
# already installed in the current venv.
# Fetch tags and deepen history for setuptools-scm version detection.
# Shallow clones (CI default) lack tag reachability.
git fetch --tags --unshallow --quiet 2>/dev/null \
|| git fetch --tags --depth=500 --quiet 2>/dev/null \
|| git fetch --tags --quiet 2>/dev/null \
|| true
printf "Installing FlagGems [${BACKEND}] ..."
uv pip install --no-build-isolation ".[${BACKEND}]" \
--default-index "${FLAGOS_PYPI}" \
--index "${MIRROR}" \
|| fail
ok
# ── Install C++ wrapped operators (optional) ─────────────────
# The native extension is a separate distribution (flag-gems-cpp-<vendor>) that
# installs its .so files into the flag_gems/ namespace. Build it from cpp/ with
# the vendor name injected into cpp/pyproject.toml.
if [ "${ENABLE_CPP:-0}" = "1" ]; then
vendor_lc="$(echo "${CMAKE_BACKEND}" | tr '[:upper:]' '[:lower:]')"
tools/set_cpp_vendor.sh "${vendor_lc}" || fail
printf "Installing FlagGems C++ extensions [${CMAKE_BACKEND}] ..."
CMAKE_ARGS="-DFLAGGEMS_BUILD_C_EXTENSIONS=ON -DFLAGGEMS_BACKEND=${CMAKE_BACKEND}" \
uv pip install --no-build-isolation ./cpp \
--default-index "${FLAGOS_PYPI}" \
--index "${MIRROR}" \
|| fail
ok
fi
# ── Compiler selection ───────────────────────────────────────
# COMPILER controls which Triton-compatible compiler to use:
# COMPILER=flagtree → use FlagTree (error if unavailable)
# COMPILER=triton → use vendor Triton
# unset → auto: FlagTree if available, otherwise Triton
COMPILER="${COMPILER:-}"
if [ -z "${COMPILER}" ]; then
if [ -n "${FLAGTREE_PKGS}" ]; then
COMPILER=flagtree
else
printf "WARNING: FlagTree is not available for ${BACKEND}, falling back to Triton.\n"
COMPILER=triton
fi
fi
if [ "${COMPILER}" = "flagtree" ]; then
if [ -n "${FLAGTREE_PKGS}" ]; then
printf "Installing FlagTree ..."
uv pip uninstall triton
uv pip install -q ${FLAGTREE_PKGS} --default-index "${FLAGOS_PYPI}" || fail
ok
else
echo "Error: COMPILER=flagtree but FlagTree is not available for '${BACKEND}'."
exit 1
fi
fi
if [ "${COMPILER}" = "triton" ] && [ -n "${TRITON_PKGS}" ]; then
printf "Installing Triton ..."
uv pip uninstall flagtree
uv pip install -q ${TRITON_PKGS} --default-index "${FLAGOS_PYPI}" || fail
ok
elif [ "${COMPILER}" = "triton" ] && [ -z "${TRITON_PKGS}" ]; then
echo "Error: COMPILER=triton but no triton packages configured for '${BACKEND}'"
exit 1
fi
if [ "${COMPILER}" != "flagtree" ] && [ "${COMPILER}" != "triton" ]; then
echo "Error: unknown COMPILER value '${COMPILER}' (expected 'flagtree' or 'triton')"
exit 1
fi
# ── Triton-specific post-install ──────────────────────────────
if [ -n "${TRITON_POST_INSTALL}" ] && [ "${COMPILER}" = "triton" ]; then
for pkg in ${TRITON_POST_INSTALL}; do
printf "Triton post-install: ${pkg} ..."
uv pip install -q "${pkg}" --default-index "${FLAGOS_PYPI}" --index "${MIRROR}" || fail
ok
done
fi
# ── Install test dependencies ─────────────────────────────────
printf "Installing test dependencies ..."
uv pip install -q ".[test]" --index "${MIRROR}" || fail
ok
# ── Write env into .venv/bin/activate ────────────────────────
# So that `source .venv/bin/activate` sets up the full environment.
printf "Writing environment to .venv/bin/activate ..."
python3 -c "
import yaml
cfg = yaml.safe_load(open('${BACKENDS_YAML}'))
b = cfg['backends']['${BACKEND}']
lines = []
lines.append('')
lines.append('# --- FlagGems environment (${BACKEND}) ---')
for k, v in b.get('env', {}).items():
lines.append(f'export {k}={v}')
for script in b.get('env_source', []):
lines.append(f'[ -f {script} ] && source {script} || true')
lines.append('# --- end FlagGems environment ---')
with open('.venv/bin/activate', 'a') as f:
f.write('\n'.join(lines) + '\n')
" || fail
ok
printf "\n${GREEN}FlagGems setup complete for ${BACKEND}${NC}\n"
printf "Run: ${GREEN}source .venv/bin/activate${NC}\n"