This reverts commit d6e40fb7f5.
We do not need this manual patch as it is the part of the code now.
452 lines
14 KiB
Bash
Executable File
452 lines
14 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# == Require Red Hat Enterprise Linux/FedoraLinux/RockyLinux/AlmaLinux/CentOS OR Ubuntu ==
|
|
if [[ -r /etc/os-release ]]; then
|
|
source /etc/os-release
|
|
case "$ID" in
|
|
rhel | rocky | almalinux | fedora | centos | ubuntu)
|
|
echo "[OK] Detected supported system: $NAME $VERSION_ID"
|
|
;;
|
|
*)
|
|
echo "[ERROR] Unsupported system: $NAME ($ID)."
|
|
echo "This script only supports Red Hat Enterprise Linux/RockyLinux/AlmaLinux/CentOS or Ubuntu."
|
|
exit 1
|
|
;;
|
|
esac
|
|
else
|
|
echo "[ERROR] Cannot detect system (missing /etc/os-release)."
|
|
exit 1
|
|
fi
|
|
|
|
# ======================== Kernel version check (require >= 6.11) =======================
|
|
MIN_KERNEL_MAJOR=6
|
|
MIN_KERNEL_MINOR=11
|
|
KERNEL_FULL=$(uname -r)
|
|
KERNEL_MAJOR=$(echo "$KERNEL_FULL" | cut -d. -f1)
|
|
KERNEL_MINOR=$(echo "$KERNEL_FULL" | cut -d. -f2)
|
|
|
|
echo "[INFO] Detected kernel version: $KERNEL_FULL"
|
|
|
|
if (( KERNEL_MAJOR < MIN_KERNEL_MAJOR )) || { (( KERNEL_MAJOR == MIN_KERNEL_MAJOR )) && (( KERNEL_MINOR < MIN_KERNEL_MINOR )); }; then
|
|
echo "[ERROR] Kernel $KERNEL_FULL is too old. Requires Linux >= ${MIN_KERNEL_MAJOR}.${MIN_KERNEL_MINOR}."
|
|
echo "Please upgrade your system or use a newer container (e.g. Fedora 42+, RHEL 10+, Debian 13+)."
|
|
exit 1
|
|
fi
|
|
|
|
echo "[OK] Kernel version >= ${MIN_KERNEL_MAJOR}.${MIN_KERNEL_MINOR}."
|
|
|
|
# ===== Config & Parse arguments =========================================================
|
|
VERSION_ARG="${1:-}" # Pass version number like 7.13.8, or leave empty
|
|
WITH_CORE="both" # Default: bundle both xray+sing-box
|
|
ARCH_OVERRIDE="" # --arch x64|arm64|all (optional compile target)
|
|
|
|
# If the first argument starts with --, do not treat it as a version number
|
|
if [[ "${VERSION_ARG:-}" == --* ]]; then
|
|
VERSION_ARG=""
|
|
fi
|
|
# Take the first non --* argument as version, discard it
|
|
if [[ -n "${VERSION_ARG:-}" ]]; then shift || true; fi
|
|
|
|
# Parse remaining optional arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--with-core)
|
|
WITH_CORE="${2:-both}"
|
|
shift 2
|
|
;;
|
|
--xray-ver)
|
|
XRAY_VER="${2:-}"
|
|
shift 2
|
|
;;
|
|
--singbox-ver)
|
|
SING_VER="${2:-}"
|
|
shift 2
|
|
;;
|
|
--arch)
|
|
ARCH_OVERRIDE="${2:-}"
|
|
shift 2
|
|
;;
|
|
--release)
|
|
RPM_RELEASE="${2:-}"
|
|
shift 2
|
|
;;
|
|
*)
|
|
if [[ -z "${VERSION_ARG:-}" ]]; then VERSION_ARG="$1"; fi
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "${RPM_RELEASE:-}" ]]; then
|
|
echo "--release is required"
|
|
exit 1
|
|
fi
|
|
|
|
# ===== Environment check + Dependencies ========================================
|
|
host_arch="$(uname -m)"
|
|
if ! [[ "$host_arch" == "aarch64" || "$host_arch" == "x86_64" ]]; then
|
|
echo "Only supports aarch64 / x86_64"
|
|
exit 1
|
|
fi
|
|
|
|
install_ok=0
|
|
case "$ID" in
|
|
# ------------------------------ RHEL family (UNCHANGED) ------------------------------
|
|
rhel | rocky | almalinux | centos)
|
|
if command -v dnf >/dev/null 2>&1; then
|
|
sudo dnf -y install dotnet-sdk-8.0 rpm-build rpmdevtools curl unzip tar rsync ||
|
|
sudo dnf -y install dotnet-sdk rpm-build rpmdevtools curl unzip tar rsync
|
|
install_ok=1
|
|
elif command -v yum >/dev/null 2>&1; then
|
|
sudo yum -y install dotnet-sdk-8.0 rpm-build rpmdevtools curl unzip tar rsync ||
|
|
sudo yum -y install dotnet-sdk rpm-build rpmdevtools curl unzip tar rsync
|
|
install_ok=1
|
|
fi
|
|
;;
|
|
# ------------------------------ Ubuntu ----------------------------------------------
|
|
ubuntu)
|
|
sudo apt-get update
|
|
# Ensure 'universe' (Ubuntu) to get 'rpm'
|
|
if ! apt-cache policy | grep -q '^500 .*ubuntu.com/ubuntu.* universe'; then
|
|
sudo apt-get -y install software-properties-common || true
|
|
sudo add-apt-repository -y universe || true
|
|
sudo apt-get update
|
|
fi
|
|
# Base tools + rpm (provides rpmbuild)
|
|
sudo apt-get -y install curl unzip tar rsync rpm || true
|
|
# Cross-arch binutils so strip matches target arch + objdump for brp scripts
|
|
sudo apt-get -y install binutils binutils-x86-64-linux-gnu binutils-aarch64-linux-gnu || true
|
|
# rpmbuild presence check
|
|
if ! command -v rpmbuild >/dev/null 2>&1; then
|
|
echo "[ERROR] 'rpmbuild' not found after installing 'rpm'."
|
|
echo " Please ensure the 'rpm' package is available from your repos (universe on Ubuntu)."
|
|
exit 1
|
|
fi
|
|
# .NET SDK 8 (best effort via apt)
|
|
if ! command -v dotnet >/dev/null 2>&1; then
|
|
sudo apt-get -y install dotnet-sdk-8.0 || true
|
|
sudo apt-get -y install dotnet-sdk-8 || true
|
|
sudo apt-get -y install dotnet-sdk || true
|
|
fi
|
|
install_ok=1
|
|
;;
|
|
esac
|
|
|
|
if [[ "$install_ok" -ne 1 ]]; then
|
|
echo "[WARN] Could not auto-install dependencies for '$ID'. Make sure these are available:"
|
|
echo " dotnet-sdk 8.x, curl, unzip, tar, rsync, rpm, rpmdevtools, rpm-build (on RPM-based distros)"
|
|
fi
|
|
|
|
command -v curl >/dev/null
|
|
|
|
# Root directory = the script's location
|
|
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
|
cd "$SCRIPT_DIR"
|
|
|
|
source ./utils.sh
|
|
|
|
# Git submodules (best effort)
|
|
if [[ -f .gitmodules ]]; then
|
|
git submodule sync --recursive || true
|
|
git submodule update --init --recursive || true
|
|
fi
|
|
|
|
# ===== Locate project ================================================================
|
|
PROJECT="v2rayN.Desktop/v2rayN.Desktop.csproj"
|
|
if [[ ! -f "$PROJECT" ]]; then
|
|
PROJECT="$(find . -maxdepth 3 -name 'v2rayN.Desktop.csproj' | head -n1 || true)"
|
|
fi
|
|
[[ -f "$PROJECT" ]] || {
|
|
echo "v2rayN.Desktop.csproj not found"
|
|
exit 1
|
|
}
|
|
|
|
VERSION="$VERSION_ARG"
|
|
|
|
# ===== Build results collection for --arch all ========================================
|
|
BUILT_RPMS=() # Will collect absolute paths of built RPMs
|
|
BUILT_ALL=0 # Flag to know if we should print the final summary
|
|
|
|
# ===== Build (single-arch) function ====================================================
|
|
build_for_arch() {
|
|
# $1: target short arch: x64 | arm64
|
|
local short="$1"
|
|
local rid rpm_target archdir
|
|
case "$short" in
|
|
x64)
|
|
rid="linux-x64"
|
|
rpm_target="x86_64"
|
|
archdir="x86_64"
|
|
;;
|
|
arm64)
|
|
rid="linux-arm64"
|
|
rpm_target="aarch64"
|
|
archdir="aarch64"
|
|
;;
|
|
*)
|
|
echo "[ERROR] Unknown arch '$short' (use x64|arm64)"
|
|
return 1
|
|
;;
|
|
esac
|
|
|
|
echo "[*] Building for target: $short (RID=$rid, RPM --target $rpm_target)"
|
|
|
|
# .NET publish (self-contained) for this RID
|
|
dotnet restore "$PROJECT"
|
|
rm -rf "$(dirname "$PROJECT")/bin/Release/net8.0" || true
|
|
dotnet publish "$PROJECT" \
|
|
-c Release -r "$rid" \
|
|
--sc \
|
|
-p:PublishSingleFile=false \
|
|
-p:SelfContained=true \
|
|
-p:IncludeNativeLibrariesForSelfExtract=true \
|
|
-p:StripSymbols=true
|
|
|
|
# Per-arch variables (scoped)
|
|
local RID_DIR="$rid"
|
|
local PUBDIR
|
|
PUBDIR="$(dirname "$PROJECT")/bin/Release/net8.0/${RID_DIR}/publish"
|
|
[[ -d "$PUBDIR" ]]
|
|
sudo find "$PUBDIR" -type f -name "*.so" -exec strip {} +
|
|
|
|
# Make RID_DIR visible to download helpers (they read this var)
|
|
export RID_DIR
|
|
|
|
# Per-arch working area
|
|
local PKGROOT="v2rayN-publish"
|
|
local WORKDIR
|
|
WORKDIR="$(mktemp -d)"
|
|
trap '[[ -n "${WORKDIR:-}" ]] && rm -rf "$WORKDIR"' RETURN
|
|
|
|
# rpmbuild topdir selection
|
|
local TOPDIR SPECDIR SOURCEDIR USE_TOPDIR_DEFINE
|
|
if [[ "$ID" =~ ^(rhel|rocky|almalinux|centos)$ ]]; then
|
|
rpmdev-setuptree
|
|
TOPDIR="${HOME}/rpmbuild"
|
|
SPECDIR="${TOPDIR}/SPECS"
|
|
SOURCEDIR="${TOPDIR}/SOURCES"
|
|
USE_TOPDIR_DEFINE=0
|
|
else
|
|
TOPDIR="${WORKDIR}/rpmbuild"
|
|
SPECDIR="${TOPDIR}/SPECS}"
|
|
SOURCEDIR="${TOPDIR}/SOURCES"
|
|
mkdir -p "${SPECDIR}" "${SOURCEDIR}" "${TOPDIR}/BUILD" "${TOPDIR}/RPMS" "${TOPDIR}/SRPMS"
|
|
USE_TOPDIR_DEFINE=1
|
|
fi
|
|
|
|
# Stage publish content
|
|
mkdir -p "$WORKDIR/$PKGROOT"
|
|
cp -a "$PUBDIR/." "$WORKDIR/$PKGROOT/"
|
|
|
|
# Optional icon
|
|
local ICON_CANDIDATE
|
|
ICON_CANDIDATE="$(dirname "$PROJECT")/../v2rayN.Desktop/v2rayN.png"
|
|
[[ -f "$ICON_CANDIDATE" ]] && cp "$ICON_CANDIDATE" "$WORKDIR/$PKGROOT/v2rayn.png" || true
|
|
|
|
# Prepare bin structure
|
|
mkdir -p "$WORKDIR/$PKGROOT/bin/xray" "$WORKDIR/$PKGROOT/bin/sing_box"
|
|
|
|
# Bundle / cores per-arch
|
|
if [[ "$WITH_CORE" == "xray" || "$WITH_CORE" == "both" ]]; then
|
|
download_xray "$WORKDIR/$PKGROOT/bin/xray" || echo "[!] xray download failed (skipped)"
|
|
fi
|
|
if [[ "$WITH_CORE" == "sing-box" || "$WITH_CORE" == "both" ]]; then
|
|
download_singbox "$WORKDIR/$PKGROOT/bin/sing_box" || echo "[!] sing-box download failed (skipped)"
|
|
fi
|
|
download_geo_assets "$WORKDIR/$PKGROOT" || echo "[!] Geo rules download failed (skipped)"
|
|
|
|
# Tarball
|
|
mkdir -p "$SOURCEDIR"
|
|
tar -C "$WORKDIR" -czf "$SOURCEDIR/$PKGROOT.tar.gz" "$PKGROOT"
|
|
|
|
# SPEC
|
|
local SPECFILE="$SPECDIR/v2rayN.spec"
|
|
mkdir -p "$SPECDIR"
|
|
cat >"$SPECFILE" <<'SPEC'
|
|
%global debug_package %{nil}
|
|
%undefine _debuginfo_subpackages
|
|
%undefine _debugsource_packages
|
|
# Ignore outdated LTTng dependencies incorrectly reported by the .NET runtime (to avoid installation failures)
|
|
%global __requires_exclude ^liblttng-ust\.so\..*$
|
|
|
|
Name: v2rayn-unofficial
|
|
Version: __VERSION__
|
|
Release: __RELEASE__
|
|
Summary: v2rayN (Avalonia) GUI client for Linux (x86_64/aarch64)
|
|
License: GPL-3.0-only
|
|
URL: https://git.vlyaii.ru/voronin9032/v2rayN
|
|
BugURL: https://github.com/2dust/v2rayN/issues
|
|
ExclusiveArch: aarch64 x86_64
|
|
Source0: __PKGROOT__.tar.gz
|
|
|
|
# Runtime dependencies (Avalonia / X11 / Fonts / GL)
|
|
Requires: freetype, cairo, pango, openssl, mesa-libEGL, mesa-libGL
|
|
Requires: glibc >= 2.34
|
|
Requires: fontconfig >= 2.13.1
|
|
Requires: desktop-file-utils >= 0.26
|
|
Requires: xdg-utils >= 1.1.3
|
|
Requires: coreutils >= 8.32
|
|
Requires: bash >= 5.1
|
|
|
|
Conflicts: v2rayN
|
|
Obsoletes: v2rayN
|
|
|
|
%description
|
|
v2rayN Linux for Red Hat Enterprise Linux
|
|
Support vless / vmess / Trojan / http / socks / Anytls / Hysteria2 / Shadowsocks / tuic / WireGuard
|
|
Support Red Hat Enterprise Linux / Fedora Linux / Rocky Linux / AlmaLinux / CentOS
|
|
For more information, Please visit our website
|
|
https://github.com/2dust/v2rayN
|
|
|
|
%prep
|
|
%setup -q -n __PKGROOT__
|
|
|
|
%build
|
|
# no build
|
|
|
|
%install
|
|
install -dm0755 %{buildroot}/opt/v2rayN
|
|
cp -a * %{buildroot}/opt/v2rayN/
|
|
|
|
# Launcher (prefer native ELF first, then DLL fallback)
|
|
install -dm0755 %{buildroot}%{_bindir}
|
|
cat > %{buildroot}%{_bindir}/v2rayn << 'EOF'
|
|
#!/usr/bin/bash
|
|
set -euo pipefail
|
|
DIR="/opt/v2rayN"
|
|
|
|
# Prefer native apphost
|
|
if [[ -x "$DIR/v2rayN" ]]; then exec "$DIR/v2rayN" "$@"; fi
|
|
|
|
# DLL fallback
|
|
for dll in v2rayN.Desktop.dll v2rayN.dll; do
|
|
if [[ -f "$DIR/$dll" ]]; then exec /usr/bin/dotnet "$DIR/$dll" "$@"; fi
|
|
done
|
|
|
|
echo "v2rayN launcher: no executable found in $DIR" >&2
|
|
ls -l "$DIR" >&2 || true
|
|
exit 1
|
|
EOF
|
|
chmod 0755 %{buildroot}%{_bindir}/v2rayn
|
|
|
|
# Desktop file
|
|
install -dm0755 %{buildroot}%{_datadir}/applications
|
|
cat > %{buildroot}%{_datadir}/applications/v2rayn.desktop << 'EOF'
|
|
[Desktop Entry]
|
|
Type=Application
|
|
Name=v2rayN
|
|
Comment=v2rayN for Red Hat Enterprise Linux
|
|
Exec=v2rayn
|
|
Icon=v2rayn
|
|
Terminal=false
|
|
Categories=Network;
|
|
EOF
|
|
|
|
# Icon
|
|
if [ -f "%{_builddir}/__PKGROOT__/v2rayn.png" ]; then
|
|
install -dm0755 %{buildroot}%{_datadir}/icons/hicolor/256x256/apps
|
|
install -m0644 %{_builddir}/__PKGROOT__/v2rayn.png %{buildroot}%{_datadir}/icons/hicolor/256x256/apps/v2rayn.png
|
|
fi
|
|
|
|
%post
|
|
/usr/bin/update-desktop-database %{_datadir}/applications >/dev/null 2>&1 || true
|
|
/usr/bin/gtk-update-icon-cache -f %{_datadir}/icons/hicolor >/dev/null 2>&1 || true
|
|
|
|
%postun
|
|
/usr/bin/update-desktop-database %{_datadir}/applications >/dev/null 2>&1 || true
|
|
/usr/bin/gtk-update-icon-cache -f %{_datadir}/icons/hicolor >/dev/null 2>&1 || true
|
|
|
|
%files
|
|
%{_bindir}/v2rayn
|
|
/opt/v2rayN
|
|
%{_datadir}/applications/v2rayn.desktop
|
|
%{_datadir}/icons/hicolor/256x256/apps/v2rayn.png
|
|
SPEC
|
|
|
|
# Replace placeholders
|
|
sed -i "s/__VERSION__/${VERSION}/g" "$SPECFILE"
|
|
sed -i "s/__RELEASE__/${RPM_RELEASE}/g" "$SPECFILE"
|
|
sed -i "s/__PKGROOT__/${PKGROOT}/g" "$SPECFILE"
|
|
|
|
# ----- Select proper 'strip' per target arch on Ubuntu only (cross-binutils) -----
|
|
# NOTE: We define only __strip to point to the target-arch strip.
|
|
# DO NOT override __brp_strip (it must stay the brp script path).
|
|
local STRIP_ARGS=()
|
|
if [[ "$ID" == "ubuntu" ]]; then
|
|
local STRIP_BIN=""
|
|
if [[ "$short" == "x64" ]]; then
|
|
STRIP_BIN="/usr/bin/x86_64-linux-gnu-strip"
|
|
else
|
|
STRIP_BIN="/usr/bin/aarch64-linux-gnu-strip"
|
|
fi
|
|
if [[ -x "$STRIP_BIN" ]]; then
|
|
STRIP_ARGS=(--define "__strip $STRIP_BIN")
|
|
fi
|
|
fi
|
|
|
|
# Build RPM for this arch (force rpm --target to match compile arch)
|
|
if [[ "$USE_TOPDIR_DEFINE" -eq 1 ]]; then
|
|
rpmbuild -ba "$SPECFILE" --define "_topdir $TOPDIR" --target "$rpm_target" "${STRIP_ARGS[@]}"
|
|
else
|
|
rpmbuild -ba "$SPECFILE" --target "$rpm_target" "${STRIP_ARGS[@]}"
|
|
fi
|
|
|
|
# Copy temporary rpmbuild to ~/rpmbuild on Debian/Ubuntu path
|
|
if [[ "$USE_TOPDIR_DEFINE" -eq 1 ]]; then
|
|
mkdir -p "$HOME/rpmbuild"
|
|
rsync -a "$TOPDIR"/ "$HOME/rpmbuild"/
|
|
TOPDIR="$HOME/rpmbuild"
|
|
fi
|
|
|
|
echo "Build done for $short. RPM at:"
|
|
local f
|
|
for f in "${TOPDIR}/RPMS/${archdir}/v2rayN-${VERSION}-${RPM_RELEASE}"*.rpm; do
|
|
[[ -e "$f" ]] || continue
|
|
echo " $f"
|
|
BUILT_RPMS+=("$f")
|
|
done
|
|
}
|
|
|
|
# ===== Arch selection and build orchestration =========================================
|
|
case "${ARCH_OVERRIDE:-}" in
|
|
"")
|
|
# No --arch: use host architecture
|
|
if [[ "$host_arch" == "aarch64" ]]; then
|
|
build_for_arch arm64
|
|
else
|
|
build_for_arch x64
|
|
fi
|
|
;;
|
|
x64 | amd64)
|
|
build_for_arch x64
|
|
;;
|
|
arm64 | aarch64)
|
|
build_for_arch arm64
|
|
;;
|
|
all)
|
|
BUILT_ALL=1
|
|
# Build x64 and arm64 separately; each package contains its own arch-only binaries.
|
|
build_for_arch x64
|
|
build_for_arch arm64
|
|
;;
|
|
*)
|
|
echo "[ERROR] Unknown --arch '${ARCH_OVERRIDE}'. Use x64|arm64|all."
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# ===== Final summary if building both arches ==========================================
|
|
if [[ "$BUILT_ALL" -eq 1 ]]; then
|
|
echo ""
|
|
echo "================ Build Summary (both architectures) ================"
|
|
if [[ "${#BUILT_RPMS[@]}" -gt 0 ]]; then
|
|
for rp in "${BUILT_RPMS[@]}"; do
|
|
echo "$rp"
|
|
done
|
|
else
|
|
echo "[WARN] No RPMs detected in summary (check build logs above)."
|
|
fi
|
|
echo "==================================================================="
|
|
fi
|