Avoid unnecessary recompiles between debug & test builds

This makes development much quicker when switching back and forth
between compiling with RLS while editing and running tests with
`cargo test`.
This commit is contained in:
Max Brunsfeld 2019-11-14 13:34:21 -08:00
parent d45b98c7d9
commit 967da88371
4 changed files with 68 additions and 33 deletions

View file

@ -1,7 +1,7 @@
extern crate cc;
use std::{env, fs};
use std::path::{Path, PathBuf};
use std::{env, fs};
fn main() {
println!("cargo:rerun-if-env-changed=TREE_SITTER_STATIC_ANALYSIS");
@ -21,13 +21,12 @@ fn main() {
let mut config = cc::Build::new();
println!("cargo:rerun-if-env-changed=TREE_SITTER_TEST");
if env::var("TREE_SITTER_TEST").is_ok() {
println!("cargo:rerun-if-env-changed=DEBUG");
if env::var("DEBUG").map(|s| s == "true").unwrap_or(false) {
config.define("TREE_SITTER_TEST", "");
}
let src_path = Path::new("src");
for entry in fs::read_dir(&src_path).unwrap() {
let entry = entry.unwrap();
let path = src_path.join(entry.file_name());
@ -40,7 +39,6 @@ fn main() {
.include(src_path)
.include("include")
.file(src_path.join("lib.c"))
.file(Path::new("binding_rust").join("helper.c"))
.compile("tree-sitter");
}

View file

@ -1,17 +0,0 @@
#if defined(TREE_SITTER_TEST)
void ts_record_free(void *);
void rust_tree_sitter_free(void *p) {
ts_record_free(p);
}
#else
void free(void *);
void rust_tree_sitter_free(void *p) {
free(p);
}
#endif

View file

@ -1,8 +1,69 @@
use std::os::raw::c_void;
extern "C" {
#[link_name = "rust_tree_sitter_free"]
/// In *Release* builds, the C library links directly against `malloc` and `free`.
///
/// When freeing memory that was allocated by C code, use `free` directly.
#[cfg(not(test))]
#[link_name = "free"]
pub fn free_ptr(ptr: *mut c_void);
/// In *Test* builds, the C library is compiled with the `TREE_SITTER_TEST` macro,
/// so all calls to `malloc`, `free`, etc are linked against wrapper functions
/// called `ts_record_malloc`, `ts_record_free`, etc. These symbols are defined
/// in the `tree_sitter_cli::tests::helpers::allocations` module.
///
/// When freeing memory that was allocated by C code, use the `free` function
/// from that module.
#[cfg(test)]
#[link_name = "ts_record_free"]
pub fn free_ptr(ptr: *mut c_void);
/// In *Debug* builds, the C library is compiled the same as in test builds: using
/// the wrapper functions. This prevents the C library from having to be recompiled
/// constantly when switching between running tests and compiling with RLS.
///
/// But we don't want to actually record allocations when running the library in
/// debug mode, so we define symbols like `ts_record_malloc` to just delegate to
/// the normal `malloc` functions.
#[cfg(all(debug_assertions, not(test)))]
fn malloc(size: usize) -> *mut c_void;
#[cfg(all(debug_assertions, not(test)))]
fn calloc(count: usize, size: usize) -> *mut c_void;
#[cfg(all(debug_assertions, not(test)))]
fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void;
#[cfg(all(debug_assertions, not(test)))]
fn free(ptr: *mut c_void);
}
#[cfg(all(debug_assertions, not(test)))]
#[no_mangle]
unsafe extern "C" fn ts_record_malloc(size: usize) -> *const c_void {
malloc(size)
}
#[cfg(all(debug_assertions, not(test)))]
#[no_mangle]
unsafe extern "C" fn ts_record_calloc(count: usize, size: usize) -> *const c_void {
calloc(count, size)
}
#[cfg(all(debug_assertions, not(test)))]
#[no_mangle]
unsafe extern "C" fn ts_record_realloc(ptr: *mut c_void, size: usize) -> *const c_void {
realloc(ptr, size)
}
#[cfg(all(debug_assertions, not(test)))]
#[no_mangle]
unsafe extern "C" fn ts_record_free(ptr: *mut c_void) {
free(ptr)
}
#[cfg(all(debug_assertions, not(test)))]
#[no_mangle]
extern "C" fn ts_toggle_allocation_recording(_: bool) -> bool {
false
}
pub struct CBufferIter<T> {
@ -40,6 +101,8 @@ impl<T: Copy> ExactSizeIterator for CBufferIter<T> {}
impl<T> Drop for CBufferIter<T> {
fn drop(&mut self) {
unsafe { free_ptr(self.ptr as *mut c_void); }
unsafe {
free_ptr(self.ptr as *mut c_void);
}
}
}

View file

@ -18,18 +18,9 @@ typedef struct {
Length new_end;
} Edit;
#ifdef TREE_SITTER_TEST
#define TS_MAX_INLINE_TREE_LENGTH 2
#define TS_MAX_TREE_POOL_SIZE 0
#else
#define TS_MAX_INLINE_TREE_LENGTH UINT8_MAX
#define TS_MAX_TREE_POOL_SIZE 32
#endif
static const ExternalScannerState empty_state = {.length = 0, .short_data = {0}};
// ExternalScannerState