Files
codeql/unified/swift-syntax-rs/build.rs
Taus 3eb353ecf7 swift-syntax-rs: Address PR review feedback
- BUILD.bazel: require x86_64 on the Linux branch of the compatibility
  select. The only registered standalone Linux Swift toolchain is
  x86_64-only, so without the CPU constraint Linux/aarch64 targets
stayed
  "compatible" and then failed toolchain resolution instead of being
  skipped cleanly.
- build.rs: emitting `rerun-if-changed` disables Cargo's default
  whole-package scan, so list every input to `swift build` — the package
  manifests, `Package.resolved`, `.swift-version`, and the whole Sources
  tree — so stale shim/toolchain output can't linger. (`.build/` is left
  unwatched, as it is this build's own output.)
- src/lib.rs: a null result from the shim is not a parse failure —
  SwiftParser recovers from invalid syntax and always yields a tree — so
it
  means the shim failed to serialize/allocate the JSON. Fix the error
  message and the variant doc accordingly.
- README.md: `.swift-version` is not honored by the macOS Bazel build
  (which uses the host Xcode toolchain); document that it pins the Linux
  and local builds only.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-15 12:14:56 +00:00

107 lines
4.3 KiB
Rust

use std::env;
use std::path::PathBuf;
use std::process::Command;
fn main() {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let swift_dir = manifest_dir.join("swift");
// Emitting any `rerun-if-changed` disables Cargo's default whole-package
// scan, so we must list every input to the `swift build` below. Watch the
// package manifests, the pinned dependency lockfile, the pinned compiler
// version, and the entire Swift sources tree (a directory is scanned
// recursively). `.build/` is intentionally *not* watched (it is this
// build's output; watching it would cause perpetual rebuilds).
for input in [
swift_dir.join("Package.swift"),
swift_dir.join("Package.resolved"),
swift_dir.join("Sources"),
manifest_dir.join(".swift-version"),
] {
println!("cargo:rerun-if-changed={}", input.display());
}
println!("cargo:rerun-if-env-changed=SWIFT");
println!("cargo:rerun-if-env-changed=SWIFTC");
// Build the Swift FFI package as a release dynamic library.
let mut command = Command::new(swift_bin());
command
.args(["build", "-c", "release"])
.current_dir(&swift_dir);
apply_bare_repository_workaround(&mut command);
let status = command.status().unwrap_or_else(|e| {
panic!(
"failed to run `{swift} build`: {e}\n\
Install a Swift toolchain (see https://www.swift.org/install/, e.g. via \
swiftly) and ensure `swift` is on PATH, or set the `SWIFT` environment \
variable to the `swift` executable. The pinned version is in `.swift-version`.",
swift = swift_bin(),
)
});
assert!(status.success(), "`swift build` failed");
// Link against the freshly built dynamic library.
let build_dir = swift_dir.join(".build/release");
println!("cargo:rustc-link-search=native={}", build_dir.display());
println!("cargo:rustc-link-lib=dylib=SwiftSyntaxFFI");
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", build_dir.display());
// The executable also needs to find the Swift runtime libraries at run time.
if let Some(runtime) = swift_runtime_dir() {
println!("cargo:rustc-link-search=native={}", runtime.display());
println!("cargo:rustc-link-arg=-Wl,-rpath,{}", runtime.display());
}
}
/// Query the active Swift toolchain for the directory containing its runtime
/// shared libraries (e.g. `libswiftCore.so`).
fn swift_runtime_dir() -> Option<PathBuf> {
let output = Command::new(swiftc_bin())
.arg("-print-target-info")
.output()
.ok()?;
if !output.status.success() {
return None;
}
let info = String::from_utf8_lossy(&output.stdout);
// Extract the value of `"runtimeResourcePath": "..."` without pulling in a
// JSON dependency.
let key = "\"runtimeResourcePath\"";
let start = info.find(key)?;
let rest = &info[start + key.len()..];
let colon = rest.find(':')?;
let after = &rest[colon + 1..];
let open = after.find('"')?;
let value_start = &after[open + 1..];
let close = value_start.find('"')?;
let resource_path = &value_start[..close];
Some(PathBuf::from(resource_path).join(if cfg!(target_os = "macos") { "macosx" } else { "linux" }))
}
/// The `swift` driver to invoke: `$SWIFT` if set, otherwise `swift` from `PATH`.
/// This keeps the build tool-agnostic — any Swift install works; no particular
/// version manager is required.
fn swift_bin() -> String {
env::var("SWIFT").unwrap_or_else(|_| "swift".to_string())
}
/// The `swiftc` compiler to invoke: `$SWIFTC` if set, otherwise `swiftc` from
/// `PATH`.
fn swiftc_bin() -> String {
env::var("SWIFTC").unwrap_or_else(|_| "swiftc".to_string())
}
/// Some environments (notably GitHub Codespaces) inject
/// `GIT_CONFIG_KEY_0=safe.bareRepository` / `GIT_CONFIG_VALUE_0=explicit`, which
/// breaks the cached bare git repositories `swift build` uses. When exactly that
/// key is present, relax it to `all` for the `swift build` subprocess only
/// (rather than unconditionally, which could clobber an unrelated
/// `GIT_CONFIG_VALUE_0`).
fn apply_bare_repository_workaround(command: &mut Command) {
if env::var("GIT_CONFIG_KEY_0").as_deref() == Ok("safe.bareRepository") {
command.env("GIT_CONFIG_VALUE_0", "all");
}
}