From c748f6060dbfecb42b8fd085545828c8d4fae69e Mon Sep 17 00:00:00 2001 From: "francis.wang" Date: Wed, 15 Jul 2026 16:25:38 +0800 Subject: [PATCH] Update README and add setup scripts --- Dockerfile | 72 ++++++++++ README.md | 68 +++++++++- setup-env-macos.sh | 317 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 455 insertions(+), 2 deletions(-) create mode 100644 Dockerfile create mode 100755 setup-env-macos.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..5a5ec041 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,72 @@ +# Dockerfile for OpenWrt-Yocto Build Environment +# +# Yocto Project does NOT natively support macOS. +# This Dockerfile provides an Ubuntu-based container with all +# required build dependencies for Yocto/OpenEmbedded builds. +# +# Based on Yocto Project Scarthgap (5.0) system requirements: +# https://docs.yoctoproject.org/ref-manual/system-requirements.html + +FROM ubuntu:24.04 + +# Prevent interactive prompts during package installation +ENV DEBIAN_FRONTEND=noninteractive + +# Install all required Yocto build host packages (from poky/documentation/poky.yaml.in) +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + chrpath \ + cpio \ + debianutils \ + diffstat \ + file \ + gawk \ + gcc \ + git \ + iputils-ping \ + libacl1 \ + liblz4-tool \ + locales \ + python3 \ + python3-git \ + python3-jinja2 \ + python3-pexpect \ + python3-pip \ + python3-subunit \ + socat \ + texinfo \ + unzip \ + wget \ + xz-utils \ + zstd \ + # Additional useful tools + sudo \ + vim \ + nano \ + less \ + bash-completion \ + && rm -rf /var/lib/apt/lists/* + +# Set up locale (required by Yocto) +RUN locale-gen en_US.UTF-8 && update-locale LANG=en_US.UTF-8 +ENV LANG=en_US.UTF-8 +ENV LC_ALL=en_US.UTF-8 + +# Create a non-root user to match macOS host user (builds should not run as root) +ARG USER_UID=1000 +ARG USER_GID=1000 +RUN groupadd -g ${USER_GID} builduser && \ + useradd -m -u ${USER_UID} -g builduser -s /bin/bash builduser && \ + echo "builduser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +# Create working directory +RUN mkdir -p /workspace && chown builduser:builduser /workspace + +# Switch to non-root user +USER builduser +WORKDIR /workspace + +# Set Git safe directory (since the mounted volume may have different ownership) +RUN git config --global --add safe.directory /workspace + +ENTRYPOINT ["/bin/bash"] diff --git a/README.md b/README.md index 9e13a470..b98e0e94 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,9 @@ ``` 03-openwrt-yocto/ -├── setup-env.sh # 一键初始化脚本 +├── setup-env.sh # Linux 环境初始化脚本 +├── setup-env-macos.sh # macOS Docker 编译环境脚本 +├── Dockerfile # Yocto 编译容器镜像定义 ├── poky/ # Yocto 核心框架 (BitBake + OE-Core) │ ├── bitbake/ # BitBake 构建引擎 │ ├── meta/ # OpenEmbedded-Core 基础层 @@ -48,7 +50,7 @@ source ./setup-env.sh > 所有操作均为幂等:重复执行不会产生重复配置。 -### 2. 构建镜像 +### 2. 构建镜像 (Linux) ```bash # 最小化 CLI 系统(无 Web 界面) @@ -144,3 +146,65 @@ packagegroup-openwrt-full (继承 base) - Yocto 版本: Scarthgap (5.0) / Nanbield (4.3) - 已验证目标: qemux86-64 - Linux 内核: 6.6 (yocto-standard) +- **macOS**: 通过 Docker 容器支持(详见下方 macOS 编译章节) + +## macOS 编译 (Docker) + +> **Yocto Project 不支持在 macOS 上原生编译。** 官方推荐的跨平台方案是通过 Docker 容器运行 Linux 编译环境。 + +#### 前置条件 + +1. 安装 [Docker Desktop for Mac](https://docs.docker.com/desktop/setup/mac/) + + ```bash + brew install --cask docker + ``` + +2. 启动 Docker Desktop 并确保 Docker 守护进程在运行。 + +3. 确保至少有 **50GB** 可用磁盘空间。 + +#### 初始化 macOS 编译环境 + +```bash +cd ~/03-openwrt-yocto + +# 首次运行:构建 Docker 镜像(约需数分钟) +./setup-env-macos.sh + +# 进入编译容器 +./setup-env-macos.sh shell +``` + +进入容器后,在容器内初始化 Yocto 环境并编译: + +```bash +# 在 Docker 容器内执行: +source ./setup-env.sh # 初始化 BitBake 环境 +bitbake openwrt-image-base # 编译镜像 +``` + +#### 一键编译 + +也可以直接从 macOS 宿主机发起编译: + +```bash +./setup-env-macos.sh build openwrt-image-base +``` + +#### 可用命令 + +| 命令 | 说明 | +|------|------| +| `./setup-env-macos.sh` | 构建 Docker 镜像(首次必需) | +| `./setup-env-macos.sh shell` | 进入交互式编译容器 | +| `./setup-env-macos.sh build ` | 在容器中执行 bitbake 编译 | +| `./setup-env-macos.sh clean` | 清理 Docker 镜像和容器 | +| `./setup-env-macos.sh help` | 查看帮助 | + +#### 技术说明 + +- Docker 镜像基于 **Ubuntu 24.04**(Yocto Scarthgap 官方支持的发行版) +- 编译产物位于宿主机的 `build-x86-openwrt/tmp/deploy/images/` 目录 +- 容器与宿主机共享项目目录,修改即时生效 +- 容器内的用户 UID/GID 与宿主机用户一致,避免文件权限问题 diff --git a/setup-env-macos.sh b/setup-env-macos.sh new file mode 100755 index 00000000..a9ea2932 --- /dev/null +++ b/setup-env-macos.sh @@ -0,0 +1,317 @@ +#!/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 "$@"