#!/bin/bash # # OpenWrt-Yocto macOS Build Environment Setup # # Usage: ./setup-env-macos.sh [command] # # Commands: # setup - Build the Docker image (default) # shell - Enter the interactive build container # build - Run bitbake inside the container (requires target, e.g. ./setup-env-macos.sh build openwrt-image-base) # clean - Remove the Docker image and container # help - Show this help message # # ─── Important Notes ─────────────────────────────────────────────────────── # # 1. Yocto Project does NOT natively support macOS. This script uses # Docker to run an Ubuntu container with all required build dependencies. # # 2. macOS uses a case-INSENSITIVE filesystem by default. Yocto REQUIRES # a case-sensitive filesystem. This script will detect this and warn you. # # 3. You need at least 50GB of free disk space for a full build. # # 4. First-time setup will build a Docker image (~1GB) which may take a few minutes. # # ─── Prerequisites ────────────────────────────────────────────────────────── # # Install Docker Desktop for Mac: https://docs.docker.com/desktop/setup/mac/ # # brew install --cask docker (if using Homebrew) # # After installation, open Docker Desktop and ensure it's running. # set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" IMAGE_NAME="openwrt-yocto-builder" IMAGE_TAG="latest" CONTAINER_NAME="openwrt-yocto-build" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' NC='\033[0m' # No Color print_header() { echo "" echo -e "${CYAN}╔══════════════════════════════════════════════════════════════╗${NC}" echo -e "${CYAN}║ OpenWrt-Yocto macOS Build Environment Setup ║${NC}" echo -e "${CYAN}╚══════════════════════════════════════════════════════════════╝${NC}" echo "" } print_error() { echo -e "${RED}[ERROR]${NC} $1"; } print_warning() { echo -e "${YELLOW}[WARN]${NC} $1"; } print_info() { echo -e "${GREEN}[INFO]${NC} $1"; } print_step() { echo -e "${CYAN}[STEP]${NC} $1"; } # ─── Prerequisite Checks ──────────────────────────────────────────────────── check_prerequisites() { print_step "Checking prerequisites..." # Check Docker if ! command -v docker &>/dev/null; then print_error "Docker is not installed." echo "" echo " Please install Docker Desktop for Mac:" echo " https://docs.docker.com/desktop/setup/mac/" echo "" echo " Or via Homebrew:" echo " brew install --cask docker" echo "" exit 1 fi # Check if Docker daemon is running if ! docker info &>/dev/null; then print_error "Docker daemon is not running." echo " Please start Docker Desktop and try again." exit 1 fi print_info "Docker is installed and running." # Check disk space (at least 50GB recommended) local available_gb available_gb=$(df -g . | awk 'NR==2 {print $4}') if [ "$available_gb" -lt 50 ]; then print_warning "Less than 50GB free disk space detected (${available_gb}GB available)." echo " Yocto builds require significant disk space. You may run out of space." echo " Continue anyway? (y/N)" read -r response if [[ ! "$response" =~ ^[Yy]$ ]]; then exit 1 fi else print_info "Disk space OK: ${available_gb}GB available." fi # Check for case-sensitive filesystem warning # macOS default APFS is case-insensitive, which breaks Yocto builds local fs_type fs_type=$(df -T . | awk 'NR==2 {print $2}') if [[ "$(uname)" == "Darwin" ]]; then print_warning "macOS uses a case-insensitive filesystem by default." echo "" echo " Yocto Project REQUIRES a case-sensitive filesystem." echo " The build will happen inside a Docker container (Linux), so this" echo " is only an issue if you extract source tarballs on macOS directly." echo " Docker volumes handle case sensitivity correctly." echo "" echo " If you encounter 'file not found' errors, ensure all source files" echo " are downloaded/cached inside the Docker container." echo "" fi } # ─── Docker Image Management ───────────────────────────────────────────────── build_image() { print_step "Building Docker image '${IMAGE_NAME}:${IMAGE_TAG}'..." # Pass host user's UID/GID so container user matches docker build \ --build-arg USER_UID="$(id -u)" \ --build-arg USER_GID="$(id -g)" \ -t "${IMAGE_NAME}:${IMAGE_TAG}" \ -f "$SCRIPT_DIR/Dockerfile" \ "$SCRIPT_DIR" print_info "Docker image built successfully." } image_exists() { docker image inspect "${IMAGE_NAME}:${IMAGE_TAG}" &>/dev/null } # ─── Container Management ──────────────────────────────────────────────────── enter_shell() { print_step "Entering build container..." # Ensure image exists if ! image_exists; then print_info "Docker image not found. Building it first..." build_image fi # Check if container already exists and is running if docker ps --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then print_info "Attaching to running container '${CONTAINER_NAME}'..." docker exec -it "${CONTAINER_NAME}" /bin/bash return fi # Check if container exists but stopped if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then print_info "Starting existing container '${CONTAINER_NAME}'..." docker start "${CONTAINER_NAME}" docker exec -it "${CONTAINER_NAME}" /bin/bash return fi # Run a new container print_info "Creating new container '${CONTAINER_NAME}'..." docker run -it --rm \ --name "${CONTAINER_NAME}" \ -v "$SCRIPT_DIR:/workspace" \ -v "${HOME}/.gitconfig:/home/builduser/.gitconfig:ro" \ "${IMAGE_NAME}:${IMAGE_TAG}" \ -c " echo '' echo '╔═══════════════════════════════════════════════════════╗' echo '║ OpenWrt-Yocto Docker Build Environment ║' echo '║ OS: Ubuntu 24.04 ║' echo '║ Project: /workspace ║' echo '╚═══════════════════════════════════════════════════════╝' echo '' echo 'Quick start:' echo ' source ./setup-env.sh # Initialize build environment' echo ' bitbake openwrt-image-base # Build the base image' echo '' exec /bin/bash " } run_bitbake() { local target="$1" if [ -z "$target" ]; then print_error "BitBake target is required." echo " Usage: ./setup-env-macos.sh build " echo " Example: ./setup-env-macos.sh build openwrt-image-base" exit 1 fi print_step "Building target: ${target}" # Ensure image exists if ! image_exists; then print_info "Docker image not found. Building it first..." build_image fi docker run -it --rm \ --name "${CONTAINER_NAME}-builder" \ -v "$SCRIPT_DIR:/workspace" \ "${IMAGE_NAME}:${IMAGE_TAG}" \ -c " source /workspace/setup-env.sh /workspace/build-x86-openwrt bitbake ${target} " } clean() { print_step "Cleaning up Docker resources..." # Stop and remove container if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then print_info "Removing container '${CONTAINER_NAME}'..." docker rm -f "${CONTAINER_NAME}" 2>/dev/null || true fi if docker ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}-builder$"; then print_info "Removing container '${CONTAINER_NAME}-builder'..." docker rm -f "${CONTAINER_NAME}-builder" 2>/dev/null || true fi # Remove image if image_exists; then print_info "Removing image '${IMAGE_NAME}:${IMAGE_TAG}'..." docker rmi "${IMAGE_NAME}:${IMAGE_TAG}" 2>/dev/null || true fi print_info "Cleanup complete." } show_help() { echo "" echo "OpenWrt-Yocto macOS Build Environment Setup" echo "" echo "Usage: ./setup-env-macos.sh [command]" echo "" echo "Commands:" echo " setup Build the Docker image (default action)" echo " shell Enter the interactive build container" echo " build TARGET Run bitbake inside the container" echo " clean Remove Docker image and containers" echo " help Show this help message" echo "" echo "Examples:" echo " ./setup-env-macos.sh # First-time setup" echo " ./setup-env-macos.sh shell # Enter build shell" echo " ./setup-env-macos.sh build openwrt-image-base # Build image" echo " ./setup-env-macos.sh clean # Cleanup" echo "" echo "Quick Start Workflow:" echo " 1. ./setup-env-macos.sh # Build Docker image" echo " 2. ./setup-env-macos.sh shell # Enter container" echo " 3. source ./setup-env.sh # Inside container: init env" echo " 4. bitbake openwrt-image-base # Inside container: build" echo "" } # ─── Main ──────────────────────────────────────────────────────────────────── main() { local cmd="${1:-setup}" case "$cmd" in setup) print_header check_prerequisites build_image echo "" print_info "Setup complete! Next steps:" echo "" echo " 1. Enter the build container:" echo " ./setup-env-macos.sh shell" echo "" echo " 2. Inside the container, initialize the build:" echo " source ./setup-env.sh" echo "" echo " 3. Build an image:" echo " bitbake openwrt-image-base" echo "" ;; shell) print_header check_prerequisites enter_shell ;; build) print_header check_prerequisites run_bitbake "$2" ;; clean) print_header clean ;; help|--help|-h) print_header show_help ;; *) print_error "Unknown command: $cmd" show_help exit 1 ;; esac } main "$@"