Skip to content

Commit 8fa46a5

Browse files
tausbnCopilot
andcommitted
unified: Build the Swift parser without a local toolchain
Now that the corpus tests no longer skip themselves, running them requires a `swift-syntax-parse` binary — and so far the only way to get one was `cargo build`, which needs Swift installed locally. Bazel already builds the same binary against a hermetic swift.org toolchain, so offer that instead and make it the default. The wrapper script locates its Swift runtime libraries beside itself, so it only works in the flattened layout the extractor pack uses; under `bazel-bin`, and in the runfiles tree, the libraries are in a different directory and it fails to start. Add a `pkg_install` target that stages that layout into a directory, and `scripts/build-parser.sh` to run it and print the resulting path: export CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE=$(scripts/build-parser.sh) `--cargo` selects the previous behaviour, which is quicker to iterate on when a local toolchain is available. Both pin swift-syntax 603.0.2, so either parser produces the same trees. `scripts/update-corpus.sh` now goes through the script and forwards its arguments, so regenerating the corpus needs only Bazel. The staging directory sits under `unified/target`, which is already ignored. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 0e5674e commit 8fa46a5

5 files changed

Lines changed: 68 additions & 6 deletions

File tree

unified/AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ This is a CodeQL extractor based on tree-sitter.
1717

1818
- The mapping from the parse tree to the target AST is found in `extractor/src/languages/swift/swift.rs`
1919

20-
- To run tests for the parser and mapping, run `cargo test` in the `extractor` directory. The corpus tests shell out to the `swift-syntax-parse` binary, which lives in a separate crate that `cargo test` does not build, so build it first with `cargo build -p swift-syntax-rs --bin swift-syntax-parse` (this needs a Swift toolchain; `scripts/update-corpus.sh` does it for you).
20+
- To run tests for the parser and mapping, run `cargo test` in the `extractor` directory. The corpus tests shell out to the `swift-syntax-parse` binary, which lives in a separate crate that `cargo test` does not build; build it and point the tests at it with `export CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE=$(scripts/build-parser.sh)`. That builds with Bazel, whose Swift toolchain is hermetic, so no local Swift installation is needed; pass `--cargo` to build with a local toolchain instead. `scripts/update-corpus.sh` does this for you.
2121

2222
- Extractor test cases are located at `extractor/tests/corpus/swift/*/*.swift`.
2323

unified/extractor/src/languages/swift/parse.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ fn spawn_error(bin: &str, error: std::io::Error) -> String {
7474
if error.kind() == std::io::ErrorKind::NotFound {
7575
format!(
7676
"could not find the Swift parser `{bin}`. Build it with \
77-
`cargo build -p swift-syntax-rs --bin swift-syntax-parse` (this needs a Swift \
78-
toolchain — see `unified/swift-syntax-rs/.swift-version` for the pinned version), \
79-
or point `{PARSE_BIN_ENV}` at an existing copy."
77+
`unified/scripts/build-parser.sh`, which prints the path to set \
78+
`{PARSE_BIN_ENV}` to (it uses Bazel's Swift toolchain, so no local \
79+
Swift installation is needed)."
8080
)
8181
} else {
8282
format!("failed to spawn Swift parser `{bin}`: {error}")

unified/scripts/build-parser.sh

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/bin/bash
2+
# Build `swift-syntax-parse`, the binary the Swift front-end shells out to, and
3+
# print the path to it.
4+
#
5+
# By default this builds with Bazel, whose Swift toolchain is hermetic: nothing
6+
# has to be installed locally. Pass `--cargo` to build through cargo instead,
7+
# which is quicker to iterate on but needs a local Swift toolchain matching
8+
# `swift-syntax-rs/.swift-version`. Both pin the same swift-syntax release, so
9+
# the two produce equivalent parsers.
10+
#
11+
# Typical use:
12+
#
13+
# export CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE=$(scripts/build-parser.sh)
14+
#
15+
# Progress output goes to stderr so that only the path lands on stdout.
16+
set -euo pipefail
17+
IFS=$'\n\t'
18+
19+
cd "$(dirname "$0")/.."
20+
21+
mode=bazel
22+
case "${1:-}" in
23+
"" | --bazel) ;;
24+
--cargo) mode=cargo ;;
25+
*)
26+
echo "usage: $(basename "$0") [--bazel | --cargo]" >&2
27+
exit 2
28+
;;
29+
esac
30+
31+
if [[ $mode == cargo ]]; then
32+
cargo build -p swift-syntax-rs --bin swift-syntax-parse >&2
33+
# Cargo builds workspace members into the target directory at the
34+
# repository root, one level above this directory.
35+
echo "$(cd .. && pwd)/target/debug/swift-syntax-parse"
36+
exit 0
37+
fi
38+
39+
# The wrapper script finds its Swift runtime libraries beside itself, so it only
40+
# works in the flattened layout the installer produces; under `bazel-bin` and in
41+
# the runfiles tree the libraries sit in a different directory.
42+
dest=$PWD/target/swift-syntax-parse
43+
bazel run //unified/swift-syntax-rs:install-parser -- --destdir "$dest" >&2
44+
echo "$dest/swift-syntax-parse"

unified/scripts/update-corpus.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ cd "$(dirname "$0")/.."
88
# separate crate which `cargo test` does not build (the extractor deliberately
99
# does not depend on it, so working on other languages needs no Swift
1010
# toolchain), so build it up front — otherwise the tests below fail on a
11-
# missing binary.
12-
cargo build -p swift-syntax-rs --bin swift-syntax-parse
11+
# missing binary. This defaults to Bazel's hermetic Swift toolchain; pass
12+
# `--cargo` to use a local one instead.
13+
CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE=$(scripts/build-parser.sh "$@")
14+
export CODEQL_EXTRACTOR_UNIFIED_SWIFT_SYNTAX_PARSE
1315

1416
cd extractor
1517
UNIFIED_UPDATE_CORPUS=1 cargo test

unified/swift-syntax-rs/BUILD.bazel

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
load("@rules_pkg//pkg:install.bzl", "pkg_install")
12
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_library", "rust_test")
23
load("@rules_shell//shell:sh_binary.bzl", "sh_binary")
34
load("//misc/bazel:pkg.bzl", "codeql_pkg_runfiles")
@@ -105,3 +106,18 @@ rust_test(
105106
edition = "2024",
106107
target_compatible_with = _SWIFT_SUPPORTED_PLATFORMS,
107108
)
109+
110+
# Stage the packaged parser into a directory, so it can be run outside Bazel:
111+
#
112+
# bazel run //unified/swift-syntax-rs:install-parser -- --destdir <dir>
113+
#
114+
# The wrapper only works in this flattened layout, where it sits next to the
115+
# real binary and the runtime libraries; in `bazel-bin` and in the runfiles tree
116+
# those live in separate directories. Bazel's Swift toolchain is hermetic, so
117+
# this is also how the extractor's tests are run without installing Swift — see
118+
# `unified/scripts/build-parser.sh`.
119+
pkg_install(
120+
name = "install-parser",
121+
srcs = [":swift-syntax-parse-pkg"],
122+
target_compatible_with = _SWIFT_SUPPORTED_PLATFORMS,
123+
)

0 commit comments

Comments
 (0)