fish-shell/fish-rust/build.rs
Mahmoud Al-Qudsi ce559bc20e Port fd_monitor (and its needed components)
I needed to rename some types already ported to rust so they don't clash with
their still-extant cpp counterparts. Helper ffi functions added to avoid needing
to dynamically allocate an FdMonitorItem for every fd (we use dozens per basic
prompt).

I ported some functions from cpp to rust that are used only in the backend but
without removing their existing cpp counterparts so cpp code can continue to use
their version of them (`wperror` and `make_detached_pthread`).

I ran into issues porting line-by-line logic because rust inverts the behavior
of `std::remove_if(..)` by making it (basically) `Vec::retain_if(..)` so I
replaced bools with an explict enum to make everything clearer.

I'll port the cpp tests for this separately, for now they're using ffi.

Porting closures was ugly. It's nothing hard, but it's very ugly as now each
capturing lambda has been changed into an explicit struct that contains its
parameters (that needs to be dynamically allocated), a standalone callback
(member) function to replace the lambda contents, and a separate trampoline
function to call it from rust over the shared C abi (not really relevant to
x86_64 w/ its single calling convention but probably needed on other platforms).

I don't like that `fd_monitor.rs` has its own `c_void`. I couldn't find a way to
move that to `ffi.rs` but still get cxx bridge to consider it a shared POD.
Every time I moved it to a different module, it would consider it to be an
opaque rust type instead. I worry this means we're going to have multiple
`c_void1`, `c_void2`, etc. types as we continue to port code to use function
pointers.

Also, rust treats raw pointers as foreign so you can't do `impl Send for * const
Foo` even if `Foo` is from the same module. That necessitated a wrapper type
(`void_ptr`) that implements `Send` and `Sync` so we can move stuff between
threads.

The code in fd_monitor_t has been split into two objects, one that is used by
the caller and a separate one associated with the background thread (this is
made nice and clean by rust's ownership model). Objects not needed under the
lock (i.e. accessed by the background thread exclusively) were moved to the
separate `BackgroundFdMonitor` type.
2023-02-19 15:42:03 -06:00

58 lines
2.1 KiB
Rust

fn main() -> miette::Result<()> {
let rust_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Env var CARGO_MANIFEST_DIR missing");
let target_dir =
std::env::var("FISH_RUST_TARGET_DIR").unwrap_or(format!("{}/{}", rust_dir, "target/"));
let fish_src_dir = format!("{}/{}", rust_dir, "../src/");
// Where cxx emits its header.
let cxx_include_dir = format!("{}/{}", target_dir, "cxxbridge/rust/");
// If FISH_BUILD_DIR is given by CMake, then use it; otherwise assume it's at ../build.
let fish_build_dir =
std::env::var("FISH_BUILD_DIR").unwrap_or(format!("{}/{}", rust_dir, "../build/"));
// Where autocxx should put its stuff.
let autocxx_gen_dir = std::env::var("FISH_AUTOCXX_GEN_DIR")
.unwrap_or(format!("{}/{}", fish_build_dir, "fish-autocxx-gen/"));
// Emit cxx junk.
// This allows "Rust to be used from C++"
// This must come before autocxx so that cxx can emit its cxx.h header.
let source_files = vec![
"src/fd_monitor.rs",
"src/fd_readable_set.rs",
"src/fds.rs",
"src/ffi_init.rs",
"src/ffi_tests.rs",
"src/future_feature_flags.rs",
"src/parse_constants.rs",
"src/redirection.rs",
"src/smoke.rs",
"src/timer.rs",
"src/tokenizer.rs",
"src/topic_monitor.rs",
"src/util.rs",
"src/builtins/shared.rs",
];
cxx_build::bridges(&source_files)
.flag_if_supported("-std=c++11")
.include(&fish_src_dir)
.include(&fish_build_dir) // For config.h
.include(&cxx_include_dir) // For cxx.h
.compile("fish-rust");
// Emit autocxx junk.
// This allows "C++ to be used from Rust."
let include_paths = [&fish_src_dir, &fish_build_dir, &cxx_include_dir];
let mut b = autocxx_build::Builder::new("src/ffi.rs", include_paths)
.custom_gendir(autocxx_gen_dir.into())
.build()?;
b.flag_if_supported("-std=c++11")
.compile("fish-rust-autocxx");
for file in source_files {
println!("cargo:rerun-if-changed={file}");
}
Ok(())
}