#!/usr/bin/env bash # ============================================================================ # build.sh - Build script (Linux) # Usage: ./build.sh [Release|Debug] [clean] # # Compiler preference: gcc > clang # Build system: Ninja (fallback to Make) # ============================================================================ set -euo pipefail PROJECT_NAME="filehasher" # --------------------------------------------------------------------------- # Colors # --------------------------------------------------------------------------- readonly RED='\033[0;31m' readonly GREEN='\033[0;32m' readonly YELLOW='\033[1;33m' readonly CYAN='\033[0;36m' readonly NC='\033[0m' # --------------------------------------------------------------------------- # Default values # --------------------------------------------------------------------------- BUILD_TYPE="Release" CLEAN_BUILD=0 # --------------------------------------------------------------------------- # Parse arguments # --------------------------------------------------------------------------- while [[ $# -gt 0 ]]; do case "$1" in Release|release) BUILD_TYPE="Release" shift ;; Debug|debug) BUILD_TYPE="Debug" shift ;; clean|-clean|--clean) CLEAN_BUILD=1 shift ;; *) echo -e "${RED}Unknown argument: $1${NC}" echo "Usage: $0 [Release|Debug] [clean]" exit 1 ;; esac done # --------------------------------------------------------------------------- # Setup # --------------------------------------------------------------------------- readonly BUILD_DIR="build/linux/${BUILD_TYPE}" readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" echo -e "${GREEN}=== Building ${PROJECT_NAME} (${BUILD_TYPE}) ===${NC}" echo "Project: ${SCRIPT_DIR}" # --------------------------------------------------------------------------- # Clean if requested # --------------------------------------------------------------------------- if [[ $CLEAN_BUILD -eq 1 ]]; then echo -e "${YELLOW}Cleaning build directory...${NC}" rm -rf "${BUILD_DIR}" echo fi # --------------------------------------------------------------------------- # Create build directory # --------------------------------------------------------------------------- mkdir -p "${BUILD_DIR}" cd "${BUILD_DIR}" # --------------------------------------------------------------------------- # Compiler selection (prefer gcc, fallback to clang) # --------------------------------------------------------------------------- echo -e "${YELLOW}Detecting compiler...${NC}" CC_BINARY="" CC_NAME="" if command -v gcc &> /dev/null; then CC_BINARY="gcc" CC_VERSION=$(gcc --version | head -n1) CC_NAME="GCC (${CC_VERSION})" echo -e " ${GREEN}[OK]${NC} Found GCC (preferred): ${CC_VERSION}" elif command -v clang &> /dev/null; then CC_BINARY="clang" CC_VERSION=$(clang --version | head -n1) CC_NAME="Clang (${CC_VERSION})" echo -e " ${YELLOW}[OK]${NC} Found Clang (fallback): ${CC_VERSION}" else echo -e "${RED}[FAIL] No suitable compiler found!${NC}" echo "Please install gcc or clang:" echo " Ubuntu/Debian: sudo apt install build-essential" echo " Fedora/RHEL: sudo dnf install gcc" echo " Arch: sudo pacman -S gcc" exit 1 fi # --------------------------------------------------------------------------- # Check dependencies # --------------------------------------------------------------------------- echo -e "${YELLOW}Checking dependencies...${NC}" # Check for liburing HAVE_LIBURING=0 if ldconfig -p | grep -q liburing 2>/dev/null; then HAVE_LIBURING=1 echo -e " ${GREEN}[OK]${NC} Found liburing" elif pkg-config --exists liburing 2>/dev/null; then HAVE_LIBURING=1 echo -e " ${GREEN}[OK]${NC} Found liburing (pkg-config)" elif [[ -f /usr/lib/liburing.so ]] || [[ -f /usr/lib64/liburing.so ]] || [[ -f /usr/local/lib/liburing.so ]]; then HAVE_LIBURING=1 echo -e " ${GREEN}[OK]${NC} Found liburing (manual detection)" else echo -e "${RED}[FAIL] liburing not found!${NC}" echo "Please install liburing-dev:" echo " Ubuntu/Debian: sudo apt install liburing-dev" echo " Fedora/RHEL: sudo dnf install liburing-devel" echo " Arch: sudo pacman -S liburing" exit 1 fi # Check for pthreads # Check if pthreads is available (either in ldconfig or merged into libc) if ldconfig -p | grep -q libpthread 2>/dev/null || ldd --version | grep -qP '2\.(3[4-9]|[4-9][0-9])'; then echo -e " ${GREEN}[OK]${NC} Found pthreads (merged or standalone)" else echo -e " ${YELLOW}[NOTE]${NC} pthreads not found, attempting link" fi echo # --------------------------------------------------------------------------- # Generator selection (prefer ninja) # --------------------------------------------------------------------------- echo -e "${YELLOW}Selecting build system...${NC}" GENERATOR="" GENERATOR_NAME="" if command -v ninja &> /dev/null; then GENERATOR="Ninja" GENERATOR_NAME="Ninja" echo -e " ${GREEN}[OK]${NC} Using Ninja" elif command -v make &> /dev/null; then GENERATOR="Unix Makefiles" GENERATOR_NAME="Make" echo -e " ${YELLOW}[OK]${NC} Ninja not found, using Make" else echo -e "${RED}[FAIL] No build system found!${NC}" echo "Please install ninja or make:" echo " Ubuntu/Debian: sudo apt install ninja-build" echo " Fedora/RHEL: sudo dnf install ninja-build" echo " Arch: sudo pacman -S ninja" exit 1 fi echo # --------------------------------------------------------------------------- # Configure # --------------------------------------------------------------------------- echo -e "${YELLOW}Configuring CMake...${NC}" # -------------------------------------------------------------------------- # compile_commands.json logic # -------------------------------------------------------------------------- EXPORT_COMPILE_COMMANDS=OFF if [[ "$BUILD_TYPE" == "Release" ]]; then if [[ -f "${SCRIPT_DIR}/compile_commands.json" ]]; then echo -e " compile_commands.json already exists - skipping generation" else echo -e " compile_commands.json will be generated" EXPORT_COMPILE_COMMANDS=ON fi fi echo -e " Build type: ${BUILD_TYPE}" echo -e " Compiler: ${CC_NAME}" echo -e " Generator: ${GENERATOR_NAME}" cmake "${SCRIPT_DIR}" \ -G "${GENERATOR}" \ -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \ -DCMAKE_C_COMPILER="${CC_BINARY}" \ -DCMAKE_EXPORT_COMPILE_COMMANDS=${EXPORT_COMPILE_COMMANDS} if [[ $? -ne 0 ]]; then echo -e "${RED}CMake configuration failed!${NC}" exit 1 fi echo -e "${GREEN}Configuration successful!${NC}" echo # --------------------------------------------------------------------------- # Build # --------------------------------------------------------------------------- echo -e "${YELLOW}Building...${NC}" # Get number of CPU cores if command -v nproc &> /dev/null; then CORES=$(nproc) else CORES=4 fi cmake --build . --config "${BUILD_TYPE}" --parallel "${CORES}" if [[ $? -ne 0 ]]; then echo -e "${RED}Build failed!${NC}" exit 1 fi echo -e "${GREEN}Build successful!${NC}" echo # --------------------------------------------------------------------------- # Verify output # --------------------------------------------------------------------------- cd "${SCRIPT_DIR}" if [[ -f "${BUILD_DIR}/${PROJECT_NAME}" ]]; then echo -e "${GREEN}Executable: ${BUILD_DIR}/${PROJECT_NAME}${NC}" if command -v file &> /dev/null; then echo -e " Type: $(file -b ${BUILD_DIR}/${PROJECT_NAME})" fi if command -v du &> /dev/null; then echo -e " Size: $(du -h ${BUILD_DIR}/${PROJECT_NAME} | cut -f1)" fi elif [[ -f "${BUILD_DIR}/${PROJECT_NAME}.exe" ]]; then echo -e "${GREEN}Executable: ${BUILD_DIR}/${PROJECT_NAME}.exe${NC}" else echo -e "${YELLOW}Note: Could not locate executable${NC}" echo "Checking build directory:" find "${BUILD_DIR}" -type f -executable 2>/dev/null || echo " No executables found" fi # --------------------------------------------------------------------------- # Summary # --------------------------------------------------------------------------- echo echo -e "${CYAN}=== Build Complete ===${NC}" echo echo -e "${YELLOW}Build Information:${NC}" echo -e " Configuration: ${BUILD_TYPE}" echo -e " Compiler: ${CC_NAME}" echo -e " Generator: ${GENERATOR_NAME}" echo -e " Output: ${BUILD_DIR}/" # --------------------------------------------------------------------------- # Copy compile_commands.json for clangd # --------------------------------------------------------------------------- if [[ "${EXPORT_COMPILE_COMMANDS}" == "ON" ]]; then if [[ -f "${BUILD_DIR}/compile_commands.json" ]]; then echo -e " clangd: compile_commands.json generated" cp "${BUILD_DIR}/compile_commands.json" "${SCRIPT_DIR}/compile_commands.json" echo -e " clangd: Copied to project root" fi fi echo echo -e "${GREEN}Ready to run: ./${BUILD_DIR}/${PROJECT_NAME}${NC}"