feat(xtask): check wasm exports
This commit is contained in:
parent
aea3a4720a
commit
dcdd6ce2d2
3 changed files with 167 additions and 0 deletions
36
.github/workflows/wasm_exports.yml
vendored
Normal file
36
.github/workflows/wasm_exports.yml
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
name: Check WASM Exports
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- lib/include/tree_sitter/api.h
|
||||
- lib/binding_web/**
|
||||
push:
|
||||
branches: [master]
|
||||
paths:
|
||||
- lib/include/tree_sitter/api.h
|
||||
- lib/binding_rust/bindings.rs
|
||||
- lib/CMakeLists.txt
|
||||
|
||||
jobs:
|
||||
check-wasm-exports:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up stable Rust toolchain
|
||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Install wasm-objdump
|
||||
run: sudo apt-get update -y && sudo apt-get install -y wabt
|
||||
|
||||
- name: Build C library (make)
|
||||
run: make -j CFLAGS="$CFLAGS"
|
||||
env:
|
||||
CFLAGS: -g -Werror -Wall -Wextra -Wshadow -Wpedantic -Werror=incompatible-pointer-types
|
||||
|
||||
- name: Check WASM exports
|
||||
run: cargo xtask check-wasm-exports
|
||||
127
xtask/src/check_wasm_exports.rs
Normal file
127
xtask/src/check_wasm_exports.rs
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
use std::{
|
||||
collections::HashSet,
|
||||
io::BufRead,
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
|
||||
use crate::{bail_on_err, build_wasm::run_wasm, BuildWasm};
|
||||
|
||||
const EXCLUDES: [&str; 28] = [
|
||||
// Unneeded because the JS side has its own way of implementing it
|
||||
"ts_node_child_by_field_name",
|
||||
"ts_node_edit",
|
||||
// Precomputed and stored in the JS side
|
||||
"ts_node_type",
|
||||
"ts_node_grammar_type",
|
||||
"ts_node_eq",
|
||||
"ts_tree_cursor_current_field_name",
|
||||
"ts_lookahead_iterator_current_symbol_name",
|
||||
// Deprecated
|
||||
"ts_node_child_containing_descendant",
|
||||
// Not used in wasm
|
||||
"ts_init",
|
||||
"ts_set_allocator",
|
||||
"ts_parser_set_cancellation_flag",
|
||||
"ts_parser_cancellation_flag",
|
||||
"ts_parser_print_dot_graphs",
|
||||
"ts_tree_print_dot_graph",
|
||||
"ts_parser_set_wasm_store",
|
||||
"ts_parser_take_wasm_store",
|
||||
"ts_parser_language",
|
||||
"ts_node_language",
|
||||
"ts_tree_language",
|
||||
"ts_lookahead_iterator_language",
|
||||
"ts_parser_logger",
|
||||
"ts_parser_parse_string",
|
||||
"ts_parser_parse_string_encoding",
|
||||
// Query cursor is not managed by user in web bindings
|
||||
"ts_query_cursor_delete",
|
||||
"ts_query_cursor_timeout_micros",
|
||||
"ts_query_cursor_match_limit",
|
||||
"ts_query_cursor_remove_match",
|
||||
"ts_query_cursor_timeout_micros",
|
||||
];
|
||||
|
||||
pub fn run() -> Result<()> {
|
||||
// Build the wasm module with debug symbols for wasm-objdump
|
||||
run_wasm(&BuildWasm {
|
||||
debug: true,
|
||||
verbose: false,
|
||||
docker: false,
|
||||
})?;
|
||||
|
||||
let mut wasm_exports = include_str!("../../lib/binding_web/exports.txt")
|
||||
.lines()
|
||||
.map(|s| s.replace("_wasm", "").replace("byte", "index"))
|
||||
// remove leading and trailing quotes, trailing comma
|
||||
.map(|s| s[1..s.len() - 2].to_string())
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
// Run wasm-objdump to see symbols used internally in binding.c but not exposed in any way.
|
||||
let wasm_objdump = Command::new("wasm-objdump")
|
||||
.args([
|
||||
"--details",
|
||||
"lib/binding_web/tree-sitter.wasm",
|
||||
"--section",
|
||||
"Name",
|
||||
])
|
||||
.output()
|
||||
.expect("Failed to run wasm-objdump");
|
||||
bail_on_err(&wasm_objdump, "Failed to run wasm-objdump")?;
|
||||
|
||||
wasm_exports.extend(
|
||||
wasm_objdump
|
||||
.stdout
|
||||
.lines()
|
||||
.map_while(Result::ok)
|
||||
.skip_while(|line| !line.contains("- func"))
|
||||
.filter_map(|line| {
|
||||
if line.contains("func") {
|
||||
if let Some(function) = line.split_whitespace().nth(2).map(String::from) {
|
||||
let trimmed = function.trim_start_matches('<').trim_end_matches('>');
|
||||
if trimmed.starts_with("ts") && !trimmed.contains("__") {
|
||||
return Some(trimmed.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}),
|
||||
);
|
||||
|
||||
let nm_child = Command::new("nm")
|
||||
.arg("-W")
|
||||
.arg("-U")
|
||||
.arg("libtree-sitter.so")
|
||||
.stdout(Stdio::piped())
|
||||
.output()
|
||||
.expect("Failed to run nm");
|
||||
bail_on_err(&nm_child, "Failed to run nm")?;
|
||||
let export_reader = nm_child
|
||||
.stdout
|
||||
.lines()
|
||||
.map_while(Result::ok)
|
||||
.filter(|line| line.contains(" T "));
|
||||
|
||||
let exports = export_reader
|
||||
.filter_map(|line| line.split_whitespace().nth(2).map(String::from))
|
||||
.filter(|symbol| !EXCLUDES.contains(&symbol.as_str()))
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
let mut missing = exports
|
||||
.iter()
|
||||
.filter(|&symbol| !wasm_exports.contains(symbol))
|
||||
.map(|symbol| symbol.as_str())
|
||||
.collect::<Vec<_>>();
|
||||
missing.sort_unstable();
|
||||
|
||||
if !missing.is_empty() {
|
||||
Err(anyhow!(format!(
|
||||
"Unmatched wasm exports:\n{}",
|
||||
missing.join("\n")
|
||||
)))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
mod benchmark;
|
||||
mod build_wasm;
|
||||
mod bump;
|
||||
mod check_wasm_exports;
|
||||
mod clippy;
|
||||
mod fetch;
|
||||
mod generate;
|
||||
|
|
@ -28,6 +29,8 @@ enum Commands {
|
|||
BuildWasmStdlib,
|
||||
/// Bumps the version of the workspace.
|
||||
BumpVersion(BumpVersion),
|
||||
/// Checks that WASM exports are synced.
|
||||
CheckWasmExports,
|
||||
/// Runs `cargo clippy`.
|
||||
Clippy(Clippy),
|
||||
/// Fetches emscripten.
|
||||
|
|
@ -204,6 +207,7 @@ fn run() -> Result<()> {
|
|||
Commands::BuildWasm(build_wasm_options) => build_wasm::run_wasm(&build_wasm_options)?,
|
||||
Commands::BuildWasmStdlib => build_wasm::run_wasm_stdlib()?,
|
||||
Commands::BumpVersion(bump_options) => bump::run(bump_options)?,
|
||||
Commands::CheckWasmExports => check_wasm_exports::run()?,
|
||||
Commands::Clippy(clippy_options) => clippy::run(&clippy_options)?,
|
||||
Commands::FetchEmscripten => fetch::run_emscripten()?,
|
||||
Commands::FetchFixtures => fetch::run_fixtures()?,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue