All checks were successful
Cross Build Windows Release on Linux / cross-build-windows (push) Successful in 5m7s
185 lines
7.3 KiB
YAML
185 lines
7.3 KiB
YAML
name: Cross Build Windows Release on Linux
|
||
|
||
on:
|
||
push:
|
||
branches:
|
||
- main
|
||
tags:
|
||
- 'v*'
|
||
pull_request:
|
||
branches:
|
||
- main
|
||
workflow_dispatch:
|
||
|
||
jobs:
|
||
cross-build-windows:
|
||
# Gitea act_runner 标签为 9950x;该工作流在 Linux Runner 中交叉编译 Windows x86_64 包。
|
||
runs-on: 9950x
|
||
container:
|
||
image: fedora:latest
|
||
|
||
steps:
|
||
- name: Configure Fedora TUNA mirror
|
||
run: |
|
||
set -euo pipefail
|
||
sed -e 's|^metalink=|#metalink=|g' \
|
||
-e 's|^#baseurl=http://download.example/pub/fedora/linux|baseurl=https://mirrors.tuna.tsinghua.edu.cn/fedora|g' \
|
||
-i /etc/yum.repos.d/fedora*.repo
|
||
if [ -f /etc/yum.repos.d/fedora-cisco-openh264.repo ]; then
|
||
sed -i 's|^enabled=1|enabled=0|g' /etc/yum.repos.d/fedora-cisco-openh264.repo
|
||
fi
|
||
dnf makecache --refresh -y
|
||
|
||
- name: Checkout
|
||
run: |
|
||
set -euo pipefail
|
||
dnf install -y git rsync
|
||
WORKDIR="$(pwd)"
|
||
SRC_DIR="$(mktemp -d /tmp/chengnan-source.XXXXXX)"
|
||
REPO_URL="${GITHUB_SERVER_URL:-https://git.luochen570.cn}/${GITHUB_REPOSITORY}.git"
|
||
TOKEN="${GITHUB_TOKEN:-}"
|
||
if [ -n "$TOKEN" ]; then
|
||
git -c http.extraHeader="Authorization: token ${TOKEN}" \
|
||
clone --depth 1 --branch "${GITHUB_REF_NAME:-main}" "$REPO_URL" "$SRC_DIR"
|
||
else
|
||
git clone --depth 1 --branch "${GITHUB_REF_NAME:-main}" "$REPO_URL" "$SRC_DIR"
|
||
fi
|
||
rsync -a --delete "$SRC_DIR/" "$WORKDIR/"
|
||
rm -rf "$SRC_DIR"
|
||
|
||
- name: Install cross build dependencies
|
||
run: |
|
||
set -euo pipefail
|
||
dnf install -y \
|
||
cmake \
|
||
curl \
|
||
ninja-build \
|
||
p7zip \
|
||
p7zip-plugins \
|
||
mingw64-gcc-c++ \
|
||
mingw64-qt6-qtbase \
|
||
mingw64-opencv
|
||
|
||
- name: Configure
|
||
run: |
|
||
set -euo pipefail
|
||
cmake -S . -B build-windows-cross -G Ninja \
|
||
-DCMAKE_BUILD_TYPE=Release \
|
||
-DCMAKE_TOOLCHAIN_FILE=/usr/share/mingw/toolchain-mingw64.cmake
|
||
|
||
- name: Build
|
||
run: |
|
||
set -euo pipefail
|
||
cmake --build build-windows-cross --parallel "$(nproc)"
|
||
|
||
- name: Package
|
||
run: |
|
||
set -euo pipefail
|
||
APP_NAME="chengnan"
|
||
PACKAGE_NAME="chengnan-windows-x86_64-cross"
|
||
PACKAGE_DIR="dist-windows-cross/${PACKAGE_NAME}"
|
||
EXE="build-windows-cross/${APP_NAME}.exe"
|
||
|
||
test -f "$EXE"
|
||
rm -rf dist-windows-cross
|
||
mkdir -p "$PACKAGE_DIR"
|
||
cp "$EXE" "$PACKAGE_DIR/"
|
||
|
||
# 收集 MinGW 运行时、Qt、OpenCV 依赖 DLL。
|
||
for round in 1 2 3; do
|
||
while IFS= read -r binary; do
|
||
while IFS= read -r dll; do
|
||
[ -f "$dll" ] || continue
|
||
cp -n "$dll" "$PACKAGE_DIR/" || true
|
||
done < <(x86_64-w64-mingw32-objdump -p "$binary" \
|
||
| awk '/DLL Name:/ {print $3}' \
|
||
| while read -r name; do \
|
||
find /usr/x86_64-w64-mingw32/sys-root/mingw/bin -iname "$name" -print -quit; \
|
||
done)
|
||
done < <(find "$PACKAGE_DIR" -maxdepth 1 -type f \( -name '*.exe' -o -name '*.dll' \) | sort)
|
||
done
|
||
|
||
# Qt 平台插件是 Windows Qt GUI 程序启动所必需的。
|
||
QT_PLUGIN_ROOT="/usr/x86_64-w64-mingw32/sys-root/mingw/lib/qt6/plugins"
|
||
if [ -d "$QT_PLUGIN_ROOT/platforms" ]; then
|
||
mkdir -p "$PACKAGE_DIR/platforms"
|
||
cp -n "$QT_PLUGIN_ROOT/platforms"/*.dll "$PACKAGE_DIR/platforms/"
|
||
fi
|
||
|
||
cat > "$PACKAGE_DIR/README.txt" <<'EOF'
|
||
chengnan Windows x86_64 交叉编译发布包
|
||
|
||
运行方式:
|
||
1. 解压整个目录。
|
||
2. 双击 chengnan.exe 运行。
|
||
|
||
说明:
|
||
- 本目录由 Linux Runner 使用 MinGW-w64 交叉编译生成。
|
||
- 请不要只复制 chengnan.exe,需保留同目录 DLL 和 platforms 子目录。
|
||
EOF
|
||
|
||
(cd dist-windows-cross && 7z a -tzip "${PACKAGE_NAME}.zip" "${PACKAGE_NAME}" >/dev/null)
|
||
(cd dist-windows-cross && sha256sum "${PACKAGE_NAME}.zip" > "${PACKAGE_NAME}.zip.sha256")
|
||
|
||
# 当前 Gitea 上传入口约 60 秒会返回 502;大文件按 15 MiB 分片上传。
|
||
ZIP="dist-windows-cross/${PACKAGE_NAME}.zip"
|
||
split -b 15M -d -a 3 "$ZIP" "${ZIP}.part-"
|
||
(cd dist-windows-cross && sha256sum "${PACKAGE_NAME}.zip".part-* > "${PACKAGE_NAME}.zip.parts.sha256")
|
||
du -h "$ZIP" "${ZIP}".part-*
|
||
|
||
- name: Verify package
|
||
run: |
|
||
set -euo pipefail
|
||
test -s dist-windows-cross/chengnan-windows-x86_64-cross.zip
|
||
test -s dist-windows-cross/chengnan-windows-x86_64-cross.zip.part-000
|
||
test -s dist-windows-cross/chengnan-windows-x86_64-cross.zip.parts.sha256
|
||
(cd dist-windows-cross && sha256sum -c chengnan-windows-x86_64-cross.zip.sha256)
|
||
(cd dist-windows-cross && sha256sum -c chengnan-windows-x86_64-cross.zip.parts.sha256)
|
||
7z l dist-windows-cross/chengnan-windows-x86_64-cross.zip | grep 'chengnan.exe'
|
||
7z l dist-windows-cross/chengnan-windows-x86_64-cross.zip | grep 'platforms/'
|
||
python3 - <<'PY'
|
||
from pathlib import Path
|
||
limit = 20 * 1024 * 1024
|
||
for part in Path('dist-windows-cross').glob('chengnan-windows-x86_64-cross.zip.part-*'):
|
||
size = part.stat().st_size
|
||
print(part.name, size)
|
||
if size > limit:
|
||
raise SystemExit(f'{part} is too large for the current Gitea upload path')
|
||
PY
|
||
|
||
- name: Upload package to Gitea Packages
|
||
env:
|
||
PACKAGE_TOKEN: ${{ secrets.PACKAGE_TOKEN }}
|
||
run: |
|
||
set -euo pipefail
|
||
PACKAGE_NAME="chengnan-windows-x86_64-cross"
|
||
VERSION="${GITHUB_SHA:-manual}"
|
||
VERSION="${VERSION:0:10}"
|
||
OWNER="${GITHUB_REPOSITORY%%/*}"
|
||
API_BASE="${GITHUB_SERVER_URL:-https://git.luochen570.cn}/api/packages/${OWNER}/generic/chengnan/${VERSION}"
|
||
TOKEN="${PACKAGE_TOKEN:-${GITHUB_TOKEN:-}}"
|
||
test -n "$TOKEN"
|
||
upload_file() {
|
||
local src="$1"
|
||
local url="$2"
|
||
local status
|
||
status="$(curl --show-error --silent --location \
|
||
--header "Authorization: token ${TOKEN}" \
|
||
--upload-file "$src" \
|
||
--write-out '%{http_code}' \
|
||
--output /tmp/gitea-upload-response.txt \
|
||
"$url")"
|
||
if [ "$status" != "201" ] && [ "$status" != "200" ]; then
|
||
echo "Upload failed with HTTP ${status}: ${url}" >&2
|
||
cat /tmp/gitea-upload-response.txt >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
for part in dist-windows-cross/${PACKAGE_NAME}.zip.part-*; do
|
||
upload_file "$part" "${API_BASE}/$(basename "$part")"
|
||
done
|
||
upload_file "dist-windows-cross/${PACKAGE_NAME}.zip.sha256" "${API_BASE}/${PACKAGE_NAME}.zip.sha256"
|
||
upload_file "dist-windows-cross/${PACKAGE_NAME}.zip.parts.sha256" "${API_BASE}/${PACKAGE_NAME}.zip.parts.sha256"
|
||
echo "Package uploaded to: ${API_BASE}/"
|
||
echo "Download all ${PACKAGE_NAME}.zip.part-* files, then reconstruct with: cat ${PACKAGE_NAME}.zip.part-* > ${PACKAGE_NAME}.zip"
|