438 lines
12 KiB
Bash
Executable File
438 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
||
# check-toolchain.sh - Verify clang installation and build requirements
|
||
# Checks for clang, required tools, and platform-specific dependencies
|
||
|
||
set -e
|
||
|
||
# =============================================================================
|
||
# Configuration
|
||
# =============================================================================
|
||
|
||
# Minimum required versions
|
||
MIN_CLANG_VERSION_MAJOR=6
|
||
MIN_CLANG_VERSION_MINOR=0
|
||
|
||
# Required tools
|
||
REQUIRED_TOOLS=(
|
||
"clang++"
|
||
"clang"
|
||
"make"
|
||
"bash"
|
||
)
|
||
|
||
# Platform-specific tools
|
||
REQUIRED_TOOLS_LINUX=(
|
||
"pkg-config"
|
||
)
|
||
|
||
REQUIRED_TOOLS_MACOS=(
|
||
"xcrun"
|
||
)
|
||
|
||
REQUIRED_TOOLS_WIN32=(
|
||
"windres" # For resource compilation
|
||
)
|
||
|
||
# =============================================================================
|
||
# Utility Functions
|
||
# =============================================================================
|
||
|
||
# Colors for output
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
NC='\033[0m' # No Color
|
||
|
||
print_success() {
|
||
echo -e "${GREEN}✓${NC} $1"
|
||
}
|
||
|
||
print_warning() {
|
||
echo -e "${YELLOW}⚠${NC} $1"
|
||
}
|
||
|
||
print_error() {
|
||
echo -e "${RED}✗${NC} $1"
|
||
}
|
||
|
||
print_info() {
|
||
echo -e "ℹ $1"
|
||
}
|
||
|
||
# =============================================================================
|
||
# Version Checking
|
||
# =============================================================================
|
||
|
||
check_clang_version() {
|
||
local clang_version
|
||
local major minor
|
||
|
||
if ! command -v clang++ &> /dev/null; then
|
||
print_error "clang++ not found in PATH"
|
||
return 1
|
||
fi
|
||
|
||
clang_version=$(clang++ --version | head -n1)
|
||
print_info "Found: $clang_version"
|
||
|
||
# Extract version numbers (handles various clang version formats)
|
||
if [[ $clang_version =~ ([0-9]+)\.([0-9]+) ]]; then
|
||
major=${BASH_REMATCH[1]}
|
||
minor=${BASH_REMATCH[2]}
|
||
|
||
if [[ $major -gt $MIN_CLANG_VERSION_MAJOR ]] || \
|
||
[[ $major -eq $MIN_CLANG_VERSION_MAJOR && $minor -ge $MIN_CLANG_VERSION_MINOR ]]; then
|
||
print_success "clang++ version $major.$minor meets minimum requirement ($MIN_CLANG_VERSION_MAJOR.$MIN_CLANG_VERSION_MINOR)"
|
||
return 0
|
||
else
|
||
print_error "clang++ version $major.$minor is below minimum requirement ($MIN_CLANG_VERSION_MAJOR.$MIN_CLANG_VERSION_MINOR)"
|
||
return 1
|
||
fi
|
||
else
|
||
print_warning "Could not parse clang++ version, proceeding anyway"
|
||
return 0
|
||
fi
|
||
}
|
||
|
||
# =============================================================================
|
||
# Tool Checking
|
||
# =============================================================================
|
||
|
||
check_tool() {
|
||
local tool=$1
|
||
local required=${2:-true}
|
||
|
||
if command -v "$tool" &> /dev/null; then
|
||
local version_info
|
||
case "$tool" in
|
||
"clang++"|"clang")
|
||
version_info=$(command "$tool" --version 2>/dev/null | head -n1 || echo "version unknown")
|
||
;;
|
||
"make")
|
||
version_info=$(command "$tool" --version 2>/dev/null | head -n1 || echo "version unknown")
|
||
;;
|
||
"pkg-config")
|
||
version_info=$(command "$tool" --version 2>/dev/null || echo "version unknown")
|
||
;;
|
||
*)
|
||
version_info="available"
|
||
;;
|
||
esac
|
||
print_success "$tool found ($version_info)"
|
||
return 0
|
||
else
|
||
if [[ "$required" == "true" ]]; then
|
||
print_error "$tool not found in PATH"
|
||
return 1
|
||
else
|
||
print_warning "$tool not found (optional)"
|
||
return 0
|
||
fi
|
||
fi
|
||
}
|
||
|
||
check_basic_tools() {
|
||
local all_good=true
|
||
|
||
print_info "Checking basic tools..."
|
||
|
||
for tool in "${REQUIRED_TOOLS[@]}"; do
|
||
if ! check_tool "$tool"; then
|
||
all_good=false
|
||
fi
|
||
done
|
||
|
||
if [[ "$all_good" == "true" ]]; then
|
||
return 0
|
||
else
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
check_platform_tools() {
|
||
local platform=$1
|
||
local all_good=true
|
||
local tools_var
|
||
|
||
case "$platform" in
|
||
"linux")
|
||
tools_var="REQUIRED_TOOLS_LINUX[@]"
|
||
;;
|
||
"macos")
|
||
tools_var="REQUIRED_TOOLS_MACOS[@]"
|
||
;;
|
||
"win32")
|
||
tools_var="REQUIRED_TOOLS_WIN32[@]"
|
||
;;
|
||
*)
|
||
print_warning "Unknown platform '$platform', skipping platform-specific tool checks"
|
||
return 0
|
||
;;
|
||
esac
|
||
|
||
print_info "Checking platform-specific tools for $platform..."
|
||
|
||
# Use indirect reference to get the array
|
||
local tools_array_name="$tools_var"
|
||
if [[ -n "${!tools_array_name:-}" ]]; then
|
||
local tools_array=("${!tools_array_name}")
|
||
for tool in "${tools_array[@]}"; do
|
||
if ! check_tool "$tool"; then
|
||
all_good=false
|
||
fi
|
||
done
|
||
fi
|
||
|
||
if [[ "$all_good" == "true" ]]; then
|
||
return 0
|
||
else
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# =============================================================================
|
||
# Platform-Specific Checks
|
||
# =============================================================================
|
||
|
||
check_macos_requirements() {
|
||
print_info "Checking macOS-specific requirements..."
|
||
|
||
# Check for Xcode command line tools
|
||
if ! xcode-select -p &> /dev/null; then
|
||
print_error "Xcode command line tools not installed"
|
||
print_info "Install with: xcode-select --install"
|
||
return 1
|
||
else
|
||
print_success "Xcode command line tools installed"
|
||
fi
|
||
|
||
# Check for macOS SDK
|
||
local sdk_path
|
||
sdk_path=$(xcrun --show-sdk-path 2>/dev/null || echo "")
|
||
if [[ -n "$sdk_path" && -d "$sdk_path" ]]; then
|
||
print_success "macOS SDK found at $sdk_path"
|
||
else
|
||
print_warning "macOS SDK not found or not accessible"
|
||
fi
|
||
|
||
# Check for required frameworks (just check if headers exist)
|
||
local frameworks=("Cocoa" "OpenGL" "Metal")
|
||
for framework in "${frameworks[@]}"; do
|
||
if [[ -d "$sdk_path/System/Library/Frameworks/$framework.framework" ]]; then
|
||
print_success "$framework framework available"
|
||
else
|
||
print_warning "$framework framework not found"
|
||
fi
|
||
done
|
||
|
||
return 0
|
||
}
|
||
|
||
check_linux_requirements() {
|
||
print_info "Checking Linux-specific requirements..."
|
||
|
||
# Check for development packages
|
||
local packages=("libx11-dev" "libgl1-mesa-dev" "libfreetype6-dev" "libfontconfig1-dev")
|
||
local missing_packages=()
|
||
|
||
for package in "${packages[@]}"; do
|
||
if dpkg -l | grep -q "$package" 2>/dev/null; then
|
||
print_success "$package installed"
|
||
elif rpm -q "$package" &>/dev/null; then
|
||
print_success "$package installed"
|
||
else
|
||
print_warning "$package not found (may be required)"
|
||
missing_packages+=("$package")
|
||
fi
|
||
done
|
||
|
||
if [[ ${#missing_packages[@]} -gt 0 ]]; then
|
||
print_info "Missing packages (Ubuntu/Debian): ${missing_packages[*]}"
|
||
print_info "Install with: sudo apt-get install ${missing_packages[*]}"
|
||
fi
|
||
|
||
return 0
|
||
}
|
||
|
||
check_win32_requirements() {
|
||
print_info "Checking Windows-specific requirements..."
|
||
|
||
# Check for Windows SDK (approximate check)
|
||
if [[ -n "${WINDOWSSDKDIR:-}" ]]; then
|
||
print_success "Windows SDK environment detected"
|
||
else
|
||
print_warning "Windows SDK environment not detected"
|
||
print_info "Make sure Visual Studio or Windows SDK is installed"
|
||
fi
|
||
|
||
return 0
|
||
}
|
||
|
||
# =============================================================================
|
||
# Library Checks
|
||
# =============================================================================
|
||
|
||
check_freetype_library() {
|
||
local platform=$1
|
||
local arch=$2
|
||
|
||
print_info "Checking FreeType library availability..."
|
||
|
||
case "$platform" in
|
||
"macos")
|
||
local freetype_lib="non-source/foreign/x64/libfreetype-mac.a"
|
||
if [[ -f "$freetype_lib" ]]; then
|
||
print_success "FreeType library found: $freetype_lib"
|
||
else
|
||
print_error "FreeType library not found: $freetype_lib"
|
||
return 1
|
||
fi
|
||
;;
|
||
"linux")
|
||
if pkg-config --exists freetype2; then
|
||
local freetype_version
|
||
freetype_version=$(pkg-config --modversion freetype2)
|
||
print_success "FreeType2 found via pkg-config (version $freetype_version)"
|
||
else
|
||
print_warning "FreeType2 not found via pkg-config"
|
||
fi
|
||
;;
|
||
"win32")
|
||
local freetype_lib="non-source/foreign/x64/freetype.lib"
|
||
if [[ -f "$freetype_lib" ]]; then
|
||
print_success "FreeType library found: $freetype_lib"
|
||
else
|
||
print_error "FreeType library not found: $freetype_lib"
|
||
return 1
|
||
fi
|
||
;;
|
||
esac
|
||
|
||
return 0
|
||
}
|
||
|
||
# =============================================================================
|
||
# Main Checking Function
|
||
# =============================================================================
|
||
|
||
check_build_environment() {
|
||
local platform
|
||
local arch
|
||
local all_good=true
|
||
|
||
echo "=== 4coder Build Environment Check ==="
|
||
echo
|
||
|
||
# Detect platform
|
||
if command -v "$(dirname "$0")/detect-platform.sh" &> /dev/null; then
|
||
platform=$($(dirname "$0")/detect-platform.sh detect)
|
||
arch=$($(dirname "$0")/detect-platform.sh arch)
|
||
print_info "Detected platform: $platform"
|
||
print_info "Detected architecture: $arch"
|
||
else
|
||
print_warning "Platform detection script not found, assuming current platform"
|
||
platform="unknown"
|
||
arch="unknown"
|
||
fi
|
||
|
||
echo
|
||
|
||
# Check clang version
|
||
if ! check_clang_version; then
|
||
all_good=false
|
||
fi
|
||
|
||
echo
|
||
|
||
# Check basic tools
|
||
if ! check_basic_tools; then
|
||
all_good=false
|
||
fi
|
||
|
||
echo
|
||
|
||
# Check platform-specific tools
|
||
if ! check_platform_tools "$platform"; then
|
||
all_good=false
|
||
fi
|
||
|
||
echo
|
||
|
||
# Check platform-specific requirements
|
||
case "$platform" in
|
||
"macos")
|
||
if ! check_macos_requirements; then
|
||
all_good=false
|
||
fi
|
||
;;
|
||
"linux")
|
||
if ! check_linux_requirements; then
|
||
all_good=false
|
||
fi
|
||
;;
|
||
"win32")
|
||
if ! check_win32_requirements; then
|
||
all_good=false
|
||
fi
|
||
;;
|
||
esac
|
||
|
||
echo
|
||
|
||
# Check libraries
|
||
if ! check_freetype_library "$platform" "$arch"; then
|
||
all_good=false
|
||
fi
|
||
|
||
echo
|
||
|
||
# Final result
|
||
if [[ "$all_good" == "true" ]]; then
|
||
print_success "Build environment check passed!"
|
||
print_info "System is ready for 4coder compilation"
|
||
return 0
|
||
else
|
||
print_error "Build environment check failed"
|
||
print_info "Some requirements are missing. Please install missing components and try again."
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# =============================================================================
|
||
# Main execution
|
||
# =============================================================================
|
||
|
||
main() {
|
||
local command="${1:-check}"
|
||
|
||
case "$command" in
|
||
"check")
|
||
check_build_environment
|
||
;;
|
||
"clang")
|
||
check_clang_version
|
||
;;
|
||
"tools")
|
||
check_basic_tools
|
||
;;
|
||
"help"|"-h"|"--help")
|
||
echo "Usage: $0 [check|clang|tools|help]"
|
||
echo ""
|
||
echo "Commands:"
|
||
echo " check - Run full build environment check (default)"
|
||
echo " clang - Check clang version only"
|
||
echo " tools - Check basic tools only"
|
||
echo " help - Show this help message"
|
||
;;
|
||
*)
|
||
echo "Error: Unknown command '$command'" >&2
|
||
echo "Run '$0 help' for usage information" >&2
|
||
return 1
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# Only run main if script is executed directly (not sourced)
|
||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||
main "$@"
|
||
fi |