From 5712c047aa30cbcc9ce62e36ba744d28bba87204 Mon Sep 17 00:00:00 2001 From: SerinaNya <34389622+SerinaNya@users.noreply.github.com> Date: Wed, 5 Aug 2026 15:48:05 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20build:=20add=20`build.sh`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 + README.md | 29 +++++++++- build.sh | 155 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 build.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..803ca21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.build/ +/dist/ diff --git a/README.md b/README.md index ff49fa1..8fc1477 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Add both feeds to `feeds.conf.default`: ```text src-git packages https://github.com/immortalwrt/packages.git -src-git mihomo +src-git mihomo https://git.laysense.com/SerinaNya/mihomo-openwrt.git ``` Then update and install the required packages: @@ -26,3 +26,30 @@ make package/feeds/mihomo/mihomo/compile V=s The official `packages` feed must remain available because it provides the Go compiler and `golang-package.mk` used by this package. + +## One-click x86/64 APK build + +On a Debian or Ubuntu x86_64 host, run the script as an unprivileged user: + +```sh +bash build.sh +``` + +The script installs the required APT packages with `sudo`, clones ImmortalWrt +`v25.12.1` into `.build/immortalwrt`, configures the generic x86/64 target, and +builds only mihomo. Generated APK files are copied to `./dist/`. + +To skip APT installation on later runs: + +```sh +SKIP_DEPS=1 bash build.sh +``` + +The build directory, job count, and source version can be overridden: + +```sh +WORK_DIR=/path/to/build JOBS=8 IMMORTALWRT_VERSION=v25.12.1 bash build.sh +``` + +The repository and build paths must be on a case-sensitive filesystem and must +not contain spaces or non-ASCII characters. diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..dd293b8 --- /dev/null +++ b/build.sh @@ -0,0 +1,155 @@ +#!/usr/bin/env bash + +set -euo pipefail + +IMMORTALWRT_VERSION="${IMMORTALWRT_VERSION:-v25.12.1}" +IMMORTALWRT_URL="${IMMORTALWRT_URL:-https://github.com/immortalwrt/immortalwrt.git}" +MIHOMO_FEED_URL="${MIHOMO_FEED_URL:-https://git.laysense.com/SerinaNya/mihomo-openwrt.git}" +JOBS="${JOBS:-$(nproc)}" + +ROOT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +WORK_DIR="${WORK_DIR:-${ROOT_DIR}/.build}" +SOURCE_DIR="${WORK_DIR}/immortalwrt" +DIST_DIR="${ROOT_DIR}/dist" + +APT_PACKAGES=( + ack antlr3 asciidoc autoconf automake autopoint binutils bison + build-essential bzip2 ccache clang cmake cpio curl device-tree-compiler + ecj fastjar flex gawk gettext gcc-multilib g++-multilib git gnutls-dev + gperf haveged help2man intltool lib32gcc-s1 libc6-dev-i386 libelf-dev + libglib2.0-dev libgmp3-dev libltdl-dev libmpc-dev libmpfr-dev + libncurses-dev libpython3-dev libreadline-dev libssl-dev libtool + libyaml-dev libz-dev lld llvm lrzsz mkisofs msmtp nano ninja-build + p7zip p7zip-full patch pkgconf python3 python3-pip python3-ply + python3-docutils python3-pyelftools qemu-utils re2c rsync scons + squashfs-tools subversion swig texinfo uglifyjs upx-ucl unzip vim wget + xmlto xxd zlib1g-dev zstd +) + +log() { + printf '\n==> %s\n' "$*" +} + +die() { + printf 'Error: %s\n' "$*" >&2 + exit 1 +} + +check_host() { + [[ "${EUID}" -ne 0 ]] || die "Run this script as an unprivileged user, not root." + [[ "$(uname -m)" == "x86_64" ]] || die "This script supports x86_64 build hosts only." + [[ "${ROOT_DIR}" != *" "* ]] || die "The repository path must not contain spaces." + [[ "${WORK_DIR}" != *" "* ]] || die "WORK_DIR must not contain spaces." + + if LC_ALL=C grep -q '[^ -~]' <<<"${ROOT_DIR}${WORK_DIR}"; then + die "Repository and work paths must contain ASCII characters only." + fi + + mkdir -p "${WORK_DIR}" + local probe + probe="$(mktemp -d "${WORK_DIR}/.case-test.XXXXXX")" + touch "${probe}/lowercase" + if [[ -e "${probe}/LOWERCASE" ]]; then + rm -rf "${probe}" + die "The build filesystem must be case-sensitive." + fi + rm -rf "${probe}" +} + +install_dependencies() { + if [[ "${SKIP_DEPS:-0}" == "1" ]]; then + log "Skipping APT dependency installation" + return + fi + + command -v apt-get >/dev/null 2>&1 || die "apt-get is required for automatic dependency installation." + command -v sudo >/dev/null 2>&1 || die "sudo is required to install APT dependencies." + + log "Installing ImmortalWrt build dependencies" + sudo apt-get update + sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y "${APT_PACKAGES[@]}" +} + +prepare_source() { + if [[ ! -d "${SOURCE_DIR}/.git" ]]; then + log "Cloning ImmortalWrt ${IMMORTALWRT_VERSION}" + git clone -b "${IMMORTALWRT_VERSION}" --single-branch --filter=blob:none \ + "${IMMORTALWRT_URL}" "${SOURCE_DIR}" + else + git -C "${SOURCE_DIR}" diff --quiet || die "ImmortalWrt checkout has modified tracked files." + git -C "${SOURCE_DIR}" diff --cached --quiet || die "ImmortalWrt checkout has staged changes." + + log "Refreshing ImmortalWrt ${IMMORTALWRT_VERSION}" + git -C "${SOURCE_DIR}" fetch --depth=1 origin \ + "refs/tags/${IMMORTALWRT_VERSION}:refs/tags/${IMMORTALWRT_VERSION}" + git -C "${SOURCE_DIR}" checkout --detach "${IMMORTALWRT_VERSION}" + fi +} + +prepare_feeds() { + log "Configuring feeds" + if [[ ! -f "${SOURCE_DIR}/feeds.conf" ]]; then + cp "${SOURCE_DIR}/feeds.conf.default" "${SOURCE_DIR}/feeds.conf" + fi + + sed -i '/^src-git mihomo /d' "${SOURCE_DIR}/feeds.conf" + printf 'src-git mihomo %s\n' "${MIHOMO_FEED_URL}" >>"${SOURCE_DIR}/feeds.conf" + + ( + cd "${SOURCE_DIR}" + ./scripts/feeds update packages mihomo + ./scripts/feeds install -p packages golang + ./scripts/feeds install -f -p mihomo mihomo + ) +} + +configure_target() { + log "Configuring the x86/64 target" + cat >"${SOURCE_DIR}/.config" <<'EOF' +CONFIG_TARGET_x86=y +CONFIG_TARGET_x86_64=y +CONFIG_TARGET_x86_64_DEVICE_generic=y +CONFIG_PACKAGE_mihomo=m +EOF + + make -C "${SOURCE_DIR}" defconfig + grep -q '^CONFIG_TARGET_x86_64=y$' "${SOURCE_DIR}/.config" || die "x86/64 target configuration failed." + grep -q '^CONFIG_PACKAGE_mihomo=m$' "${SOURCE_DIR}/.config" || die "mihomo package selection failed." +} + +build_package() { + log "Building mihomo with ${JOBS} parallel jobs" + make -C "${SOURCE_DIR}" package/feeds/mihomo/mihomo/download -j"${JOBS}" V=s + make -C "${SOURCE_DIR}" package/feeds/mihomo/mihomo/clean + + if [[ -d "${SOURCE_DIR}/bin/packages" ]]; then + find "${SOURCE_DIR}/bin/packages" -type f -name 'mihomo-*.apk' -delete + fi + + make -C "${SOURCE_DIR}" package/feeds/mihomo/mihomo/compile -j"${JOBS}" V=s +} + +collect_artifacts() { + log "Collecting APK artifacts" + mkdir -p "${DIST_DIR}" + find "${DIST_DIR}" -maxdepth 1 -type f -name 'mihomo-*.apk' -delete + + local artifacts=() + while IFS= read -r -d '' artifact; do + artifacts+=("${artifact}") + done < <(find "${SOURCE_DIR}/bin/packages" -type f -name 'mihomo-*.apk' -print0) + + ((${#artifacts[@]} > 0)) || die "Build completed but no mihomo APK was found." + cp -v "${artifacts[@]}" "${DIST_DIR}/" + + log "Build complete" + printf 'APK output directory: %s\n' "${DIST_DIR}" +} + +check_host +install_dependencies +prepare_source +prepare_feeds +configure_target +build_package +collect_artifacts