|
| 1 | +#!/bin/bash |
| 2 | +set -e |
| 3 | + |
| 4 | +# Usage: |
| 5 | +# ./build.sh breakout # Build _C.so with breakout statically linked |
| 6 | +# ./build.sh breakout --float # float32 precision (required for --slowly) |
| 7 | +# ./build.sh breakout --debug # Debug build |
| 8 | +# ./build.sh breakout --local # Standalone executable (debug, sanitizers) |
| 9 | +# ./build.sh breakout --fast # Standalone executable (optimized) |
| 10 | +# ./build.sh breakout --web # Emscripten web build |
| 11 | +# ./build.sh breakout --profile # Kernel profiling binary |
| 12 | + |
| 13 | +ENV=${1:?Usage: ./build.sh ENV_NAME [--float] [--debug] [--local|--fast|--web|--profile]} |
| 14 | +MODE="" |
| 15 | +PRECISION="" |
| 16 | +DEBUG="" |
| 17 | +for arg in "${@:2}"; do |
| 18 | + case $arg in |
| 19 | + --float) PRECISION="-DPRECISION_FLOAT" ;; |
| 20 | + --debug) DEBUG=1 ;; |
| 21 | + --local) MODE=local ;; |
| 22 | + --fast) MODE=fast ;; |
| 23 | + --web) MODE=web ;; |
| 24 | + --profile) MODE=profile ;; |
| 25 | + esac |
| 26 | +done |
| 27 | + |
| 28 | +CLANG_WARN="\ |
| 29 | + -Wall \ |
| 30 | + -ferror-limit=3 \ |
| 31 | + -Werror=incompatible-pointer-types \ |
| 32 | + -Werror=return-type \ |
| 33 | + -Wno-error=incompatible-pointer-types-discards-qualifiers \ |
| 34 | + -Wno-incompatible-pointer-types-discards-qualifiers \ |
| 35 | + -Wno-error=array-parameter" |
| 36 | + |
| 37 | +if [ -n "$DEBUG" ] || [ "$MODE" = "local" ]; then |
| 38 | + CLANG_OPT="-g -O0 $CLANG_WARN" |
| 39 | + NVCC_OPT="-O0 -g" |
| 40 | + LINK_OPT="-g" |
| 41 | + [ "$PLATFORM" = "Linux" ] && CLANG_OPT="$CLANG_OPT -fsanitize=address,undefined,bounds,pointer-overflow,leak -fno-omit-frame-pointer" |
| 42 | +else |
| 43 | + CLANG_OPT="-O2 -DNDEBUG $CLANG_WARN" |
| 44 | + NVCC_OPT="-O3" |
| 45 | + LINK_OPT="-O2" |
| 46 | +fi |
| 47 | + |
| 48 | +# ============================================================================ |
| 49 | +# Platform + dependencies |
| 50 | +# ============================================================================ |
| 51 | + |
| 52 | +PLATFORM="$(uname -s)" |
| 53 | +if [ -d "ocean/$ENV" ]; then |
| 54 | + SRC_DIR="ocean/$ENV" |
| 55 | +elif [ -d "$ENV" ]; then |
| 56 | + SRC_DIR="$ENV" |
| 57 | +else |
| 58 | + echo "Error: environment '$ENV' not found" && exit 1 |
| 59 | +fi |
| 60 | + |
| 61 | +if [ "$PLATFORM" = "Linux" ]; then |
| 62 | + RAYLIB_NAME='raylib-5.5_linux_amd64' |
| 63 | +else |
| 64 | + RAYLIB_NAME='raylib-5.5_macos' |
| 65 | +fi |
| 66 | + |
| 67 | +RAYLIB_URL="https://github.com/raysan5/raylib/releases/download/5.5" |
| 68 | + |
| 69 | +download() { |
| 70 | + local name=$1 url=$2 |
| 71 | + [ -d "$name" ] && return |
| 72 | + echo "Downloading $name..." |
| 73 | + if [[ "$url" == *.zip ]]; then |
| 74 | + curl -sL "$url" -o "$name.zip" && unzip -q "$name.zip" && rm "$name.zip" |
| 75 | + else |
| 76 | + curl -sL "$url" -o "$name.tar.gz" && tar xf "$name.tar.gz" && rm "$name.tar.gz" |
| 77 | + fi |
| 78 | +} |
| 79 | + |
| 80 | +# Raylib (always needed) |
| 81 | +if [ "$MODE" = "web" ]; then |
| 82 | + RAYLIB_NAME='raylib-5.5_webassembly' |
| 83 | + download "$RAYLIB_NAME" "$RAYLIB_URL/$RAYLIB_NAME.zip" |
| 84 | +else |
| 85 | + download "$RAYLIB_NAME" "$RAYLIB_URL/$RAYLIB_NAME.tar.gz" |
| 86 | +fi |
| 87 | +[ ! -f "$RAYLIB_NAME/include/rlights.h" ] && \ |
| 88 | + curl -sL "https://raw.githubusercontent.com/raysan5/raylib/master/examples/shaders/rlights.h" \ |
| 89 | + -o "$RAYLIB_NAME/include/rlights.h" |
| 90 | + |
| 91 | +RAYLIB_A="$RAYLIB_NAME/lib/libraylib.a" |
| 92 | +INCLUDES=(-I./$RAYLIB_NAME/include -I./src) |
| 93 | +LINK_ARCHIVES="$RAYLIB_A" |
| 94 | +EXTRA_SRC="" |
| 95 | + |
| 96 | +# Box2d (impulse_wars only) |
| 97 | +if [ "$ENV" = "impulse_wars" ]; then |
| 98 | + if [ "$MODE" = "web" ]; then BOX2D_NAME='box2d-web' |
| 99 | + elif [ "$PLATFORM" = "Linux" ]; then BOX2D_NAME='box2d-linux-amd64' |
| 100 | + else BOX2D_NAME='box2d-macos-arm64' |
| 101 | + fi |
| 102 | + BOX2D_URL="https://github.com/capnspacehook/box2d/releases/latest/download" |
| 103 | + download "$BOX2D_NAME" "$BOX2D_URL/$BOX2D_NAME.tar.gz" |
| 104 | + INCLUDES+=(-I./$BOX2D_NAME/include -I./$BOX2D_NAME/src) |
| 105 | + LINK_ARCHIVES="$LINK_ARCHIVES ./$BOX2D_NAME/libbox2d.a" |
| 106 | +fi |
| 107 | + |
| 108 | +# Constellation needs cJSON |
| 109 | +[ "$ENV" = "constellation" ] && EXTRA_SRC="vendor/cJSON.c" && INCLUDES+=(-I./vendor) && OUTPUT_NAME="seethestars" |
| 110 | + |
| 111 | +# ============================================================================ |
| 112 | +# Standalone builds: --local, --fast, --web |
| 113 | +# ============================================================================ |
| 114 | + |
| 115 | +if [ "$MODE" = "web" ]; then |
| 116 | + [ ! -f "minshell.html" ] && \ |
| 117 | + curl -sL "https://raw.githubusercontent.com/raysan5/raylib/master/src/minshell.html" -o minshell.html |
| 118 | + mkdir -p "build_web/$ENV" |
| 119 | + echo "Building $ENV for web..." |
| 120 | + emcc \ |
| 121 | + -o "build_web/$ENV/game.html" \ |
| 122 | + "$SRC_DIR/$ENV.c" $EXTRA_SRC \ |
| 123 | + -O3 -Wall \ |
| 124 | + $LINK_ARCHIVES \ |
| 125 | + "${INCLUDES[@]}" \ |
| 126 | + -L. -L./$RAYLIB_NAME/lib \ |
| 127 | + -sASSERTIONS=2 -gsource-map \ |
| 128 | + -sUSE_GLFW=3 -sUSE_WEBGL2=1 -sASYNCIFY -sFILESYSTEM -sFORCE_FILESYSTEM=1 \ |
| 129 | + --shell-file ./minshell.html \ |
| 130 | + -sINITIAL_MEMORY=512MB -sALLOW_MEMORY_GROWTH -sSTACK_SIZE=512KB \ |
| 131 | + -DNDEBUG -DPLATFORM_WEB -DGRAPHICS_API_OPENGL_ES3 \ |
| 132 | + --preload-file resources/$ENV@resources/$ENV \ |
| 133 | + --preload-file resources/shared@resources/shared |
| 134 | + echo "Built: build_web/$ENV/game.html" |
| 135 | + exit 0 |
| 136 | +fi |
| 137 | + |
| 138 | +if [ "$MODE" = "local" ] || [ "$MODE" = "fast" ]; then |
| 139 | + FLAGS=( |
| 140 | + "${INCLUDES[@]}" |
| 141 | + "$SRC_DIR/$ENV.c" $EXTRA_SRC -o "${OUTPUT_NAME:-$ENV}" |
| 142 | + $LINK_ARCHIVES |
| 143 | + -lGL -lm -lpthread -fopenmp |
| 144 | + -DPLATFORM_DESKTOP |
| 145 | + ) |
| 146 | + [ "$PLATFORM" = "Darwin" ] && FLAGS+=(-framework Cocoa -framework IOKit -framework CoreVideo) |
| 147 | + clang $CLANG_OPT "${FLAGS[@]}" |
| 148 | + echo "Built: ./${OUTPUT_NAME:-$ENV}" |
| 149 | + exit 0 |
| 150 | +fi |
| 151 | + |
| 152 | +# ============================================================================ |
| 153 | +# Default: build _C.so with env statically linked |
| 154 | +# ============================================================================ |
| 155 | + |
| 156 | +CUDA_HOME=${CUDA_HOME:-${CUDA_PATH:-/usr/local/cuda}} |
| 157 | +NVCC="$CUDA_HOME/bin/nvcc" |
| 158 | + |
| 159 | +PYTHON_INCLUDE=$(python -c "import sysconfig; print(sysconfig.get_path('include'))") |
| 160 | +PYBIND_INCLUDE=$(python -c "import pybind11; print(pybind11.get_include())") |
| 161 | +NUMPY_INCLUDE=$(python -c "import numpy; print(numpy.get_include())") |
| 162 | +EXT_SUFFIX=$(python -c "import sysconfig; print(sysconfig.get_config_var('EXT_SUFFIX'))") |
| 163 | +OUTPUT="pufferlib/_C${EXT_SUFFIX}" |
| 164 | + |
| 165 | +# Step 1: Static env library |
| 166 | +BINDING_SRC="$SRC_DIR/binding.c" |
| 167 | +STATIC_OBJ="src/libstatic_${ENV}.o" |
| 168 | +STATIC_LIB="src/libstatic_${ENV}.a" |
| 169 | +[ ! -f "$BINDING_SRC" ] && echo "Error: $BINDING_SRC not found" && exit 1 |
| 170 | + |
| 171 | +echo "=== Building static env: $ENV ===" |
| 172 | +clang -c $CLANG_OPT \ |
| 173 | + -I. -Isrc -I$SRC_DIR \ |
| 174 | + -I./$RAYLIB_NAME/include -I$CUDA_HOME/include \ |
| 175 | + -DPLATFORM_DESKTOP \ |
| 176 | + -fno-semantic-interposition -fvisibility=hidden \ |
| 177 | + -fPIC -fopenmp \ |
| 178 | + "$BINDING_SRC" -o "$STATIC_OBJ" |
| 179 | +ar rcs "$STATIC_LIB" "$STATIC_OBJ" |
| 180 | + |
| 181 | +OBS_TENSOR_T=$(strings "$STATIC_OBJ" | grep 'Tensor$' | head -1) |
| 182 | +[ -z "$OBS_TENSOR_T" ] && echo "Error: Could not find OBS_TENSOR_T" && exit 1 |
| 183 | +echo "OBS_TENSOR_T=$OBS_TENSOR_T" |
| 184 | + |
| 185 | +# Step 2: Profile binary or Python bindings |
| 186 | +if [ "$MODE" = "profile" ]; then |
| 187 | + ARCH=${NVCC_ARCH:-sm_89} |
| 188 | + echo "=== Building profile binary (arch=$ARCH) ===" |
| 189 | + $NVCC $NVCC_OPT -arch=$ARCH -std=c++17 \ |
| 190 | + -I. -Isrc -I$SRC_DIR \ |
| 191 | + -I$CUDA_HOME/include -I$RAYLIB_NAME/include \ |
| 192 | + -DOBS_TENSOR_T=$OBS_TENSOR_T \ |
| 193 | + -DENV_NAME=$ENV \ |
| 194 | + -Xcompiler=-DPLATFORM_DESKTOP \ |
| 195 | + $PRECISION \ |
| 196 | + -Xcompiler=-fopenmp \ |
| 197 | + tests/profile_kernels.cu ini.c \ |
| 198 | + "$STATIC_LIB" "$RAYLIB_A" \ |
| 199 | + -lnccl -lnvidia-ml -lcublas -lcurand -lcudnn -lnvToolsExt \ |
| 200 | + -lGL -lm -lpthread -lomp5 \ |
| 201 | + -o profile |
| 202 | + echo "=== Built: ./profile ===" |
| 203 | + exit 0 |
| 204 | +fi |
| 205 | + |
| 206 | +echo "=== Compiling bindings.cu ===" |
| 207 | +$NVCC -c -Xcompiler -fPIC \ |
| 208 | + -Xcompiler=-D_GLIBCXX_USE_CXX11_ABI=1 \ |
| 209 | + -Xcompiler=-DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION \ |
| 210 | + -Xcompiler=-DPLATFORM_DESKTOP \ |
| 211 | + -std=c++17 \ |
| 212 | + -I. -Isrc \ |
| 213 | + -I$PYTHON_INCLUDE -I$PYBIND_INCLUDE -I$NUMPY_INCLUDE \ |
| 214 | + -I$CUDA_HOME/include -I$RAYLIB_NAME/include \ |
| 215 | + -Xcompiler=-fopenmp \ |
| 216 | + -DOBS_TENSOR_T=$OBS_TENSOR_T \ |
| 217 | + $PRECISION $NVCC_OPT \ |
| 218 | + src/bindings.cu -o src/bindings.o |
| 219 | + |
| 220 | +# Step 3: Link |
| 221 | +echo "=== Linking $OUTPUT ===" |
| 222 | +LINK_CMD=( |
| 223 | + g++ -shared -fPIC -fopenmp |
| 224 | + src/bindings.o "$STATIC_LIB" "$RAYLIB_A" |
| 225 | + -L$CUDA_HOME/lib64 |
| 226 | + -lcudart -lnccl -lnvidia-ml -lcublas -lcusolver -lcurand -lcudnn |
| 227 | + -lnvToolsExt -lomp5 |
| 228 | + $LINK_OPT |
| 229 | +) |
| 230 | +[ "$PLATFORM" = "Linux" ] && LINK_CMD+=(-Bsymbolic-functions) |
| 231 | +[ "$PLATFORM" = "Darwin" ] && LINK_CMD+=(-framework Cocoa -framework OpenGL -framework IOKit) |
| 232 | +LINK_CMD+=(-o "$OUTPUT") |
| 233 | +"${LINK_CMD[@]}" |
| 234 | + |
| 235 | +echo "=== Built: $OUTPUT ===" |
0 commit comments