Files
metabuilder/gameengine/build.sh
2026-03-09 22:30:41 +00:00

298 lines
7.7 KiB
Bash
Executable File

#!/bin/bash
###############################################################################
# GameEngine Build Automation Script
#
# This script automates the complete Conan + CMake + Ninja build pipeline
# for the SDL3/bgfx game engine.
#
# Usage:
# ./build.sh [target] # Build specific target (default: sdl3_app)
# ./build.sh test_bootstrap_orchestration # Build first test
# ./build.sh --clean # Clean and rebuild from scratch
# ./build.sh --list-targets # List all available targets
# ./build.sh --help # Show this help message
###############################################################################
set -e # Exit on first error
# Color codes for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Configuration
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BUILD_DIR="${PROJECT_ROOT}/build/Release"
SOURCE_DIR="${PROJECT_ROOT}"
CMAKE_CONFIG="${PROJECT_ROOT}/cmake_config.json"
CMAKE_TEMPLATE="${PROJECT_ROOT}/CMakeLists.txt.jinja2"
CMAKE_OUTPUT="${PROJECT_ROOT}/CMakeLists.txt"
GENERATE_SCRIPT="${PROJECT_ROOT}/generate_cmake.py"
BUILD_TYPE="Release"
GENERATOR="Ninja"
VERBOSE=0
CLEAN_BUILD=0
# Functions
print_section() {
echo ""
echo -e "${BLUE}===============================================================================${NC}"
echo -e "${BLUE}$1${NC}"
echo -e "${BLUE}===============================================================================${NC}"
}
print_step() {
echo -e "${GREEN}$1${NC}"
}
print_error() {
echo -e "${RED}✗ ERROR: $1${NC}"
}
print_success() {
echo -e "${GREEN}$1${NC}"
}
print_warning() {
echo -e "${YELLOW}⚠ WARNING: $1${NC}"
}
show_help() {
cat "${BASH_SOURCE[0]}" | grep "^#" | tail -n +2 | head -n 20
}
list_targets() {
if [ -f "${CMAKE_OUTPUT}" ]; then
print_section "Available CMake Targets"
# Extract executable and test targets from CMakeLists.txt
grep -E "^add_executable|^add_test" "${CMAKE_OUTPUT}" | sed 's/add_executable(\([^ ]*\).*/ - \1 (executable)/' | sed 's/add_test(\([^ ]*\).*/ - \1 (test)/' | sort | uniq
else
print_error "CMakeLists.txt not found. Please run build step first."
exit 1
fi
}
verify_requirements() {
print_section "Verifying Requirements"
local missing=0
# Check for Conan
if ! command -v conan &> /dev/null; then
print_error "Conan is not installed"
missing=1
else
print_step "Conan: $(conan --version)"
fi
# Check for CMake
if ! command -v cmake &> /dev/null; then
print_error "CMake is not installed"
missing=1
else
print_step "CMake: $(cmake --version | head -1)"
fi
# Check for Ninja
if ! command -v ninja &> /dev/null; then
print_error "Ninja is not installed"
missing=1
else
print_step "Ninja: $(ninja --version)"
fi
# Check for Python 3
if ! command -v python3 &> /dev/null; then
print_error "Python 3 is not installed"
missing=1
else
print_step "Python: $(python3 --version)"
fi
# Check for Jinja2
if ! python3 -c "import jinja2" 2>/dev/null; then
print_error "Python Jinja2 is not installed"
print_step "Install with: pip3 install jinja2"
missing=1
else
print_step "Jinja2: Available"
fi
if [ $missing -eq 1 ]; then
print_error "Some required tools are missing. Please install them and try again."
exit 1
fi
print_success "All requirements verified"
}
install_conan_deps() {
print_section "Installing Conan Dependencies"
if [ ! -f "${PROJECT_ROOT}/conanfile.py" ]; then
print_error "conanfile.py not found at ${PROJECT_ROOT}/conanfile.py"
exit 1
fi
print_step "Running: conan install . --build=missing"
cd "${PROJECT_ROOT}"
if [ $VERBOSE -eq 1 ]; then
conan install . --build=missing -vv
else
conan install . --build=missing
fi
print_success "Conan dependencies installed"
}
generate_cmakelists() {
print_section "Generating CMakeLists.txt"
if [ ! -f "${CMAKE_CONFIG}" ]; then
print_error "cmake_config.json not found at ${CMAKE_CONFIG}"
exit 1
fi
if [ ! -f "${GENERATE_SCRIPT}" ]; then
print_error "generate_cmake.py not found at ${GENERATE_SCRIPT}"
exit 1
fi
print_step "Running: python3 generate_cmake.py --config cmake_config.json --template CMakeLists.txt.jinja2 --output CMakeLists.txt"
cd "${PROJECT_ROOT}"
python3 generate_cmake.py --config cmake_config.json --template CMakeLists.txt.jinja2 --output CMakeLists.txt
if [ ! -f "${CMAKE_OUTPUT}" ]; then
print_error "CMakeLists.txt generation failed"
exit 1
fi
print_success "CMakeLists.txt generated ($(wc -l < "${CMAKE_OUTPUT}") lines)"
}
configure_cmake() {
print_section "Configuring CMake"
# Create build directory
mkdir -p "${BUILD_DIR}"
print_step "Running: cmake -B ${BUILD_DIR} -S ${SOURCE_DIR} ..."
# Construct cmake command
local cmake_cmd=(
cmake
"-B" "${BUILD_DIR}"
"-S" "${SOURCE_DIR}"
"-DCMAKE_BUILD_TYPE=${BUILD_TYPE}"
"-DCMAKE_TOOLCHAIN_FILE=${BUILD_DIR}/generators/conan_toolchain.cmake"
"-G" "${GENERATOR}"
"-DBUILD_SDL3_APP=ON"
"-DSDL_VERSION=SDL3"
)
if [ $VERBOSE -eq 1 ]; then
cmake_cmd+=("--debug-output")
fi
"${cmake_cmd[@]}"
print_success "CMake configuration complete"
}
build_target() {
local target="${1:-sdl3_app}"
print_section "Building Target: $target"
if [ ! -d "${BUILD_DIR}" ]; then
print_error "Build directory not configured. Please run full build first."
exit 1
fi
print_step "Running: cmake --build ${BUILD_DIR} --target $target"
if [ $VERBOSE -eq 1 ]; then
cmake --build "${BUILD_DIR}" --target "$target" --verbose
else
cmake --build "${BUILD_DIR}" --target "$target"
fi
print_success "Build complete for target: $target"
}
clean_build() {
print_section "Cleaning Build Directory"
if [ -d "${BUILD_DIR}" ]; then
print_step "Removing: ${BUILD_DIR}"
rm -rf "${BUILD_DIR}"
print_success "Build directory cleaned"
else
print_warning "Build directory does not exist"
fi
}
full_build() {
local target="${1:-sdl3_app}"
print_section "FULL BUILD PIPELINE"
echo "Target: $target"
echo "Build Type: ${BUILD_TYPE}"
echo "Generator: ${GENERATOR}"
echo "Project Root: ${PROJECT_ROOT}"
verify_requirements
install_conan_deps
generate_cmakelists
configure_cmake
build_target "$target"
print_section "BUILD COMPLETE"
echo -e "${GREEN}Successfully built target: $target${NC}"
# Show binary location if it's sdl3_app
if [ "$target" = "sdl3_app" ]; then
echo -e "${GREEN}Binary location: ${BUILD_DIR}/sdl3_app${NC}"
else
echo -e "${GREEN}Target built: $target${NC}"
fi
}
# Main script logic
main() {
case "${1:-}" in
--help|-h)
show_help
exit 0
;;
--list-targets)
list_targets
exit 0
;;
--clean)
clean_build
CLEAN_BUILD=1
# If no second argument, stop after clean
if [ -z "${2:-}" ]; then
exit 0
fi
# Otherwise, rebuild with second argument as target
full_build "${2:-sdl3_app}"
;;
--verbose|-v)
VERBOSE=1
full_build "${2:-sdl3_app}"
;;
*)
# Default: build specified target or sdl3_app
full_build "${1:-sdl3_app}"
;;
esac
}
# Run main
main "$@"