build_linux.sh

cross platform rendering playground

build_linux.sh

10.38 KB
#!/usr/bin/env bash
# Vulkan build for vk-renderer + RHI examples (Linux).
# Usage: build_linux.sh [example] [-r] [-c]
#   example  Name under src/backend/conformance/ (e.g. triangle). Builds
#            src/backend/conformance/<example> with core + backend only.
#            Default (no example): full renderer build.
#   -r       Release build (default is Debug)
#   -c       Clean build (delete everything first)
# All build artifacts and output live under build/.
# The binary must run from the repo root (shader paths are repo-relative).
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"

build_type=debug
clean_build=0
example=""
for arg in "$@"; do
    case "$arg" in
        -r|release) build_type=release ;;
        -c)         clean_build=1 ;;
        *)          example="$arg" ;;
    esac
done
if [ -n "$example" ]; then
    echo "[$build_type vulkan build: $example]"
else
    echo "[$build_type build]"
fi

ROOT="$SCRIPT_DIR"
BUILD="$ROOT/build"
OBJ="$BUILD/obj"
DEPS="$ROOT/build/_deps"
SLANG_DIR="$DEPS/slang-src"

# --- Example mode (positional arg): build src/backend/conformance/<example>
# --- with core + backend only, instead of the full renderer ------------------
EXAMPLES="$ROOT/src/backend/conformance"
if [ -n "$example" ]; then
    EXAMPLE_SRC="$EXAMPLES/$example/$example.cpp"
    if [ ! -f "$EXAMPLE_SRC" ]; then
        echo "[error: no such example: $example (expected $EXAMPLE_SRC)]" >&2
        exit 1
    fi
    OBJ="$ROOT/build/obj-ex-$example"
fi

# --- Vulkan SDK ----------------------------------------------------------
VULKAN_CFLAGS=""
VULKAN_LDFLAGS="-lvulkan"
if command -v pkg-config >/dev/null 2>&1; then
    if pkg-config --exists vulkan; then
        VULKAN_CFLAGS="$(pkg-config --cflags vulkan)"
        VULKAN_LDFLAGS="$(pkg-config --libs vulkan)"
        echo "[vulkan] using pkg-config"
    fi
fi
if [ -n "$VULKAN_SDK" ]; then
    echo "[vulkan] VULKAN_SDK detected, overriding system paths"
    VULKAN_CFLAGS="-I$VULKAN_SDK/include"
    VULKAN_LDFLAGS="-L$VULKAN_SDK/lib -lvulkan"
fi

# --- Download Slang (binary SDK, shared across targets) ----------------------
if [ ! -f "$SLANG_DIR/include/slang.h" ]; then
    echo "[downloading slang]"
    mkdir -p "$SLANG_DIR"
    SLANG_URL="https://github.com/shader-slang/slang/releases/download/v2026.17.1/slang-2026.17.1-linux-x86_64.tar.gz"
    curl -sL "$SLANG_URL" -o "$DEPS/slang.tar.gz"
    tar -xzf "$DEPS/slang.tar.gz" -C "$SLANG_DIR" --strip-components=1
    rm "$DEPS/slang.tar.gz"
else
    echo "[slang already downloaded]"
fi
SLANG_INCLUDE="-I$SLANG_DIR/include"
SLANG_LIB="$SLANG_DIR/lib/libslang.so"

# --- Clean -------------------------------------------------------------------
if [ "$clean_build" = "1" ]; then
    if [ -n "$example" ]; then
        echo "[cleaning example build: $example]"
        rm -rf "$OBJ"
    else
        echo "[cleaning build]"
        rm -rf "$BUILD"
    fi
fi
mkdir -p "$OBJ" "$DEPS"

# --- glfw (static, shared across targets) ------------------------------------
if [ ! -f "$DEPS/libglfw3.a" ]; then
    echo "[building glfw]"
    mkdir -p "$DEPS/glfw"
    cmake -G Ninja -S "$ROOT/third-party/glfw" -B "$DEPS/glfw" \
        -DGLFW_BUILD_DOCS=OFF -DGLFW_BUILD_TESTS=OFF -DGLFW_BUILD_EXAMPLES=OFF \
        -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=Release >/dev/null 2>&1 || exit 1
    cmake --build "$DEPS/glfw" >/dev/null 2>&1 || exit 1
    cp "$DEPS/glfw/src/libglfw3.a" "$DEPS/libglfw3.a"
else
    echo "[glfw already built]"
fi

# --- KTX-Software (examples don't link it: skip) -----------------------------
if [ -z "$example" ]; then
if [ ! -f "$BUILD/libktx.a" ]; then
    echo "[building ktx]"
    mkdir -p "$DEPS/ktx"
    cmake -G Ninja -S "$ROOT/third-party/KTX-Software" -B "$DEPS/ktx" \
        -DKTX_FEATURE_TESTS=OFF -DKTX_FEATURE_TOOLS=OFF -DKTX_FEATURE_DOC=OFF \
        -DKTX_FEATURE_GL_UPLOAD=OFF -DKTX_FEATURE_VK_UPLOAD=OFF \
        -DKTX_FEATURE_LOADTEST_APPS=OFF -DCMAKE_BUILD_TYPE=RelWithDebInfo >/dev/null 2>&1 || exit 1
    cmake --build "$DEPS/ktx" >/dev/null 2>&1 || exit 1
    cp "$DEPS/ktx/lib/libktx.a"      "$BUILD/libktx.a"
    cp "$DEPS/ktx/lib/libktx_read.a" "$BUILD/libktx_read.a"
else
    echo "[ktx already built]"
fi
fi

# --- Compile flags -------------------------------------------------------
#CXX="clang++"
CXX="g++"
CXX_COMMON="-std=c++20 -fno-rtti -D_USE_MATH_DEFINES -DVK_NO_PROTOTYPES -DRHI_BACKEND_VULKAN -DENABLE_EDITOR -DFMT_USE_CONSTEXPR=0 -DFMT_ENFORCE_COMPILE_STRING=0"
CXX_INCLUDES="-I$ROOT/src -I$ROOT/third-party -I$ROOT/third-party/glfw/include -I$ROOT/third-party/VMA/include -I$ROOT/third-party/plog/include -I$ROOT/third-party/imgui -I$ROOT/third-party/imgui/backends -I$ROOT/third-party/rtm/includes -I$ROOT/third-party/KTX-Software/include $SLANG_INCLUDE $VULKAN_CFLAGS"
if [ "$build_type" = "debug" ]; then
    CXX_FLAGS="-g -O0 -D_DEBUG -DIMGUI_IMPL_VULKAN_USE_VOLK $CXX_COMMON $CXX_INCLUDES"
else
    CXX_FLAGS="-g -O2 -DNDEBUG -DIMGUI_IMPL_VULKAN_USE_VOLK $CXX_COMMON $CXX_INCLUDES"
fi

LD_FLAGS="$VULKAN_LDFLAGS -lX11 -lXrandr -lXinerama -lXcursor -lXi -lpthread -ldl"

# --- Source files (matches CMakeLists.txt; VOLK_IMPLEMENTATION lives in
# --- renderer.cpp / the example .cpp, so third-party/volk.c is intentionally
# --- NOT compiled) -----------------------------------------------------------
SRC="$ROOT/src"
TP="$ROOT/third-party"

CORE_SRC="\
    $SRC/core/arena.cpp                  \
    $SRC/core/platform.cpp               \
    $SRC/core/math_rtm.cpp               \
    $SRC/core/logger.cpp"

BACKEND_SRC="\
    $SRC/backend/vulkan/context.cpp      \
    $SRC/backend/vulkan/swapchain.cpp    \
    $SRC/backend/vulkan/pipeline.cpp     \
    $SRC/backend/vulkan/descriptors.cpp  \
    $SRC/backend/vulkan/debug.cpp        \
    $SRC/backend/vulkan/query_pool.cpp   \
    $SRC/backend/vulkan/cmd_pool.cpp     \
    $SRC/backend/vulkan/cmd_buffer.cpp   \
    $SRC/backend/vulkan/allocator.cpp    \
    $SRC/backend/vulkan/queue.cpp        \
    $SRC/backend/vulkan/buffer.cpp       \
    $SRC/backend/vulkan/image.cpp        \
    $SRC/backend/vulkan/sampler.cpp      \
    $SRC/backend/vulkan/shader.cpp       \
    $SRC/backend/vulkan/accel_struct.cpp \
    $SRC/backend/vulkan/vk_conversion.cpp \
    $SRC/backend/vulkan/rhi_helpers.cpp"

RENDERER_SRC="\
    $SRC/renderer.cpp                              \
    $SRC/quick_submit.cpp                          \
    $SRC/pipelines.cpp                             \
    $SRC/passes/fg.cpp                             \
    $SRC/asset/asset.cpp                           \
    $SRC/asset/texture.cpp                         \
    $SRC/asset/gltf.cpp                            \
    $TP/mikktspace.c                               \
    $SRC/scene/scene.cpp                           \
    $SRC/scene/ibl.cpp                             \
    $SRC/passes/ssr/ssr.cpp                        \
    $SRC/passes/depth_pre/depth_normal.cpp         \
    $SRC/passes/dispatch_mdi/build_indirect.cpp    \
    $SRC/passes/forward/forward.cpp                \
    $SRC/passes/fwd_cpu/fwd_cpu.cpp                \
    $SRC/passes/shadow/shadow.cpp                  \
    $SRC/passes/grid/grid.cpp                      \
    $SRC/passes/id_blit/id_blit.cpp                \
    $SRC/passes/fullscreen/fullscreen.cpp          \
    $SRC/passes/cluster/cluster_bounds.cpp         \
    $SRC/passes/cluster/light_cull.cpp             \
    $SRC/passes/hiz/hiz.cpp                        \
    $SRC/passes/imgui/imgui.cpp                    \
    $SRC/passes/skybox/skybox.cpp                  \
    $SRC/passes/rt_build.cpp                       \
    $SRC/passes/ddgi/ddgi_trace.cpp                \
    $SRC/passes/ddgi/ddgi_update.cpp               \
    $SRC/passes/ddgi/ddgi_classify.cpp             \
    $SRC/passes/ddgi/ddgi_relocate.cpp             \
    $SRC/passes/ddgi/ddgi_probes_dbg.cpp           \
    $SRC/passes/debug/debug_lines.cpp              \
    $SRC/editor/editor.cpp                         \
    $SRC/editor/debug_draw.cpp                     \
    $SRC/editor/frame.cpp                          \
    $SRC/editor/gizmo.cpp                          \
    $SRC/editor/style.cpp                          \
    $SRC/editor/viewport.cpp                       \
    $SRC/editor/log_viewer.cpp                     \
    $SRC/editor/texture_viewer.cpp                 \
    $SRC/editor/targets.cpp                        \
    $SRC/editor/timings.cpp                        \
    $SRC/editor/hierarchy.cpp                      \
    $SRC/editor/inspector.cpp                      \
    $SRC/backend/imgui_backend.cpp                 \
    $TP/imgui/imgui.cpp                            \
    $TP/imgui/imgui_draw.cpp                       \
    $TP/imgui/imgui_tables.cpp                     \
    $TP/imgui/imgui_widgets.cpp                    \
    $TP/imgui/imgui_demo.cpp                       \
    $TP/imgui/backends/imgui_impl_glfw.cpp"

# --- Compile -------------------------------------------------------------
echo "[compiling]"
if [ -n "$example" ]; then
    for src in $EXAMPLE_SRC $CORE_SRC $BACKEND_SRC; do
        objname=$(basename "$src" | sed 's/\.cpp$/.o/')
        $CXX -c $CXX_FLAGS "$src" -o "$OBJ/$objname"
    done
else
    for src in $CORE_SRC $BACKEND_SRC $RENDERER_SRC; do
        objname=$(basename "$src" | sed 's/\.cpp$/.o/;s/\.c$/.o/')
        $CXX -c $CXX_FLAGS "$src" -o "$OBJ/$objname"
    done
    # imgui.o collision: src/passes/imgui/imgui.cpp and third-party/imgui/imgui.cpp
    # both emit imgui.o in this flat dir: rebuild with distinct names.
    $CXX -c $CXX_FLAGS "$SRC/passes/imgui/imgui.cpp" -o "$OBJ/imgui_pass.o"
    $CXX -c $CXX_FLAGS "$TP/imgui/imgui.cpp" -o "$OBJ/imgui_lib.o"
    rm -f "$OBJ/imgui.o"
    # stale objs from renamed/removed sources (link uses *.o wildcard)
    rm -f "$OBJ/descriptor_pool.o" "$OBJ/descriptor_set.o" "$OBJ/gpu_resource.o" \
        "$OBJ/cmd_buffers.o" "$OBJ/submission_queue.o" "$OBJ/render_target.o" \
        "$OBJ/renderpass_io.o" "$OBJ/imgui_impl_vulkan.o" \
        "$OBJ"/ui_*.o "$OBJ"/pass_*.o
fi

# --- Link -------------------------------------------------------------------
echo "[linking]"
if [ -n "$example" ]; then
    OUT="$BUILD/vk-$example"
    $CXX "$OBJ"/*.o \
        "$DEPS/libglfw3.a" \
        "$SLANG_LIB" \
        $LD_FLAGS \
        -o "$OUT"
else
    OUT="$BUILD/vk-renderer"
    $CXX "$OBJ"/*.o \
        "$BUILD/libglfw3.a" "$BUILD/libktx.a" "$BUILD/libktx_read.a" \
        "$SLANG_LIB" \
        $LD_FLAGS \
        -o "$OUT"
fi

echo "[done: $OUT]"
if [ -n "$example" ]; then
    echo "[run from the repo root: $OUT]"
fi