As @DK mentioned this can be done with file!()
and env!("CARGO_MANIFEST_DIR")
.
Here's a macro for ease of use:
#[macro_export]
macro_rules! file_abs {
() => {
std::path::Path::new(env!("CARGO_MANIFEST_DIR").join(file!()))
};
}
Workspace Crates
This solution works for standalone crates but not workspaces. Assuming the crate is following the standard convention of crates/my_crate
the above macro would return something like this:
/playgroud/crates/my_crate/crates/my_crate/src/main.rs
This can be fixed by popping the first two components of the path returned by file!()
.
#[macro_export]
macro_rules! file_abs_workspace {
() => {
std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join(my_crate::pop_first_two_path_components(file!()))
};
}
pub fn pop_first_two_path_components(path: &str) -> PathBuf {
let mut components = std::path::Path::new(path).components();
components.next();
components.next();
components.as_path().to_path_buf()
}
Once you have the file you can get the parent like normal:
fn main(){
let dir = file_abs_workspace!().parent().unwrap();
println!("directory is: {:?}", dir);
}
Note i haven't yet tried this with a published workspace crate, I suspect in that case you'd need to switch back to file_abs!()
.