Skip to content

Commit 710b1c1

Browse files
ci: build linux64_sqlite against depends with PLATFORM_GUI=1
A new linux64_platform_gui depends target builds depends with PLATFORM_GUI=1, and linux64_sqlite builds against it instead of the linux64 depends (as linux64_tsan builds against linux64_multiprocess's), so dash-qt and the unit tests of that job are built with --enable-platform-gui (enabled through config.site) without adding a separate build and test job. contrib/devtools/check-no-rust.py then fails the linux64_sqlite build if dashd, dash-cli, dash-tx, dash-wallet or the fuzz binary contain cxx bridge, Rust runtime or Rust standard library symbols, or no symbols at all: dash-sdk-cxx is for dash-qt only. The source cache also gets the x86_64 Linux sources of the new depends job: the Rust toolchain, protoc, standard library and Platform archives. Its runner may be ARM, and the toolchain and protoc archives are chosen by the build machine, so download-one is given BUILD and HOST directly; download-linux would not pass BUILD to its sub-make. The cache key is versioned so that a cache saved without those sources is not taken as complete. This step fails until the Platform archives are on the depends sources mirror. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 1dfa4bc commit 710b1c1

9 files changed

Lines changed: 121 additions & 11 deletions

File tree

‎.github/workflows/build-depends.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ jobs:
170170
uses: actions/cache/restore@v5
171171
with:
172172
path: depends/sources
173-
key: depends-sources-${{ hashFiles('depends/packages/*') }}
174-
restore-keys: depends-sources-
173+
key: depends-sources-v2-${{ hashFiles('depends/packages/*') }}
174+
restore-keys: depends-sources-v2-
175175

176176
- name: Restore SDKs cache
177177
id: sdk-cache

‎.github/workflows/build.yml‎

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,7 @@ jobs:
227227
if: |
228228
vars.SKIP_LINUX64 == '' ||
229229
vars.SKIP_LINUX64_ASAN == '' ||
230-
vars.SKIP_LINUX64_FUZZ == '' ||
231-
vars.SKIP_LINUX64_SQLITE == ''
230+
vars.SKIP_LINUX64_FUZZ == ''
232231
with:
233232
build-target: linux64
234233
container-path: ${{ needs.container.outputs.path }}
@@ -263,6 +262,18 @@ jobs:
263262
runs-on: ${{ needs.check-skip.outputs['runner-amd64'] }}
264263
runs-on-check: ${{ needs.check-skip.outputs['runner-check-skip'] }}
265264

265+
depends-linux64_platform_gui:
266+
name: x86_64-pc-linux-gnu_platform_gui
267+
uses: ./.github/workflows/build-depends.yml
268+
needs: [check-skip, container, cache-sources]
269+
if: ${{ vars.SKIP_LINUX64_SQLITE == '' }}
270+
with:
271+
build-target: linux64_platform_gui
272+
container-path: ${{ needs.container.outputs.path }}
273+
base-image-digest: ${{ needs.check-skip.outputs.base-image-digest }}
274+
runs-on: ${{ needs.check-skip.outputs['runner-amd64'] }}
275+
runs-on-check: ${{ needs.check-skip.outputs['runner-check-skip'] }}
276+
266277
depends-mac:
267278
name: x86_64-apple-darwin
268279
uses: ./.github/workflows/build-depends.yml
@@ -387,15 +398,15 @@ jobs:
387398
src-linux64_sqlite:
388399
name: linux64_sqlite-build
389400
uses: ./.github/workflows/build-src.yml
390-
needs: [check-skip, container, depends-linux64]
401+
needs: [check-skip, container, depends-linux64_platform_gui]
391402
if: ${{ vars.SKIP_LINUX64_SQLITE == '' }}
392403
with:
393404
build-target: linux64_sqlite
394405
container-path: ${{ needs.container.outputs.path }}
395-
depends-key: ${{ needs.depends-linux64.outputs.key }}
396-
depends-host: ${{ needs.depends-linux64.outputs.host }}
397-
depends-dep-opts: ${{ needs.depends-linux64.outputs.dep-opts }}
398-
depends-artifact: ${{ needs.depends-linux64.outputs.built-artifact }}
406+
depends-key: ${{ needs.depends-linux64_platform_gui.outputs.key }}
407+
depends-host: ${{ needs.depends-linux64_platform_gui.outputs.host }}
408+
depends-dep-opts: ${{ needs.depends-linux64_platform_gui.outputs.dep-opts }}
409+
depends-artifact: ${{ needs.depends-linux64_platform_gui.outputs.built-artifact }}
399410
runs-on: ${{ needs.check-skip.outputs['runner-amd64'] }}
400411
secrets: *remote-ccache-auth
401412

‎.github/workflows/cache-depends-sources.yml‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,23 @@ jobs:
3131
allow-unsafe-pr-checkout: true
3232
persist-credentials: false
3333

34+
# v2: caches from before the Platform GUI step below lack its sources.
3435
- name: Check for cached sources
3536
id: cache-check
3637
uses: actions/cache@v5
3738
with:
3839
path: depends/sources
39-
key: depends-sources-${{ hashFiles('depends/packages/*') }}
40-
restore-keys: depends-sources-
40+
key: depends-sources-v2-${{ hashFiles('depends/packages/*') }}
41+
restore-keys: depends-sources-v2-
4142
lookup-only: true
4243

4344
- name: Download sources
4445
if: steps.cache-check.outputs.cache-hit != 'true'
4546
run: make -C depends download
47+
48+
# The linux64_platform_gui depends job runs on x86_64, but this runner
49+
# may not: name the build machine, since the Rust toolchain and protoc
50+
# archives are chosen by it. download-linux would not pass BUILD on.
51+
- name: Download Platform GUI sources for x86_64 Linux
52+
if: steps.cache-check.outputs.cache-hit != 'true'
53+
run: make -C depends download-one PLATFORM_GUI=1 BUILD=x86_64-pc-linux-gnu HOST=x86_64-unknown-linux-gnu

‎ci/dash/build_src.sh‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ if [ "${RUN_STDLIB_PATH_CHECK}" = "true" ]; then
5454
make -C src --jobs=1 check-stdlib-paths
5555
fi
5656

57+
if [ "${RUN_CHECK_NO_RUST}" = "true" ]; then
58+
"${BASE_ROOT_DIR}/contrib/devtools/check-no-rust.py" src/dashd src/dash-cli src/dash-tx src/dash-wallet src/test/fuzz/fuzz
59+
fi
60+
5761
if [ -n "$USE_VALGRIND" ]; then
5862
echo "valgrind in USE!"
5963
"${BASE_ROOT_DIR}/ci/test/wrap-valgrind.sh"

‎ci/dash/matrix.sh‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ elif [ "$BUILD_TARGET" = "linux64_multiprocess" ]; then
3030
source ./ci/test/00_setup_env_native_multiprocess.sh
3131
elif [ "$BUILD_TARGET" = "linux64_nowallet" ]; then
3232
source ./ci/test/00_setup_env_native_nowallet_libbitcoinkernel.sh
33+
elif [ "$BUILD_TARGET" = "linux64_platform_gui" ]; then
34+
source ./ci/test/00_setup_env_native_platform_gui.sh
3335
elif [ "$BUILD_TARGET" = "linux64_sqlite" ]; then
3436
source ./ci/test/00_setup_env_native_sqlite.sh
3537
elif [ "$BUILD_TARGET" = "linux64_tsan" ]; then
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Copyright (c) 2026 The Dash Core developers
4+
# Distributed under the MIT software license, see the accompanying
5+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
6+
7+
export LC_ALL=C.UTF-8
8+
9+
# Depends with dash-sdk-cxx (PLATFORM_GUI=1); linux64_sqlite builds against it.
10+
export CONTAINER_NAME=ci_native_platform_gui
11+
export HOST=x86_64-pc-linux-gnu
12+
export DEP_OPTS="PLATFORM_GUI=1"

‎ci/test/00_setup_env_native_sqlite.sh‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ export PACKAGES="python3-zmq qtbase5-dev qttools5-dev-tools libdbus-1-dev libhar
1111
export DEP_OPTS="NO_BDB=1 NO_UPNP=1 DEBUG=1"
1212
export GOAL="install"
1313
export BITCOIN_CONFIG="--enable-zmq --enable-reduce-exports --with-sqlite --without-bdb CC=gcc-11 CXX=g++-11"
14+
export RUN_CHECK_NO_RUST="true"

‎contrib/devtools/README.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,3 +219,11 @@ bundle hash on any machine. The Platform tarball and the bundle are then
219219
uploaded to the depends sources mirror.
220220

221221
contrib/devtools/platform-bundle.sh <platform-commit>
222+
223+
check-no-rust.py
224+
================
225+
226+
Fails if any of the given executables contain Rust code. Run by the
227+
`linux64_sqlite` CI job, which builds against depends with `PLATFORM_GUI=1`,
228+
on `dashd`, the command-line tools and the fuzz binary, which must never link
229+
`dash-sdk-cxx`.

‎contrib/devtools/check-no-rust.py‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2026 The Dash Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
'''
6+
Check that executables do not link Rust code.
7+
8+
dash-sdk-cxx, the Dash Platform SDK binding (--enable-platform-gui), is for
9+
dash-qt only; dashd, the command-line tools and the fuzz binary must not
10+
contain any of it.
11+
A binary fails if its symbol table has cxx bridge, Rust runtime or Rust
12+
standard library symbols, or has no symbols at all (a stripped binary cannot
13+
be checked).
14+
15+
Example usage:
16+
17+
contrib/devtools/check-no-rust.py src/dashd src/dash-cli src/dash-tx src/dash-wallet src/test/fuzz/fuzz
18+
'''
19+
import re
20+
import subprocess
21+
import sys
22+
23+
from utils import determine_wellknown_cmd
24+
25+
# cxx bridge symbols carry "cxxbridge1$". Rust code is either legacy-mangled
26+
# under a crate namespace (rust, std, core, alloc) or v0-mangled ("_R"
27+
# followed by a path tag and a crate root "Cs<disambiguator>_"), which C and
28+
# C++ symbols never match. The allocator shim, the panic handler and the
29+
# unwinding personality are plain C names every Rust program links.
30+
RUST_SYMBOL = re.compile(
31+
r'cxxbridge1\$'
32+
r'|_ZN(4rust|3std|4core|5alloc)[0-9]'
33+
r'|\b_?_R[A-Za-z0-9_]*?Cs[A-Za-z0-9]*_[0-9]'
34+
r'|\b_?(__rust_alloc|rust_begin_unwind|rust_eh_personality)'
35+
)
36+
37+
38+
def rust_symbols(nm, path):
39+
result = subprocess.run(nm + [path], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, check=False)
40+
if result.returncode != 0:
41+
sys.exit(f'{path}: {result.stderr.strip()}')
42+
lines = result.stdout.splitlines()
43+
if not lines:
44+
sys.exit(f'{path}: no symbols, so it cannot be checked (stripped?)')
45+
return [line for line in lines if RUST_SYMBOL.search(line)]
46+
47+
48+
def main():
49+
if len(sys.argv) < 2:
50+
sys.exit(__doc__)
51+
nm = determine_wellknown_cmd('NM', 'nm')
52+
failed = False
53+
for path in sys.argv[1:]:
54+
found = rust_symbols(nm, path)
55+
if found:
56+
failed = True
57+
print(f'{path}: links Rust code, for example:')
58+
for line in found[:5]:
59+
print(f' {line}')
60+
sys.exit(1 if failed else 0)
61+
62+
63+
if __name__ == '__main__':
64+
main()

0 commit comments

Comments
 (0)