#!/bin/bash set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" BUILD_DIR="${SCRIPT_DIR}/build" BIN_DIR="${SCRIPT_DIR}/bin" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } check_compiler() { local compiler=$1 if command -v "$compiler" >/dev/null 2>&1; then log_success "Compiler found: $compiler ($(${compiler} --version | head -1))" return 0 else log_warn "Compiler not found: $compiler" return 1 fi } download_file() { local url=$1 local dest=$2 if command -v curl >/dev/null 2>&1; then curl -sL --max-time 60 --retry 3 -o "$dest" "$url" elif command -v wget >/dev/null 2>&1; then wget -q --timeout=60 --tries=3 -O "$dest" "$url" else log_error "Neither curl nor wget is available" return 1 fi } download_file_with_fallback() { local path=$1 local dest=$2 local -a MIRRORS=( "http://archive.ubuntu.com/ubuntu/pool" "http://ru.archive.ubuntu.com/ubuntu/pool" ) for mirror in "${MIRRORS[@]}"; do if download_file "${mirror}/${path}" "$dest" && [ -s "$dest" ]; then return 0 fi done return 1 } noble_repo_add() { echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu noble main universe" \ | sudo tee /etc/apt/sources.list.d/noble-mips-cross.list >/dev/null printf 'Package: *\nPin: release n=noble\nPin-Priority: 100\n' \ | sudo tee /etc/apt/preferences.d/noble-mips-cross >/dev/null sudo apt-get update -qq } noble_repo_remove() { sudo rm -f /etc/apt/sources.list.d/noble-mips-cross.list sudo rm -f /etc/apt/preferences.d/noble-mips-cross sudo apt-get update -qq } install_mips_from_noble() { log_info "Adding Ubuntu 24.04 (noble) repo for MIPS cross-compiler dependencies..." noble_repo_add local tmpdir tmpdir=$(mktemp -d) local -a PKGS=( "universe/g/gcc-12-cross/gcc-12-cross-base_12.3.0-17ubuntu1cross1_all.deb" "universe/g/gcc-12-cross-mipsen/gcc-12-cross-base-mipsen_12.3.0-17ubuntu1cross3_all.deb" "universe/b/binutils-mipsen/binutils-mips-linux-gnu_2.42-2ubuntu1cross5_amd64.deb" "universe/b/binutils-mipsen/binutils-mipsel-linux-gnu_2.42-2ubuntu1cross5_amd64.deb" "universe/g/gcc-12-cross-mipsen/cpp-12-mips-linux-gnu_12.3.0-17ubuntu1cross3_amd64.deb" "universe/g/gcc-12-cross-mipsen/cpp-12-mipsel-linux-gnu_12.3.0-17ubuntu1cross3_amd64.deb" "universe/g/gcc-12-cross-mipsen/gcc-12-mips-linux-gnu_12.3.0-17ubuntu1cross3_amd64.deb" "universe/g/gcc-12-cross-mipsen/gcc-12-mipsel-linux-gnu_12.3.0-17ubuntu1cross3_amd64.deb" "universe/c/cross-toolchain-base-mipsen/linux-libc-dev-mips-cross_6.8.0-25.25cross2_all.deb" "universe/c/cross-toolchain-base-mipsen/linux-libc-dev-mipsel-cross_6.8.0-25.25cross2_all.deb" "universe/c/cross-toolchain-base-mipsen/libc6-mips-cross_2.39-0ubuntu8cross2_all.deb" "universe/c/cross-toolchain-base-mipsen/libc6-dev-mips-cross_2.39-0ubuntu8cross2_all.deb" "universe/c/cross-toolchain-base-mipsen/libc6-mipsel-cross_2.39-0ubuntu8cross2_all.deb" "universe/c/cross-toolchain-base-mipsen/libc6-dev-mipsel-cross_2.39-0ubuntu8cross2_all.deb" "universe/g/gcc-12-cross-mipsen/libgcc-12-dev-mips-cross_12.3.0-17ubuntu1cross3_all.deb" "universe/g/gcc-12-cross-mipsen/libgcc-12-dev-mipsel-cross_12.3.0-17ubuntu1cross3_all.deb" ) local failed=0 for pkg_path in "${PKGS[@]}"; do local pkg_name pkg_name=$(basename "$pkg_path") log_info "Downloading ${pkg_name}..." if ! download_file_with_fallback "${pkg_path}" "${tmpdir}/${pkg_name}"; then log_error "Failed to download ${pkg_name}" failed=1 break fi done if [ $failed -eq 0 ]; then log_info "Installing MIPS packages (noble repo active for dependency resolution)..." if sudo apt-get install -y --allow-downgrades "${tmpdir}"/*.deb; then for pair in "mips-linux-gnu" "mipsel-linux-gnu"; do if [ ! -f "/usr/bin/${pair}-gcc" ] && [ -f "/usr/bin/${pair}-gcc-12" ]; then sudo ln -sf "/usr/bin/${pair}-gcc-12" "/usr/bin/${pair}-gcc" log_info "Created symlink: /usr/bin/${pair}-gcc -> /usr/bin/${pair}-gcc-12" fi done rm -rf "$tmpdir" noble_repo_remove return 0 fi log_error "apt install failed with noble repo" failed=1 fi rm -rf "$tmpdir" noble_repo_remove return 1 } install_mips_from_bootlin() { log_info "Trying Bootlin pre-built toolchains for MIPS..." local BOOTLIN_BASE="https://toolchains.bootlin.com/downloads/releases/toolchains" local INSTALL_DIR="/opt/cross" local tmpdir tmpdir=$(mktemp -d) mkdir -p "$INSTALL_DIR" local -a ARCH_LIST=( "mips32|mips32--uclibc--stable-2024.02-1|mips-buildroot-linux-uclibc|mips-linux-gnu" "mips32el|mips32el--uclibc--stable-2024.02-1|mipsel-buildroot-linux-uclibc|mipsel-linux-gnu" ) for entry in "${ARCH_LIST[@]}"; do local arch_dir compiler_prefix tarball_base link_prefix arch_dir=$(echo "$entry" | cut -d'|' -f1) tarball_base=$(echo "$entry" | cut -d'|' -f2) compiler_prefix=$(echo "$entry" | cut -d'|' -f3) link_prefix=$(echo "$entry" | cut -d'|' -f4) local tarball="${tarball_base}.tar.bz2" log_info "Downloading Bootlin ${arch_dir} toolchain (~200 MB)..." if ! download_file "${BOOTLIN_BASE}/${arch_dir}/tarballs/${tarball}" "${tmpdir}/${tarball}"; then log_error "Failed to download Bootlin ${arch_dir} toolchain" rm -rf "$tmpdir" return 1 fi log_info "Extracting ${arch_dir} toolchain..." tar -xjf "${tmpdir}/${tarball}" -C "$INSTALL_DIR" rm -f "${tmpdir}/${tarball}" local toolchain_dir toolchain_dir=$(ls -d "${INSTALL_DIR}/${tarball_base}" 2>/dev/null | head -1) if [ -z "$toolchain_dir" ]; then log_error "Extracted toolchain directory not found" rm -rf "$tmpdir" return 1 fi for tool in gcc g++ ar ld strip nm objdump objcopy as ranlib; do local real_bin="${toolchain_dir}/bin/${compiler_prefix}-${tool}" [ -f "$real_bin" ] || continue printf '#!/bin/sh\nexec "%s" "$@"\n' "$real_bin" \ | sudo tee "/usr/local/bin/${link_prefix}-${tool}" >/dev/null sudo chmod +x "/usr/local/bin/${link_prefix}-${tool}" done log_success "Bootlin ${arch_dir} toolchain installed to ${toolchain_dir}" done rm -rf "$tmpdir" return 0 } install_cross_compilers() { log_info "Installing cross-compilers and dependencies..." if [ -f /etc/debian_version ]; then log_info "Detected Debian/Ubuntu system" sudo apt-get update local mips_ok=0 if sudo apt-get install -y \ gcc \ gcc-mips-linux-gnu \ gcc-mipsel-linux-gnu \ gcc-aarch64-linux-gnu \ gcc-arm-linux-gnueabihf \ binutils-mips-linux-gnu \ binutils-mipsel-linux-gnu \ binutils-aarch64-linux-gnu \ binutils-arm-linux-gnueabihf \ libc6-dev \ libc6-dev-mips-cross \ libc6-dev-mipsel-cross \ libc6-dev-arm64-cross \ libc6-dev-armhf-cross 2>/dev/null; then mips_ok=1 fi if [ $mips_ok -eq 0 ]; then log_warn "MIPS packages not found in current repos, trying Ubuntu 24.04 (noble) archives..." if ! install_mips_from_noble; then log_warn "Noble archive method failed, trying Bootlin pre-built toolchains..." if ! install_mips_from_bootlin; then log_error "Failed to install MIPS cross-compilers from all sources" log_error "Manual option: https://toolchains.bootlin.com/" fi fi sudo apt-get install -y \ gcc \ gcc-aarch64-linux-gnu \ gcc-arm-linux-gnueabihf \ binutils-aarch64-linux-gnu \ binutils-arm-linux-gnueabihf \ libc6-dev \ libc6-dev-arm64-cross \ libc6-dev-armhf-cross 2>/dev/null || true fi log_success "Cross-compilers installation complete" elif [ -f /etc/redhat-release ]; then log_info "Detected RedHat/CentOS/Fedora system" sudo yum install -y gcc gcc-mips64-linux-gnu gcc-aarch64-linux-gnu gcc-arm-linux-gnu glibc-static || \ sudo dnf install -y gcc gcc-mips64-linux-gnu gcc-aarch64-linux-gnu gcc-arm-linux-gnu glibc-static log_success "Cross-compilers and dependencies installed" elif [ -f /etc/arch-release ]; then log_info "Detected Arch Linux system" sudo pacman -S --needed gcc mips-linux-gnu-gcc aarch64-linux-gnu-gcc arm-linux-gnueabihf-gcc log_success "Cross-compilers and dependencies installed" else log_error "Unsupported distribution. Please install cross-compilers manually." exit 1 fi } build_for_arch() { local arch=$1 local cc=$2 local cflags=$3 local output_name=$4 local use_static=$5 log_info "Building for ${arch}..." local build_arch_dir="${BUILD_DIR}/${arch}" mkdir -p "${build_arch_dir}" cd "${SCRIPT_DIR}" make clean >/dev/null 2>&1 || true local make_cmd="CC=\"${cc}\" EXTRA_CFLAGS=\"${cflags}\"" if [ "$use_static" = "static" ]; then make_cmd="$make_cmd STATIC=1" fi if eval $make_cmd make -j$(nproc) 2>&1 | tee "${build_arch_dir}/build.log"; then if [ -f "${SCRIPT_DIR}/wg-obfuscator" ]; then mkdir -p "${BIN_DIR}" cp "${SCRIPT_DIR}/wg-obfuscator" "${BIN_DIR}/${output_name}" local size=$(ls -lh "${BIN_DIR}/${output_name}" | awk '{print $5}') local file_info=$(file "${BIN_DIR}/${output_name}" | cut -d: -f2) log_success "Build completed: ${output_name} (${size})" echo " ${file_info}" echo "${arch}|SUCCESS|${size}|${file_info}" >> "${BUILD_DIR}/build_report.txt" return 0 else log_error "Binary not found after build" echo "${arch}|FAILED|N/A|Binary not created" >> "${BUILD_DIR}/build_report.txt" return 1 fi else log_error "Build failed for ${arch}" echo "${arch}|FAILED|N/A|Compilation error" >> "${BUILD_DIR}/build_report.txt" return 1 fi } show_summary() { echo echo "========================================" echo " BUILD SUMMARY" echo "========================================" echo if [ -f "${BUILD_DIR}/build_report.txt" ]; then printf "%-12s | %-10s | %-8s | %s\n" "ARCH" "STATUS" "SIZE" "DETAILS" echo "------------------------------------------------------------------------" while IFS='|' read -r arch status size details; do if [ "$status" = "SUCCESS" ]; then printf "${GREEN}%-12s${NC} | ${GREEN}%-10s${NC} | %-8s | %s\n" "$arch" "$status" "$size" "$details" else printf "${RED}%-12s${NC} | ${RED}%-10s${NC} | %-8s | %s\n" "$arch" "$status" "$size" "$details" fi done < "${BUILD_DIR}/build_report.txt" echo local success_count=$(grep -c "SUCCESS" "${BUILD_DIR}/build_report.txt" || echo 0) local total_count=$(wc -l < "${BUILD_DIR}/build_report.txt") echo "Results: ${success_count}/${total_count} successful builds" echo if [ -d "${BIN_DIR}" ] && [ "$(ls -A ${BIN_DIR} 2>/dev/null)" ]; then echo "Built binaries located in: ${BIN_DIR}" echo ls -lh "${BIN_DIR}" fi fi echo echo "Build logs: ${BUILD_DIR}/" echo "========================================" } main() { echo echo "========================================" echo " WireGuard Obfuscator Multi-Arch Build" echo "========================================" echo log_info "Build directory: ${BUILD_DIR}" log_info "Binary output directory: ${BIN_DIR}" echo mkdir -p "${BUILD_DIR}" mkdir -p "${BIN_DIR}" rm -f "${BUILD_DIR}/build_report.txt" log_info "Checking available compilers..." echo local has_gcc=false local has_mips=false local has_mipsel=false local has_aarch64=false local has_i686=false local has_arm=false check_compiler "gcc" && has_gcc=true check_compiler "mips-linux-gnu-gcc" && has_mips=true check_compiler "mipsel-linux-gnu-gcc" && has_mipsel=true check_compiler "aarch64-linux-gnu-gcc" && has_aarch64=true check_compiler "arm-linux-gnueabihf-gcc" && has_arm=true echo if ! $has_gcc || ! $has_mips || ! $has_mipsel || ! $has_aarch64 || ! $has_arm; then log_warn "Some cross-compilers are missing, installing automatically..." install_cross_compilers check_compiler "gcc" && has_gcc=true check_compiler "mips-linux-gnu-gcc" && has_mips=true check_compiler "mipsel-linux-gnu-gcc" && has_mipsel=true check_compiler "aarch64-linux-gnu-gcc" && has_aarch64=true check_compiler "arm-linux-gnueabihf-gcc" && has_arm=true echo fi local build_count=0 local success_count=0 if $has_gcc || check_compiler "gcc"; then log_info "=== Building for x86_64 ===" if build_for_arch "x86_64" "gcc" "" "wg-obfuscator-x86_64" "static"; then success_count=$((success_count + 1)) fi build_count=$((build_count + 1)) echo fi if $has_mips || check_compiler "mips-linux-gnu-gcc"; then log_info "=== Building for MIPS ===" if build_for_arch "mips" "mips-linux-gnu-gcc" "" "wg-obfuscator-mips" "static"; then success_count=$((success_count + 1)) fi build_count=$((build_count + 1)) echo fi if $has_mipsel || check_compiler "mipsel-linux-gnu-gcc"; then log_info "=== Building for MIPSEL ===" if build_for_arch "mipsel" "mipsel-linux-gnu-gcc" "" "wg-obfuscator-mipsel" "static"; then success_count=$((success_count + 1)) fi build_count=$((build_count + 1)) echo fi if $has_aarch64 || check_compiler "aarch64-linux-gnu-gcc"; then log_info "=== Building for AARCH64 ===" if build_for_arch "aarch64" "aarch64-linux-gnu-gcc" "" "wg-obfuscator-aarch64" "static"; then success_count=$((success_count + 1)) fi build_count=$((build_count + 1)) echo fi if $has_arm || check_compiler "arm-linux-gnueabihf-gcc"; then log_info "=== Building for ARMv7 ===" if build_for_arch "armv7" "arm-linux-gnueabihf-gcc" "" "wg-obfuscator-armv7" "static"; then success_count=$((success_count + 1)) fi build_count=$((build_count + 1)) echo fi make clean >/dev/null 2>&1 || true show_summary if [ $success_count -eq $build_count ]; then log_success "All builds completed successfully!" exit 0 else log_warn "Some builds failed. Check logs in ${BUILD_DIR}/" exit 1 fi } main "$@"