Files
chengnan/.gitea/workflows/build-windows-cross-linux.yml
luochen570 4832838a0d
Some checks failed
Cross Build Windows Release on Linux / cross-build-windows (push) Failing after 0s
Build Windows Release with MSYS2 / build-windows-msys2 (push) Has been cancelled
ci: upload build outputs to repository release
2026-05-30 14:11:23 +08:00

220 lines
8.7 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Cross Build Windows Release on Linux
on:
push:
branches:
- main
tags:
- 'v*'
pull_request:
branches:
- main
workflow_dispatch:
jobs:
cross-build-windows:
# 使用可访问 GitHub 的 Gitea act_runnerrunner-mihomo可直接拉取 actions/checkout、actions/upload-artifact 等 GitHub Action。
runs-on: ubuntu-latest
container:
image: fedora:latest
steps:
- name: Prepare action runtime
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
dnf install -y git nodejs
- name: Checkout
uses: actions/checkout@v4
- name: Install cross build dependencies
run: |
set -euo pipefail
dnf install -y \
cmake \
curl \
ninja-build \
p7zip \
p7zip-plugins \
python3 \
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")
du -h "dist-windows-cross/${PACKAGE_NAME}.zip"
- 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.sha256
(cd dist-windows-cross && sha256sum -c chengnan-windows-x86_64-cross.zip.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/'
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: chengnan-windows-x86_64-cross
path: |
dist-windows-cross/chengnan-windows-x86_64-cross.zip
dist-windows-cross/chengnan-windows-x86_64-cross.zip.sha256
if-no-files-found: error
- name: Upload package to repository release
if: ${{ github.event_name != 'pull_request' }}
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
set -euo pipefail
PACKAGE_NAME="chengnan-windows-x86_64-cross"
SERVER_URL="${GITHUB_SERVER_URL:-https://git.luochen570.cn}"
REPOSITORY="${GITHUB_REPOSITORY}"
API_BASE="${SERVER_URL}/api/v1/repos/${REPOSITORY}"
TOKEN="${RELEASE_TOKEN:-${GITHUB_TOKEN:-}}"
test -n "$TOKEN"
if [ "${GITHUB_REF_TYPE:-}" = "tag" ]; then
TAG_NAME="${GITHUB_REF_NAME}"
RELEASE_NAME="${GITHUB_REF_NAME}"
PRERELEASE=false
else
TAG_NAME="build-${GITHUB_SHA:0:10}"
RELEASE_NAME="chengnan ${GITHUB_SHA:0:10}"
PRERELEASE=true
fi
json_escape() {
python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))'
}
release_payload="$(printf '{"tag_name":%s,"target_commitish":%s,"name":%s,"body":%s,"draft":false,"prerelease":%s}' \
"$(printf '%s' "$TAG_NAME" | json_escape)" \
"$(printf '%s' "${GITHUB_SHA}" | json_escape)" \
"$(printf '%s' "$RELEASE_NAME" | json_escape)" \
"$(printf 'Automated Windows x86_64 cross build from Gitea Actions.\n' | json_escape)" \
"$PRERELEASE")"
status="$(curl --show-error --silent --location \
--header "Authorization: token ${TOKEN}" \
--header 'Content-Type: application/json' \
--data "$release_payload" \
--write-out '%{http_code}' \
--output /tmp/gitea-release-response.json \
"${API_BASE}/releases")"
if [ "$status" = "409" ] || [ "$status" = "422" ]; then
RELEASE_ID="$(curl --show-error --silent --location \
--header "Authorization: token ${TOKEN}" \
"${API_BASE}/releases/tags/${TAG_NAME}" \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')"
elif [ "$status" = "201" ] || [ "$status" = "200" ]; then
RELEASE_ID="$(python3 -c 'import json,sys; print(json.load(open("/tmp/gitea-release-response.json"))["id"])')"
else
echo "Create release failed with HTTP ${status}" >&2
cat /tmp/gitea-release-response.json >&2
exit 1
fi
upload_asset() {
local src="$1"
local name
local existing_id
local status
name="$(basename "$src")"
existing_id="$(curl --show-error --silent --location \
--header "Authorization: token ${TOKEN}" \
"${API_BASE}/releases/${RELEASE_ID}/assets" \
| ASSET_NAME="$name" python3 -c 'import json,os,sys; assets=json.load(sys.stdin); print(next((str(a["id"]) for a in assets if a.get("name")==os.environ["ASSET_NAME"]), ""))')"
if [ -n "$existing_id" ]; then
curl --show-error --silent --location \
--request DELETE \
--header "Authorization: token ${TOKEN}" \
--output /tmp/gitea-release-asset-delete-response.json \
"${API_BASE}/releases/${RELEASE_ID}/assets/${existing_id}"
fi
status="$(curl --show-error --silent --location \
--header "Authorization: token ${TOKEN}" \
--form "attachment=@${src};filename=${name}" \
--write-out '%{http_code}' \
--output /tmp/gitea-release-asset-response.json \
"${API_BASE}/releases/${RELEASE_ID}/assets?name=${name}")"
if [ "$status" != "201" ] && [ "$status" != "200" ]; then
echo "Upload release asset failed with HTTP ${status}: ${name}" >&2
cat /tmp/gitea-release-asset-response.json >&2
exit 1
fi
}
upload_asset "dist-windows-cross/${PACKAGE_NAME}.zip"
upload_asset "dist-windows-cross/${PACKAGE_NAME}.zip.sha256"
echo "Release assets uploaded to ${SERVER_URL}/${REPOSITORY}/releases/tag/${TAG_NAME}"