From f9d298622508348a74e2745beac4c865a40ffe35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Sun, 19 Jul 2026 21:16:49 +0800 Subject: [PATCH] Add linux desktop build --- .github/workflows/build.yml | 160 ++++++++++++++++++++++++++++++- cmd/internal/build_boxdd/main.go | 16 ++-- docs/clients/desktop/index.md | 7 +- docs/clients/index.md | 2 +- docs/clients/index.zh.md | 2 +- 5 files changed, 174 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 36c736132..4ff7f63d2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,6 +17,7 @@ on: - Binary - Android - Windows + - Linux - Apple - app-store - iOS @@ -882,6 +883,162 @@ jobs: with: name: binary-windows-client path: 'dist' + build_linux_client: + name: Build Linux client (${{ matrix.desktop_arch }}) + if: (github.event_name != 'workflow_dispatch' || inputs.build == 'All' || inputs.build == 'Linux') && github.ref != 'refs/heads/oldstable' + runs-on: ubuntu-latest + needs: + - calculate_version + strategy: + matrix: + include: + - { desktop_arch: x64, go_arch: amd64 } + - { desktop_arch: arm64, go_arch: arm64 } + - { desktop_arch: armv7l, go_arch: arm, go_arm: "7" } + steps: + - name: Checkout + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + with: + fetch-depth: 0 + submodules: 'recursive' + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: 1.25.12 + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + package_json_file: clients/desktop/package.json + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version-file: clients/desktop/package.json + cache: pnpm + cache-dependency-path: | + clients/desktop/pnpm-lock.yaml + clients/desktop/dashboard/pnpm-lock.yaml + - name: Set tag + run: |- + git ls-remote --exit-code --tags origin v${{ needs.calculate_version.outputs.version }} || echo "PUBLISHED=false" >> "$GITHUB_ENV" + git tag v${{ needs.calculate_version.outputs.version }} -f + - name: Checkout main branch + if: github.ref == 'refs/heads/testing' + run: |- + git -C clients/desktop checkout main + - name: Checkout submodule recursive + run: |- + git -C clients/desktop submodule update --init --recursive + - name: Update version + if: github.event_name == 'workflow_dispatch' + run: |- + go run -v ./cmd/internal/update_desktop_version --ci + - name: Update nightly version + if: github.event_name != 'workflow_dispatch' + run: |- + go run -v ./cmd/internal/update_desktop_version --ci --nightly + - name: Clone cronet-go + run: |- + set -xeuo pipefail + CRONET_GO_VERSION=$(cat .github/CRONET_GO_VERSION) + git init ~/cronet-go + git -C ~/cronet-go remote add origin https://github.com/sagernet/cronet-go.git + git -C ~/cronet-go fetch --depth=1 origin "$CRONET_GO_VERSION" + git -C ~/cronet-go checkout FETCH_HEAD + git -C ~/cronet-go submodule update --init --recursive --depth=1 + - name: Regenerate Debian keyring + run: |- + set -xeuo pipefail + rm -f ~/cronet-go/naiveproxy/src/build/linux/sysroot_scripts/keyring.gpg + cd ~/cronet-go + GPG_TTY=/dev/null ./naiveproxy/src/build/linux/sysroot_scripts/generate_keyring.sh + - name: Cache Chromium toolchain + uses: actions/cache@v4 + with: + path: | + ~/cronet-go/naiveproxy/src/third_party/llvm-build/ + ~/cronet-go/naiveproxy/src/gn/out/ + ~/cronet-go/naiveproxy/src/chrome/build/pgo_profiles/ + ~/cronet-go/naiveproxy/src/out/sysroot-build/ + key: chromium-toolchain-linux-desktop-${{ matrix.go_arch }}-${{ hashFiles('.github/CRONET_GO_VERSION') }} + - name: Download Chromium toolchain + run: |- + set -xeuo pipefail + cd ~/cronet-go + go run ./cmd/build-naive --target=linux/${{ matrix.go_arch }} download-toolchain + - name: Set Chromium toolchain environment + run: |- + set -xeuo pipefail + cd ~/cronet-go + go run ./cmd/build-naive --target=linux/${{ matrix.go_arch }} env >> "$GITHUB_ENV" + - name: Install package tools + run: |- + set -euo pipefail + sudo apt-get update + sudo apt-get install -y debsigs libarchive-tools rpm zstd + curl -Lo "$RUNNER_TEMP/debsigs.diff" 'https://gitlab.com/debsigs/debsigs/-/commit/160138f5de1ec110376d3c807b60a37388bc7c90.diff' + sudo patch /usr/bin/debsigs < "$RUNNER_TEMP/debsigs.diff" + - name: Install dependencies + run: |- + pnpm -C clients/desktop install + - name: Build + run: |- + pnpm -C clients/desktop package:linux -- deb rpm pacman ${{ matrix.desktop_arch }} + env: + CGO_ENABLED: "0" + GOARM: ${{ matrix.go_arm }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Setup package signing + run: |- + set -euo pipefail + SIGNING_GNUPG_HOME="$RUNNER_TEMP/package-signing-gnupg" + SIGNING_PASSPHRASE_FILE="$RUNNER_TEMP/package-signing-passphrase" + mkdir -m 700 "$SIGNING_GNUPG_HOME" + printf '%s' "$GPG_PASSPHRASE" > "$SIGNING_PASSPHRASE_FILE" + chmod 600 "$SIGNING_PASSPHRASE_FILE" + { + echo "GNUPGHOME=$SIGNING_GNUPG_HOME" + echo "SIGNING_PASSPHRASE_FILE=$SIGNING_PASSPHRASE_FILE" + } >> "$GITHUB_ENV" + printf '%s' "$GPG_KEY" | gpg \ + --homedir "$SIGNING_GNUPG_HOME" \ + --batch \ + --pinentry-mode loopback \ + --passphrase-file "$SIGNING_PASSPHRASE_FILE" \ + --import + cat > "$HOME/.rpmmacros" <&2 + exit 1 + fi + mkdir -p dist + cp "${artifacts[@]}" dist + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: binary-linux-client-${{ matrix.desktop_arch }} + path: 'dist' build_apple: name: Build Apple clients runs-on: macos-26 @@ -1066,7 +1223,7 @@ jobs: path: 'dist' upload: name: Upload builds - if: "!failure() && github.event_name == 'workflow_dispatch' && (inputs.build == 'All' || inputs.build == 'Binary' || inputs.build == 'Android' || inputs.build == 'Windows' || inputs.build == 'Apple' || inputs.build == 'macOS-standalone')" + if: "!failure() && github.event_name == 'workflow_dispatch' && (inputs.build == 'All' || inputs.build == 'Binary' || inputs.build == 'Android' || inputs.build == 'Windows' || inputs.build == 'Linux' || inputs.build == 'Apple' || inputs.build == 'macOS-standalone')" runs-on: ubuntu-latest needs: - calculate_version @@ -1075,6 +1232,7 @@ jobs: - build_windows - build_android - build_windows_client + - build_linux_client - build_apple steps: - name: Checkout diff --git a/cmd/internal/build_boxdd/main.go b/cmd/internal/build_boxdd/main.go index 0e0a6fa75..70a0b7083 100644 --- a/cmd/internal/build_boxdd/main.go +++ b/cmd/internal/build_boxdd/main.go @@ -58,7 +58,8 @@ func build() error { if err != nil { return E.Cause(err, "read version") } - tags, err := buildTags(operatingSystem, architecture) + cgoEnabled := operatingSystem != "windows" && os.Getenv("CC") != "" + tags, err := buildTags(operatingSystem, architecture, cgoEnabled) if err != nil { return err } @@ -76,8 +77,12 @@ func build() error { } arguments = append(arguments, "./experimental/boxdd") command := exec.Command("go", arguments...) + cgoEnabledValue := "0" + if cgoEnabled { + cgoEnabledValue = "1" + } command.Env = append(os.Environ(), - "CGO_ENABLED=0", + "CGO_ENABLED="+cgoEnabledValue, "GOOS="+operatingSystem, "GOARCH="+architecture, "GOTOOLCHAIN=local", @@ -91,7 +96,7 @@ func build() error { return nil } -func buildTags(operatingSystem string, architecture string) ([]string, error) { +func buildTags(operatingSystem string, architecture string, cgoEnabled bool) ([]string, error) { tagsFile := "release/DEFAULT_BUILD_TAGS" if operatingSystem == "windows" { if architecture == "386" { @@ -99,15 +104,14 @@ func buildTags(operatingSystem string, architecture string) ([]string, error) { } else { tagsFile = "release/DEFAULT_BUILD_TAGS_WINDOWS" } + } else if !cgoEnabled { + tagsFile = "release/DEFAULT_BUILD_TAGS_OTHERS" } content, err := os.ReadFile(tagsFile) if err != nil { return nil, E.Cause(err, "read build tags") } tags := strings.Split(strings.TrimSpace(string(content)), ",") - if operatingSystem != "windows" { - tags = append(tags, "with_purego") - } if debugEnabled { tags = append(tags, "debug") } diff --git a/docs/clients/desktop/index.md b/docs/clients/desktop/index.md index 332636ebd..2dc8fe288 100644 --- a/docs/clients/desktop/index.md +++ b/docs/clients/desktop/index.md @@ -4,14 +4,13 @@ icon: material/laptop # sing-box for Desktop -SFW allows users to manage and run local or remote sing-box configuration files, and provides -platform-specific function implementation, such as TUN transparent proxy implementation. - -Linux support is on the way. +sing-box for Desktop allows users to manage and run local or remote sing-box configuration files, +and provides platform-specific functionality, such as TUN transparent proxying. ## :material-graph: Requirements * Windows 10+ (x64 / x86 / arm64) +* Linux (x64 / arm64 / armv7l) ## :material-download: Download diff --git a/docs/clients/index.md b/docs/clients/index.md index c1232407e..a527e6be8 100644 --- a/docs/clients/index.md +++ b/docs/clients/index.md @@ -7,7 +7,7 @@ Maintained by Project S to provide a unified experience and platform-specific fu | :material-android: Android | [sing-box for Android](./android/) | | :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple/) | | :material-microsoft-windows: Windows | [sing-box for Desktop](./desktop/) | -| :material-linux: Linux | Working in progress | +| :material-linux: Linux | [sing-box for Desktop](./desktop/) | Some third-party projects that claim to use sing-box or use sing-box as a selling point are not listed here. The core motivation of the maintainers of such projects is to acquire more users, and even though they provide friendly VPN diff --git a/docs/clients/index.zh.md b/docs/clients/index.zh.md index d2fbb4d4b..45747d2fe 100644 --- a/docs/clients/index.zh.md +++ b/docs/clients/index.zh.md @@ -7,7 +7,7 @@ | :material-android: Android | [sing-box for Android](./android/) | | :material-apple: iOS/macOS/Apple tvOS | [sing-box for Apple platforms](./apple/) | | :material-microsoft-windows: Windows | [sing-box for Desktop](./desktop/) | -| :material-linux: Linux | 施工中 | +| :material-linux: Linux | [sing-box for Desktop](./desktop/) | 此处没有列出一些声称使用或以 sing-box 为卖点的第三方项目。此类项目维护者的动机是获得更多用户,即使它们提供友好的商业 VPN 客户端功能, 但代码质量很差且包含广告。