diff --git a/.github/workflows/build-android.yml b/.github/workflows/build-android.yml index 64380320..196d256d 100644 --- a/.github/workflows/build-android.yml +++ b/.github/workflows/build-android.yml @@ -40,7 +40,8 @@ jobs: outputs: version: ${{ steps.package.outputs.version }} env: - XMAKE_VERSION: "3.1.1" + # Exercise the minimum supported version; local builds may use newer Xmake. + XMAKE_MIN_VERSION: "3.1.1" CROSSDESK_SOURCE_TAG: ${{ inputs.source_tag || '' }} CROSSDESK_RELEASE_BUILD: ${{ inputs.source_tag && 'YES' || 'NO' }} steps: @@ -119,9 +120,9 @@ jobs: - name: Install xmake uses: xmake-io/github-action-setup-xmake@v1 with: - xmake-version: ${{ env.XMAKE_VERSION }} + xmake-version: ${{ env.XMAKE_MIN_VERSION }} actions-cache-folder: .xmake-toolchain-cache - actions-cache-key: ${{ runner.os }}-${{ runner.arch }}-ubuntu24.04-android-xmake${{ env.XMAKE_VERSION }} + actions-cache-key: ${{ runner.os }}-${{ runner.arch }}-ubuntu24.04-android-xmake${{ env.XMAKE_MIN_VERSION }} - name: Cache Xmake package repository uses: actions/cache@v5 @@ -129,7 +130,7 @@ jobs: path: apps/android/.native/global/.xmake/repositories/xmake-repo key: ${{ runner.os }}-${{ runner.arch }}-android-xmake-repo-v1-${{ hashFiles('apps/android/scripts/build_native.py') }} - # Cache installed packages only. build_native.py checks Xmake 3.1.1 and pins + # Cache installed packages only. build_native.py checks Xmake >= 3.1.1 and pins # its own package repository; never reuse another platform's build/config. - name: Cache native dependencies uses: actions/cache@v5 @@ -146,6 +147,9 @@ jobs: - name: Verify shared license catalog run: python3 -B apps/ios/scripts/generate_third_party_licenses.py + - name: Verify native build tool selection + run: python3 -B -m unittest discover -s apps/android/test -p 'build_native_test.py' -v + - name: Build APKs and run Lint working-directory: apps/android run: | diff --git a/.github/workflows/build-ios.yml b/.github/workflows/build-ios.yml index 299c5167..80643d25 100644 --- a/.github/workflows/build-ios.yml +++ b/.github/workflows/build-ios.yml @@ -51,7 +51,8 @@ jobs: CROSSDESK_SOURCE_TAG: ${{ inputs.source_tag || '' }} IOS_DEPLOYMENT_TARGET: "16.0" EXPECTED_IOS_SDK: "26.5" - XMAKE_VERSION: "3.1.1" + # Exercise the minimum supported version; local builds may use newer Xmake. + XMAKE_MIN_VERSION: "3.1.1" XMAKE_REPO_REVISION: "121109352da272cd1a3d4ed52f2dcda34f839955" steps: @@ -152,9 +153,9 @@ jobs: uses: actions/cache@v5 with: path: apps/ios/.xmake/packages - key: "${{ runner.os }}-xmake${{ env.XMAKE_VERSION }}-deps-ios-arm64-source-v1-xcode26.6-xrepo1211093-min16-${{ github.run_id }}" + key: "${{ runner.os }}-xmake${{ env.XMAKE_MIN_VERSION }}-deps-ios-arm64-source-v1-xcode26.6-xrepo1211093-min16-${{ github.run_id }}" restore-keys: | - ${{ runner.os }}-xmake${{ env.XMAKE_VERSION }}-deps-ios-arm64-source-v1-xcode26.6-xrepo1211093-min16- + ${{ runner.os }}-xmake${{ env.XMAKE_MIN_VERSION }}-deps-ios-arm64-source-v1-xcode26.6-xrepo1211093-min16- - name: Set up Python uses: actions/setup-python@v6 @@ -172,17 +173,14 @@ jobs: - name: Install xmake uses: xmake-io/github-action-setup-xmake@v1 with: - xmake-version: "${{ env.XMAKE_VERSION }}" + xmake-version: "${{ env.XMAKE_MIN_VERSION }}" - - name: Verify xmake version + - name: Verify minimum xmake version shell: bash run: | - XMAKE_VERSION_OUTPUT="$(xmake --version)" - echo "${XMAKE_VERSION_OUTPUT}" - if [[ "${XMAKE_VERSION_OUTPUT}" != *"xmake v${XMAKE_VERSION}"* ]]; then - echo "Unexpected xmake version: expected ${XMAKE_VERSION}" >&2 - exit 1 - fi + xmake --version | tee "${RUNNER_TEMP}/xmake-version.txt" + python3 -B apps/ios/scripts/generate_third_party_licenses.py \ + --xmake-version "${RUNNER_TEMP}/xmake-version.txt" - name: Pin xmake package repository shell: bash diff --git a/.github/workflows/build-linux-image.yml b/.github/workflows/build-linux-image.yml index 2c6518f7..a1f23abd 100644 --- a/.github/workflows/build-linux-image.yml +++ b/.github/workflows/build-linux-image.yml @@ -27,9 +27,9 @@ concurrency: env: IMAGE_NAME: crossdesk/ubuntu20.04 - STACK_TAG: buildenv-cuda12.6.3-gcc10-cmake3.31.6-pipewire0.3.48-xmake3.0.9-rust1.92.0 + STACK_TAG: buildenv-cuda12.6.3-gcc10-cmake3.31.6-pipewire0.3.48-xmake3.1.1-rust1.92.0 CMAKE_VERSION: 3.31.6 - XMAKE_VERSION: 3.0.9 + XMAKE_VERSION: 3.1.1 RUST_VERSION: 1.92.0 RUSTUP_VERSION: 1.28.2 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2d0a753f..850b4efe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,12 +37,12 @@ jobs: include: - arch: amd64 runner: ubuntu-24.04 - image: crossdesk/ubuntu20.04:buildenv-cuda12.6.3-gcc10-cmake3.31.6-pipewire0.3.48-xmake3.0.9-rust1.92.0 + image: crossdesk/ubuntu20.04:buildenv-cuda12.6.3-gcc10-cmake3.31.6-pipewire0.3.48-xmake3.1.1-rust1.92.0 package_script: ./apps/desktop/scripts/linux/pkg_amd64.sh - arch: arm64 runner: ubuntu-24.04-arm - image: crossdesk/ubuntu20.04:buildenv-cuda12.6.3-gcc10-cmake3.31.6-pipewire0.3.48-xmake3.0.9-rust1.92.0 + image: crossdesk/ubuntu20.04:buildenv-cuda12.6.3-gcc10-cmake3.31.6-pipewire0.3.48-xmake3.1.1-rust1.92.0 package_script: ./apps/desktop/scripts/linux/pkg_arm64.sh container: diff --git a/apps/android/README.md b/apps/android/README.md index 5e5af91e..35ab4803 100644 --- a/apps/android/README.md +++ b/apps/android/README.md @@ -35,7 +35,7 @@ - JDK 17 或更新版本(可使用 Android Studio 自带 JBR)。 - Android SDK Platform 36、Build Tools 36.0.0、NDK `28.2.13676358`。 -- Xmake **3.1.1**、Python 3.9+、Git、CMake 和主机编译工具。 +- Xmake **3.1.1 或更新版本**、Python 3.9+、Git、CMake 和主机编译工具。 - Python 的 setuptools、wheel,用于构建依赖的宿主工具。 先在仓库根目录初始化子模块: @@ -49,8 +49,7 @@ macOS 命令行示例: ```sh export ANDROID_HOME="$HOME/Library/Android/sdk" export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home" -# 若 PATH 中的 Xmake 不是 3.1.1,通过 XMAKE_BIN 指定对应可执行文件。 -# 构建器也识别 ~/.cache/crossdesk/toolchains/xmake-3.1.1/xmake。 +# 使用 PATH 中的 Xmake(最低 3.1.1),或通过 XMAKE_BIN 指定其他可执行文件。 cd apps/android ./gradlew :app:assembleDebug ``` @@ -94,7 +93,7 @@ git push origin android-v1.6.0-20261002 已有 Release 需要补传服务器或刷新下载信息时,可手动运行 `Update version.json from Release` 并填写已有 `source_tag`,无需重新构建。 -工作流使用 Ubuntu 24.04、JDK 17、Python 3.13、SDK 36、Build Tools 36.0.0、NDK r28c 和 Xmake 3.1.1。Gradle 使用工程内的 Wrapper,原生构建器固定 Xmake 包仓库版本。SDK/NDK 使用独立目录缓存,按宿主系统、架构和工具链版本区分;命中缓存时跳过 SDK 安装,未命中时在安装完成后立即保存,即使后续 APK 构建失败,下次也可复用。Xmake 可执行环境、固定版本的包仓库和 pip 下载也有各自的缓存;Ubuntu 系统工具只安装缺失项。 +工作流使用 Ubuntu 24.04、JDK 17、Python 3.13、SDK 36、Build Tools 36.0.0、NDK r28c,并使用最低支持的 Xmake 3.1.1 验证构建;本地允许使用更新的 Xmake。Gradle 使用工程内的 Wrapper,原生构建器固定 Xmake 包仓库版本。SDK/NDK 使用独立目录缓存,按宿主系统、架构和工具链版本区分;命中缓存时跳过 SDK 安装,未命中时在安装完成后立即保存,即使后续 APK 构建失败,下次也可复用。Xmake 可执行环境、固定版本的包仓库和 pip 下载也有各自的缓存;Ubuntu 系统工具只安装缺失项。 Gradle 缓存与 Android 原生依赖缓存分别管理;原生缓存按宿主架构、构建脚本及 MiniRTC 配方区分,不复用桌面或 iOS 的配置和目标文件。GitHub 托管 runner 每次启动仍是新环境;第一次运行或缓存失效时需要安装。不同分支和标签可读取默认分支的缓存,因此建议先在默认分支运行一次 `Build Android` 预热,再创建发布标签。 diff --git a/apps/android/native/xmake.lua b/apps/android/native/xmake.lua index 5a1171ef..85ffcd88 100644 --- a/apps/android/native/xmake.lua +++ b/apps/android/native/xmake.lua @@ -1,4 +1,5 @@ set_project("crossdesk_android") +set_xmakever("3.1.1") set_languages("c++17") add_rules("mode.release", "mode.debug") set_policy("package.precompiled", false) diff --git a/apps/android/scripts/build_native.py b/apps/android/scripts/build_native.py index b585fa4e..77b7b125 100644 --- a/apps/android/scripts/build_native.py +++ b/apps/android/scripts/build_native.py @@ -12,6 +12,19 @@ ROOT = ANDROID.parents[1] SOURCE = ROOT / 'deps/submodules/minirtc' CACHE = ANDROID / '.native' PACKAGE_REVISION = 'eda39de3fb99b420c168f1ab9ab2d1791e11b662' +XMAKE_MIN_VERSION = (3, 1, 1) + + +def find_xmake(): + xmake = os.environ.get('XMAKE_BIN') or shutil.which('xmake') + minimum = '.'.join(map(str, XMAKE_MIN_VERSION)) + if not xmake: + raise SystemExit(f'Xmake {minimum} or newer is required; install it or set XMAKE_BIN.') + output = subprocess.check_output([xmake, '--version'], text=True) + version = re.search(r'xmake v(\d+)\.(\d+)\.(\d+)(?:\+|[,\s]|$)', output) + if not version or tuple(map(int, version.groups())) < XMAKE_MIN_VERSION: + raise SystemExit(f'Use Xmake {minimum} or newer (set XMAKE_BIN to its executable).') + return xmake def main(): @@ -20,13 +33,7 @@ def main(): ndk = sdk / 'ndk/28.2.13676358' if not ndk.is_dir(): raise SystemExit('Install Android NDK 28.2.13676358 using SDK Manager.') - bundled = Path.home() / '.cache/crossdesk/toolchains/xmake-3.1.1/xmake' - xmake = os.environ.get('XMAKE_BIN') or (str(bundled) if bundled.is_file() else shutil.which('xmake')) - if not xmake: - raise SystemExit('xmake is required; install it or set XMAKE_BIN.') - version = subprocess.check_output([xmake, '--version'], text=True) - if not re.search(r'xmake v3\.1\.1(?:\+|[,\s])', version): - raise SystemExit('Use Xmake 3.1.1 (set XMAKE_BIN to its executable).') + xmake = find_xmake() if not (SOURCE / 'xmake.lua').is_file(): raise SystemExit('Initialize the MiniRTC submodule before building.') env = os.environ.copy() diff --git a/apps/android/test/build_native_test.py b/apps/android/test/build_native_test.py new file mode 100644 index 00000000..c9263fb3 --- /dev/null +++ b/apps/android/test/build_native_test.py @@ -0,0 +1,57 @@ +"""Check Xmake discovery and the minimum supported version before native builds.""" + +import importlib.util +import os +from pathlib import Path +import unittest +from unittest.mock import patch + + +source = Path(__file__).resolve().parents[1] / "scripts/build_native.py" +spec = importlib.util.spec_from_file_location("build_native", source) +build_native = importlib.util.module_from_spec(spec) +spec.loader.exec_module(build_native) + + +class XmakeSelectionTest(unittest.TestCase): + def setUp(self): + for patcher in ( + patch.dict(os.environ, {}, clear=True), + patch.object(build_native.shutil, "which", return_value="/tools/xmake"), + patch.object(build_native.subprocess, "check_output", return_value="xmake v3.1.1\n"), + ): + patcher.start() + self.addCleanup(patcher.stop) + + def test_path_tool_accepts_minimum_and_newer_versions(self): + for output in ("xmake v3.1.1", "xmake v3.1.2\n", "xmake v3.1.10, A build utility\n", + "xmake v3.2.0\n", "xmake v3.10.0\n", "xmake v4.0.0\n", + "\x1b[1mxmake v3.1.1+HEAD.3ba37a0d4, A build utility\x1b[0m\n"): + with self.subTest(output=output): + build_native.subprocess.check_output.return_value = output + self.assertEqual(build_native.find_xmake(), "/tools/xmake") + + def test_explicit_tool_takes_precedence_over_path(self): + os.environ["XMAKE_BIN"] = "/custom/xmake" + self.assertEqual(build_native.find_xmake(), "/custom/xmake") + build_native.shutil.which.assert_not_called() + build_native.subprocess.check_output.assert_called_once_with( + ["/custom/xmake", "--version"], text=True) + + def test_missing_tool_reports_minimum_requirement(self): + build_native.shutil.which.return_value = None + with self.assertRaisesRegex(SystemExit, "Xmake 3.1.1 or newer is required"): + build_native.find_xmake() + build_native.subprocess.check_output.assert_not_called() + + def test_older_or_unrecognized_versions_are_rejected(self): + for output in ("xmake v3.1.0\n", "xmake v3.0.99\n", "xmake v2.99.99\n", + "xmake version unknown\n", "xmake v3.1\n", "xmake v3.1.1invalid\n", ""): + with self.subTest(output=output): + build_native.subprocess.check_output.return_value = output + with self.assertRaisesRegex(SystemExit, "Use Xmake 3.1.1 or newer"): + build_native.find_xmake() + + +if __name__ == "__main__": + unittest.main() diff --git a/apps/ios/README.md b/apps/ios/README.md index 7fa404c4..9b0e3a95 100644 --- a/apps/ios/README.md +++ b/apps/ios/README.md @@ -7,7 +7,7 @@ There is no `WKWebView` or browser runtime. ## Requirements - Xcode 16 or newer -- Xmake 3.1.1 available on `PATH` (or selected with `XMAKE_BIN`) +- Xmake 3.1.1 or newer available on `PATH` (or selected with `XMAKE_BIN`) - A physical arm64 iPhone/iPad running iOS 16 or newer, or an iOS simulator on Apple Silicon ## Build @@ -27,7 +27,7 @@ licenses** when cloning: `git clone --branch --recurse-submodules https://github.com/kunkundi/crossdesk.git`. The iOS marketing version is independent of the repository tag; use the source tag or commit recorded in the app. -Install [Xmake 3.1.1](https://github.com/xmake-io/xmake/releases/tag/v3.1.1), +Install [Xmake](https://xmake.io/guide/quick-start.html) 3.1.1 or newer, CMake, and a current Python 3 with setuptools/wheel. Pin the package repository in a separate Xmake global directory before building: @@ -41,7 +41,7 @@ git -C "$XMAKE_GLOBALDIR/.xmake/repositories/xmake-repo" checkout --detach 12110 Keep `XMAKE_GLOBALDIR` set for command-line Xcode builds. For builds launched from the Xcode app, set it as a user-defined build setting on the target, or pin the default `~/.xmake/repositories/xmake-repo` instead. The build checks -the tool version, package repository commit and reviewed recipe hashes. +the minimum Xmake version, package repository commit and reviewed recipe hashes. Application dependencies are built from source, with Xmake precompiled package downloads disabled. @@ -105,9 +105,10 @@ or relevant build configuration also trigger it. The main workflow on branch/tag pushes and manual runs, and waits for its result before publishing a version-tag release. -The workflow retains the pinned Xcode/SDK and Xmake versions, dependency cache, -license and privacy checks, unsigned arm64 Release build, and app-bundle -verification. It uploads `crossdesk-ios-arm64-unsigned-v-.zip`, +The workflow tests the minimum supported Xmake version (3.1.1) and retains the +pinned Xcode/SDK, dependency cache, license and privacy checks, unsigned arm64 +Release build, and app-bundle verification. It uploads +`crossdesk-ios-arm64-unsigned-v-.zip`, including the app, source metadata, third-party source catalog, rights notice and any generated dSYM. The version comes from the iOS target; dated repository tags provide the build date, otherwise the date uses the Asia/Shanghai timezone. diff --git a/apps/ios/licenses/sources.json b/apps/ios/licenses/sources.json index 54c83667..b4bc6365 100644 --- a/apps/ios/licenses/sources.json +++ b/apps/ios/licenses/sources.json @@ -900,7 +900,7 @@ ], "bundle_sha256": "f54e5e2168bf6e91d81a413931a052d29f59e0c221df5e1de3f51bd27c662c3a", "toolchain": { - "xmake_version": "3.1.1", + "xmake_min_version": "3.1.1", "xmake_repository_revision": "121109352da272cd1a3d4ed52f2dcda34f839955" } } diff --git a/apps/ios/scripts/generate_third_party_licenses.py b/apps/ios/scripts/generate_third_party_licenses.py index 3e48d752..f47bed30 100644 --- a/apps/ios/scripts/generate_third_party_licenses.py +++ b/apps/ios/scripts/generate_third_party_licenses.py @@ -137,9 +137,10 @@ def generate(lock, cache): def verify(lock, inputs, target_info, xmake_repository=None, xmake_version=None): checked(OUTPUT.read_bytes(), lock["bundle_sha256"], str(OUTPUT)) if xmake_version is not None: - version = re.search(r"xmake v(\d+\.\d+\.\d+)", xmake_version.read_text()) - if not version or version[1] != lock["toolchain"]["xmake_version"]: - raise ValueError("Xmake version differs from the reviewed iOS toolchain; see apps/ios/README.md") + minimum = lock["toolchain"]["xmake_min_version"] + version = re.search(r"xmake v(\d+)\.(\d+)\.(\d+)(?:\+|[,\s]|$)", xmake_version.read_text()) + if not version or tuple(map(int, version.groups())) < tuple(map(int, minimum.split("."))): + raise ValueError(f"Xmake {minimum} or newer is required; see apps/ios/README.md") if xmake_repository is not None: revision = subprocess.check_output( ["git", "-C", str(xmake_repository), "rev-parse", "HEAD"], text=True).strip() diff --git a/apps/ios/tests/third_party_licenses_test.py b/apps/ios/tests/third_party_licenses_test.py index c480e4d3..74d5ec90 100644 --- a/apps/ios/tests/third_party_licenses_test.py +++ b/apps/ios/tests/third_party_licenses_test.py @@ -52,7 +52,7 @@ class LicenseValidationTest(unittest.TestCase): self.target.write_text(str(self.root / "packages/a/asio/1.0/abcd/include") + "\n") self.lock = { "bundle_sha256": licenses.digest(self.bundle.read_bytes()), - "toolchain": {"xmake_version": "3.1.1"}, + "toolchain": {"xmake_min_version": "3.1.1"}, "components": [ { "id": "minirtc", "version": self.reviewed_revision, @@ -149,11 +149,23 @@ class LicenseValidationTest(unittest.TestCase): with self.assertRaisesRegex(ValueError, "Source checksum mismatch: .*libopus.a"): self.verify() - def test_unreviewed_toolchain_is_rejected(self): + def test_minimum_and_newer_xmake_versions_are_accepted(self): version = self.root / "xmake-version.txt" - version.write_text("xmake v3.1.2\n") - with self.assertRaisesRegex(ValueError, "Xmake version differs"): - self.verify(xmake_version=version) + for output in ("xmake v3.1.1", "xmake v3.1.2\n", "xmake v3.1.10, A build utility\n", + "xmake v3.2.0\n", "xmake v3.10.0\n", "xmake v4.0.0\n", + "\x1b[1mxmake v3.1.1+HEAD.3ba37a0d4, A build utility\x1b[0m\n"): + with self.subTest(output=output): + version.write_text(output) + self.verify(xmake_version=version) + + def test_older_or_unrecognized_xmake_versions_are_rejected(self): + version = self.root / "xmake-version.txt" + for output in ("xmake v3.1.0\n", "xmake v3.0.99\n", "xmake v2.99.99\n", + "xmake version unknown\n", "xmake v3.1\n", "xmake v3.1.1invalid\n", ""): + with self.subTest(output=output): + version.write_text(output) + with self.assertRaisesRegex(ValueError, "Xmake 3.1.1 or newer is required"): + self.verify(xmake_version=version) class ComponentSourceTest(unittest.TestCase): diff --git a/docker/linux-build/Dockerfile b/docker/linux-build/Dockerfile index 4e192c56..f62a9182 100644 --- a/docker/linux-build/Dockerfile +++ b/docker/linux-build/Dockerfile @@ -5,7 +5,7 @@ FROM ${BASE_IMAGE} ARG TARGETARCH ARG CMAKE_VERSION=3.31.6 -ARG XMAKE_VERSION=3.0.9 +ARG XMAKE_VERSION=3.1.1 ARG RUST_VERSION=1.92.0 ARG RUSTUP_VERSION=1.28.2 diff --git a/docker/linux-build/README.md b/docker/linux-build/README.md index b25e3e3d..1608b395 100644 --- a/docker/linux-build/README.md +++ b/docker/linux-build/README.md @@ -5,6 +5,9 @@ CMake 3.31、xmake、Rust、Linux 开发库(包括 D-Bus、DRM,以及仅用 PipeWire 0.3/SPA 头文件 SDK)以及根据项目 `xmake.lua` 提前编译好的依赖。 +Xmake 最低支持 3.1.1,与移动端一致,构建环境校验允许更新版本。发布镜像的工具链 tag +记录实际安装的版本;默认使用最低支持版本验证构建。 + ## 发布方式 推送影响镜像的文件到 `ci/linux-build-image` 分支时, @@ -12,7 +15,7 @@ PipeWire 0.3/SPA 头文件 SDK)以及根据项目 全部通过后再合并为同一个 multi-arch 镜像: ```text -crossdesk/ubuntu20.04:buildenv-cuda12.6.3-gcc10-cmake3.31.6-pipewire0.3.48-xmake3.0.9-rust1.92.0 +crossdesk/ubuntu20.04:buildenv-cuda12.6.3-gcc10-cmake3.31.6-pipewire0.3.48-xmake3.1.1-rust1.92.0 ``` Docker 会根据运行机器自动选择正确架构。amd64 变体以 diff --git a/docker/linux-build/verify-build-image.sh b/docker/linux-build/verify-build-image.sh index fc8ff5b6..c998ff0f 100644 --- a/docker/linux-build/verify-build-image.sh +++ b/docker/linux-build/verify-build-image.sh @@ -3,7 +3,7 @@ set -euo pipefail EXPECTED_ARCH="${EXPECTED_ARCH:-}" EXPECTED_CMAKE_VERSION="${EXPECTED_CMAKE_VERSION:-3.31.6}" -EXPECTED_XMAKE_VERSION="${EXPECTED_XMAKE_VERSION:-3.0.9}" +XMAKE_MIN_VERSION="${XMAKE_MIN_VERSION:-3.1.1}" EXPECTED_RUST_VERSION="${EXPECTED_RUST_VERSION:-1.92.0}" BUILD_CC="${CC:-/usr/bin/gcc-10}" BUILD_CXX="${CXX:-/usr/bin/g++-10}" @@ -28,7 +28,11 @@ if [[ -n "${EXPECTED_ARCH}" && "${ACTUAL_ARCH}" != "${EXPECTED_ARCH}" ]]; then fi XMAKE_VERSION_OUTPUT="$(xmake --version 2>&1)" -grep -F "v${EXPECTED_XMAKE_VERSION}" <<<"${XMAKE_VERSION_OUTPUT}" >/dev/null +ACTUAL_XMAKE_VERSION="$(sed -nE 's/.*xmake v([0-9]+\.[0-9]+\.[0-9]+)(\+.*|,.*|[[:space:]].*|$)/\1/p' <<<"${XMAKE_VERSION_OUTPUT}" | head -n 1)" +if [[ -z "${ACTUAL_XMAKE_VERSION}" ]] || ! dpkg --compare-versions "${ACTUAL_XMAKE_VERSION}" ge "${XMAKE_MIN_VERSION}"; then + echo "Xmake ${XMAKE_MIN_VERSION} or newer is required, found ${ACTUAL_XMAKE_VERSION:-unknown}" >&2 + exit 1 +fi rustc --version | grep -F "rustc ${EXPECTED_RUST_VERSION}" >/dev/null cargo --version >/dev/null cmake --version | grep -F "cmake version ${EXPECTED_CMAKE_VERSION}" >/dev/null diff --git a/docs/BUILD.md b/docs/BUILD.md index 181128a3..cc1daf65 100644 --- a/docs/BUILD.md +++ b/docs/BUILD.md @@ -6,7 +6,7 @@ ## 构建依赖 -- Git、[Xmake](https://xmake.io/guide/quick-start.html) 及下文对应平台的编译工具链。 +- Git、[Xmake](https://xmake.io/guide/quick-start.html)(桌面端和移动端均要求 3.1.1 或更新版本)及下文对应平台的编译工具链。 - 构建脚本通过 Xmake 管理 **CMake 3.x(≥ 3.21、< 4.0)**、**Rust 1.92.0** 等依赖;首次构建需要下载工具与源码。具体约束见 [Slint 包配置](../deps/thirdparty/slint/xmake.lua)。 ## Windows @@ -246,6 +246,6 @@ README 的桌面图片直接由当前 Slint UI 渲染,复现方式见 [截图 ## Android -原生控制端位于独立的 `apps/android` Gradle 工程,要求 Android 8.0+ arm64 设备,使用 SDK 36、NDK r28c 和 Xmake 3.1.1。构建、APK 安装与模拟器测试见 [Android 开发说明](../apps/android/README.md)。 +原生控制端位于独立的 `apps/android` Gradle 工程,要求 Android 8.0+ arm64 设备,使用 SDK 36、NDK r28c 和 Xmake 3.1.1 或更新版本。构建、APK 安装与模拟器测试见 [Android 开发说明](../apps/android/README.md)。 [Android CI](../.github/workflows/build-android.yml) 可独立手动运行,并由主构建工作流调用。CI 提供 Debug / 设备测试 APK、未签名 Release APK 和 Lint 报告,执行原生协议测试及 16 KB 对齐、许可证检查;标签发布收集未签名 Release APK,安装前需要自行签名。设备测试需要另行在 arm64 手机或模拟器上执行。 diff --git a/docs/BUILD_EN.md b/docs/BUILD_EN.md index b5f8bc5f..c90b4639 100644 --- a/docs/BUILD_EN.md +++ b/docs/BUILD_EN.md @@ -6,7 +6,7 @@ After cloning, run build and packaging commands from the repository root. The [X ## Build requirements -- Git, [Xmake](https://xmake.io/guide/quick-start.html), and the platform toolchain listed below. +- Git, [Xmake](https://xmake.io/guide/quick-start.html) (3.1.1 or newer for both desktop and mobile), and the platform toolchain listed below. - The build scripts use Xmake to manage **CMake 3.x (≥ 3.21, < 4.0)**, **Rust 1.92.0**, and other dependencies. The first build downloads tools and source archives. See the [Slint package configuration](../deps/thirdparty/slint/xmake.lua) for the constraints. ## Windows @@ -258,6 +258,6 @@ Desktop README images are rendered directly from the current Slint UI. See the [ ## Android -The native controller is a separate Gradle project in `apps/android`, targeting Android 8.0+ arm64 with SDK 36, NDK r28c, and Xmake 3.1.1. See the [Android development guide](../apps/android/README.md) for APK builds, installation, and emulator tests. +The native controller is a separate Gradle project in `apps/android`, targeting Android 8.0+ arm64 with SDK 36, NDK r28c, and Xmake 3.1.1 or newer. See the [Android development guide](../apps/android/README.md) for APK builds, installation, and emulator tests. [Android CI](../.github/workflows/build-android.yml) can run manually on its own and is also called by the main build workflow. It uploads Debug/device-test APKs, an unsigned Release APK and Lint reports, runs native protocol tests, and checks 16 KB alignment and license contents. Tag releases include the unsigned Release APK, which requires your own signing before installation. Device tests must be run separately on an arm64 phone or emulator. diff --git a/xmake.lua b/xmake.lua index 6a32755d..d0871b74 100644 --- a/xmake.lua +++ b/xmake.lua @@ -1,4 +1,5 @@ set_project("crossdesk") +set_xmakever("3.1.1") set_license("GPL-3.0-only") local source_dir = os.getenv("CROSSDESK_SOURCE_DIR") or os.scriptdir()