summaryrefslogtreecommitdiff
path: root/build.sh
diff options
context:
space:
mode:
Diffstat (limited to 'build.sh')
-rwxr-xr-xbuild.sh427
1 files changed, 350 insertions, 77 deletions
diff --git a/build.sh b/build.sh
index f9a5a9e..339b19a 100755
--- a/build.sh
+++ b/build.sh
@@ -1,101 +1,374 @@
#!/usr/bin/env bash
-# run.sh - simple build+test helper for BoltDBG
+# build.sh - Professional build script for BoltDBG (improved)
+#
# Usage:
-# ./run.sh # default: Debug build, ASAN off, run tests
-# BUILD_TYPE=Release ./run.sh
-# ASAN=ON ./run.sh
-# CLEAN=1 ./run.sh # remove build/ then do everything
-# INSTALL=1 ./run.sh # run `cmake --install` after build
+# ./build.sh # Debug build (preset: debug)
+# ./build.sh --preset release # Release build
+# ./build.sh --preset debug-asan # Debug with ASAN
+# ./build.sh --clean # Clean build
+# ./build.sh --install # Build and install
+# ./build.sh --format # Format code before build
+# ./build.sh --help # Show help
#
+# Environment variables:
+# CMAKE_PRESET - CMake preset to use (default: debug)
+# JOBS - Number of parallel jobs (default: auto -> detected)
+# BUILD_DIR - Build directory (default: build/<preset>)
+# INSTALL_PREFIX - Install prefix (default: /usr/local)
+
set -euo pipefail
-# Defaults (can be overridden by environment variables)
-: "${BUILD_TYPE:=Debug}"
-: "${ASAN:=OFF}" # ON or OFF
-: "${CLEAN:=0}" # 1 to remove build dir first
-: "${JOBS:=auto}" # number of parallel build jobs; auto = detect
-: "${INSTALL:=0}" # 1 to install after build
-: "${CMAKE_EXTRA_ARGS:=""}" # any extra args for cmake
-
-# Detect number of processors
-if [ "$JOBS" = "auto" ]; then
- if command -v nproc >/dev/null 2>&1; then
- JOBS=$(nproc)
- elif [ "$(uname)" = "Darwin" ] && command -v sysctl >/dev/null 2>&1; then
- JOBS=$(sysctl -n hw.ncpu)
- else
+# ============================================================================
+# Configuration
+# ============================================================================
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+ROOT_DIR="${SCRIPT_DIR}"
+
+# Defaults (can be overridden by env)
+: "${CMAKE_PRESET:=debug}"
+: "${JOBS:=auto}"
+: "${INSTALL_PREFIX:=/usr/local}"
+: "${VERBOSE:=0}"
+
+# Flags
+CLEAN_BUILD=1
+RUN_INSTALL=0
+RUN_TESTS=0
+RUN_FORMAT=0
+SHOW_HELP=0
+
+# ============================================================================
+# Colors and Formatting
+# ============================================================================
+
+if [[ -t 1 ]]; then
+ RED='\033[0;31m'
+ GREEN='\033[0;32m'
+ YELLOW='\033[1;33m'
+ BLUE='\033[0;34m'
+ BOLD='\033[1m'
+ NC='\033[0m' # No Color
+else
+ RED=''
+ GREEN=''
+ YELLOW=''
+ BLUE=''
+ BOLD=''
+ NC=''
+fi
+
+# ============================================================================
+# Helper Functions
+# ============================================================================
+
+log_info() { echo -e "${BLUE}[INFO]${NC} $*"; }
+log_success() { echo -e "${GREEN}[SUCCESS]${NC} $*"; }
+log_warning() { echo -e "${YELLOW}[WARNING]${NC} $*"; }
+log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
+log_header() {
+ echo
+ echo -e "${BOLD}========================================${NC}"
+ echo -e "${BOLD}$*${NC}"
+ echo -e "${BOLD}========================================${NC}"
+}
+
+require_cmd() {
+ if ! command -v "$1" >/dev/null 2>&1; then
+ log_error "Required command '$1' not found. Please install it."
+ exit 2
+ fi
+}
+
+detect_jobs() {
+ if [[ "${JOBS}" == "auto" ]]; then
+ if command -v nproc >/dev/null 2>&1; then
+ JOBS="$(nproc)"
+ elif [[ "$(uname)" == "Darwin" ]] && command -v sysctl >/dev/null 2>&1; then
+ JOBS="$(sysctl -n hw.ncpu)"
+ else
+ JOBS=2
+ fi
+ fi
+ # ensure integer
+ if ! [[ "${JOBS}" =~ ^[0-9]+$ ]]; then
JOBS=2
fi
+}
+
+show_help() {
+ cat << EOF
+${BOLD}BoltDBG Build Script${NC}
+
+USAGE:
+ $0 [OPTIONS]
+
+OPTIONS:
+ --preset PRESET CMake preset (debug, release, debug-asan, etc.)
+ --clean Remove build directory before building
+ --install Install after building
+ --no-tests Skip running tests
+ --format Run code formatter before building
+ --jobs N Number of parallel build jobs (default: auto)
+ --prefix PATH Installation prefix (default: /usr/local)
+ --verbose Enable verbose output
+ --help Show this help message
+
+PRESETS:
+ debug Debug build with symbols
+ release Optimized release build
+ debug-asan Debug with Address Sanitizer
+ debug-ubsan Debug with UB Sanitizer
+ debug-tsan Debug with Thread Sanitizer
+ ci CI/CD build configuration
+
+EXAMPLES:
+ $0 # Basic debug build
+ $0 --preset release # Release build
+ $0 --preset debug-asan --clean # Clean ASAN build
+ $0 --install --prefix ~/local # Build and install to ~/local
+ $0 --format --preset release # Format then build release
+
+EOF
+ exit 0
+}
+
+# ============================================================================
+# Argument Parsing
+# ============================================================================
+
+while [[ $# -gt 0 ]]; do
+ case $1 in
+ --preset)
+ CMAKE_PRESET="${2:-}"
+ shift 2
+ ;;
+ --clean)
+ CLEAN_BUILD=1
+ shift
+ ;;
+ --install)
+ RUN_INSTALL=1
+ shift
+ ;;
+ --no-tests)
+ RUN_TESTS=0
+ shift
+ ;;
+ --format)
+ RUN_FORMAT=1
+ shift
+ ;;
+ --jobs)
+ JOBS="${2:-}"
+ shift 2
+ ;;
+ --prefix)
+ INSTALL_PREFIX="${2:-}"
+ shift 2
+ ;;
+ --verbose)
+ VERBOSE=1
+ shift
+ ;;
+ --help|-h)
+ SHOW_HELP=1
+ shift
+ ;;
+ *)
+ log_error "Unknown option: $1"
+ echo "Use --help for usage information"
+ exit 1
+ ;;
+ esac
+done
+
+if [[ $SHOW_HELP -eq 1 ]]; then
+ show_help
fi
-ROOT_DIR="$(cd "$(dirname "$0")" && pwd)"
-BUILD_DIR="${ROOT_DIR}/build"
-
-echo "=== BoltDBG build helper ==="
-echo "Root: ${ROOT_DIR}"
-echo "Build dir: ${BUILD_DIR}"
-echo "Build type: ${BUILD_TYPE}"
-echo "ASAN: ${ASAN}"
-echo "Jobs: ${JOBS}"
-echo "Clean: ${CLEAN}"
-echo "Install: ${INSTALL}"
-echo "Extra args: ${CMAKE_EXTRA_ARGS}"
-echo
+# ============================================================================
+# Prerequisites
+# ============================================================================
+
+require_cmd cmake
+require_cmd git
+
+detect_jobs
+
+BUILD_DIR="${ROOT_DIR}/build/${CMAKE_PRESET}"
+
+# ============================================================================
+# Main Build Process
+# ============================================================================
+
+log_header "BoltDBG Build Configuration"
+log_info "Root directory: ${ROOT_DIR}"
+log_info "Build directory: ${BUILD_DIR}"
+log_info "CMake preset: ${CMAKE_PRESET}"
+log_info "Parallel jobs: ${JOBS}"
+log_info "Install prefix: ${INSTALL_PREFIX}"
+log_info "Clean build: ${CLEAN_BUILD}"
+log_info "Run tests: ${RUN_TESTS}"
+log_info "Run install: ${RUN_INSTALL}"
+
+# Step 1: Code formatting (optional)
+if [[ $RUN_FORMAT -eq 1 ]]; then
+ log_header "Step 1/6: Code Formatting"
+ if [[ -f "${ROOT_DIR}/scripts/format.sh" ]]; then
+ "${ROOT_DIR}/scripts/format.sh"
+ log_success "Code formatted"
+ else
+ log_warning "scripts/format.sh not found, skipping formatting"
+ fi
+else
+ log_info "Skipping code formatting (use --format to enable)"
+fi
-# Step 0: optionally clean
-if [ "${CLEAN}" = "1" ]; then
- echo "[1/6] Cleaning build directory..."
- rm -rf "${BUILD_DIR}"
+# Step 2: Fetch dependencies (optional helper)
+# If you use submodules or have a fetch script, run it here.
+if [[ -f "${ROOT_DIR}/scripts/fetch_deps.sh" ]]; then
+ log_header "Step 2/6: Fetch Dependencies"
+ "${ROOT_DIR}/scripts/fetch_deps.sh" || {
+ log_warning "fetch_deps.sh failed or returned non-zero, continuing anyway"
+ }
+else
+ log_info "No fetch_deps.sh found — relying on CMake FetchContent or vendored deps"
fi
-# Step 1: init/update submodules (if any)
-if [ -f .gitmodules ]; then
- echo "[2/6] Initializing/updating git submodules..."
- git submodule sync --recursive || true
- git submodule update --init --recursive --depth 1 || true
+# Step 3: Clean (optional)
+if [[ $CLEAN_BUILD -eq 1 ]]; then
+ log_header "Step 3/6: Clean Build Directory"
+ if [[ -d "${BUILD_DIR}" ]]; then
+ log_info "Removing ${BUILD_DIR}..."
+ rm -rf "${BUILD_DIR}"
+ log_success "Build directory cleaned"
+ else
+ log_info "Build directory does not exist, nothing to clean"
+ fi
else
- echo "[2/6] No .gitmodules found — skipping submodule init."
+ log_info "Using existing build directory (use --clean for fresh build)"
fi
-# Step 2: create build dir
-echo "[3/6] Preparing build directory..."
+# Step 4: Configure
+log_header "Step 4/6: CMake Configure"
mkdir -p "${BUILD_DIR}"
-cd "${BUILD_DIR}"
-
-# Step 3: run cmake configure
-echo "[4/6] Configuring with CMake..."
-cmake \
- -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
- -DBOLTDBG_ENABLE_ASAN="${ASAN}" \
- ${CMAKE_EXTRA_ARGS} \
- "${ROOT_DIR}"
-
-# Step 4: build
-echo "[5/6] Building (parallel jobs: ${JOBS})..."
-# Use cmake --build for multi-config generators as well
-cmake --build . -- -j"${JOBS}"
-
-# Step 5: run tests (if enabled in CMake)
-if cmake --build . --target help | grep -q "RUN_TESTS" || true; then
- echo "[6/6] Running ctest (if any tests present)..."
- # Prefer ctest binary if available
+
+# If CMakePresets.json exists, prefer using presets. Otherwise fallback to manual args.
+CMAKE_CONF_ARGS=()
+CMAKE_CONF_ARGS+=("-DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX}")
+
+if [[ "${VERBOSE}" -eq 1 ]]; then
+ CMAKE_CONF_ARGS+=("-DCMAKE_VERBOSE_MAKEFILE=ON")
+fi
+
+if [[ -f "${ROOT_DIR}/CMakePresets.json" ]]; then
+ # Use preset; need to call with -S and -B for predictable behavior
+ log_info "Found CMakePresets.json — configuring with preset '${CMAKE_PRESET}'"
+ cmake -S "${ROOT_DIR}" -B "${BUILD_DIR}" --preset "${CMAKE_PRESET}" "${CMAKE_CONF_ARGS[@]}"
+else
+ # Fallback: map simple preset names to CMAKE_BUILD_TYPE and sanitizer flags
+ log_info "No CMakePresets.json — using fallback configure for preset '${CMAKE_PRESET}'"
+ case "${CMAKE_PRESET}" in
+ debug)
+ CMAKE_CONF_ARGS+=("-DCMAKE_BUILD_TYPE=Debug")
+ ;;
+ release)
+ CMAKE_CONF_ARGS+=("-DCMAKE_BUILD_TYPE=Release")
+ ;;
+ debug-asan)
+ CMAKE_CONF_ARGS+=("-DCMAKE_BUILD_TYPE=Debug" "-DBOLTDBG_ENABLE_ASAN=ON")
+ ;;
+ debug-ubsan)
+ CMAKE_CONF_ARGS+=("-DCMAKE_BUILD_TYPE=Debug" "-DBOLTDBG_ENABLE_UBSAN=ON")
+ ;;
+ debug-tsan)
+ CMAKE_CONF_ARGS+=("-DCMAKE_BUILD_TYPE=Debug" "-DBOLTDBG_ENABLE_TSAN=ON")
+ ;;
+ ci)
+ CMAKE_CONF_ARGS+=("-DCMAKE_BUILD_TYPE=RelWithDebInfo")
+ ;;
+ *)
+ # default fallback
+ CMAKE_CONF_ARGS+=("-DCMAKE_BUILD_TYPE=Debug")
+ log_warning "Unknown preset '${CMAKE_PRESET}', falling back to Debug build type"
+ ;;
+ esac
+
+ # Run configure explicitly with -S and -B
+ log_info "Running: cmake -S ${ROOT_DIR} -B ${BUILD_DIR} ${CMAKE_CONF_ARGS[*]}"
+ cmake -S "${ROOT_DIR}" -B "${BUILD_DIR}" "${CMAKE_CONF_ARGS[@]}"
+fi
+
+log_success "Configuration complete"
+
+# Step 5: Build
+log_header "Step 5/6: Build"
+
+# Build args for cmake --build
+CMAKE_BUILD_ARGS=(--build "${BUILD_DIR}" --parallel "${JOBS}")
+if [[ "${VERBOSE}" -eq 1 ]]; then
+ CMAKE_BUILD_ARGS+=(--verbose)
+fi
+
+log_info "Running: cmake ${CMAKE_BUILD_ARGS[*]}"
+cmake "${CMAKE_BUILD_ARGS[@]}"
+log_success "Build complete"
+
+# Step 6: Tests
+if [[ $RUN_TESTS -eq 1 ]]; then
+ log_header "Step 6/6: Run Tests"
if command -v ctest >/dev/null 2>&1; then
- ctest --output-on-failure -j "${JOBS}" || {
- echo "Some tests failed."
- # do not exit immediately so user sees build artifacts; still return non-zero
- exit 1
- }
+ (
+ cd "${BUILD_DIR}"
+ if ! ctest --output-on-failure --parallel "${JOBS}"; then
+ log_error "Some tests failed"
+ exit 1
+ fi
+ )
+ log_success "All tests passed"
else
- echo "ctest not found; skipping tests."
+ log_warning "ctest not found, skipping tests"
fi
else
- echo "[6/6] No tests target detected; skipping ctest."
+ log_info "Skipping tests (use --no-tests to enable)"
+fi
+
+# Optional: Install
+if [[ $RUN_INSTALL -eq 1 ]]; then
+ log_header "Installing"
+ cmake --install "${BUILD_DIR}" --prefix "${INSTALL_PREFIX}"
+ log_success "Installation complete to ${INSTALL_PREFIX}"
+fi
+
+# ============================================================================
+# Summary
+# ============================================================================
+
+log_header "Build Complete"
+
+# Try to guess executable path, but don't assume too much
+POSSIBLE_BIN="${BUILD_DIR}/src/boltdbg"
+if [[ -x "${POSSIBLE_BIN}" ]]; then
+ log_success "Executable: ${POSSIBLE_BIN}"
+else
+ log_info "Executable not found at ${POSSIBLE_BIN}. Check your targets inside ${BUILD_DIR}"
+ log_info "You can inspect build tree or run: cmake --build ${BUILD_DIR} --target <your-target>"
fi
-# Optional install
-if [ "${INSTALL}" = "1" ]; then
- echo "[+] Installing to CMAKE_INSTALL_PREFIX..."
- cmake --install . --prefix "${CMAKE_INSTALL_PREFIX:-/usr/local}"
+if [[ $RUN_INSTALL -eq 1 ]]; then
+ log_success "Installed to: ${INSTALL_PREFIX}/bin/ (if install step created it)"
fi
-echo "=== Build finished successfully ==="
+echo
+log_info "To run the application (if present):"
+echo " ${POSSIBLE_BIN}"
+echo
+log_info "To run tests manually:"
+echo " cd ${BUILD_DIR} && ctest --output-on-failure"
+echo
+log_info "To install manually:"
+echo " cmake --install ${BUILD_DIR} --prefix ${INSTALL_PREFIX}"
+echo
+
+exit 0