Rust宏库manifest-dir-macros的使用:轻松获取Cargo.toml目录路径的宏工具
Rust宏库manifest-dir-macros的使用:轻松获取Cargo.toml目录路径的宏工具
Manifest Dir Macros
这个crate提供了函数式宏,可以在编译时检查或操作相对于CARGO_MANIFEST_DIR的路径。
示例
#[macro_use] extern crate manifest_dir_macros;
// 构建并打印各种路径
println!(path!("Cargo.toml")); // 获取Cargo.toml的完整路径
println!(path!("src/lib.rs")); // 获取src/lib.rs的完整路径
println!(path!("src", "lib.rs")); // 组合路径
println!(path!("src", "lib.rs", "/bin")); // 组合绝对路径
println!(path!("/usr")); // 直接使用绝对路径
// 路径检查
println!(exist_path!("Cargo.toml")); // 检查文件是否存在
println!(directory_path!("src")); // 检查是否为目录
println!(not_directory_path!("Cargo.toml")); // 检查是否不是目录
println!(file_path!("Cargo.toml")); // 检查是否为文件
// 相对路径操作
println!(relative_path!("Cargo.toml")); // 获取相对于项目根目录的路径
println!(directory_relative_path!("src")); // 获取目录的相对路径
println!(not_directory_relative_path!("Cargo.toml")); // 获取非目录的相对路径
println!(file_relative_path!("Cargo.toml")); // 获取文件的相对路径
// 路径组件提取
println!(get_file_name!("src/lib.rs")); // 获取文件名
println!(get_file_name!(default = "main.rs", "/")); // 带默认值的文件名获取
println!(get_file_stem!("src/lib.rs")); // 获取文件主干名
println!(get_file_stem!(default = "lib", "/")); // 带默认值的文件主干名获取
println!(get_extension!("src/lib.rs")); // 获取文件扩展名
println!(get_extension!(default = "rs", "src/lib")); // 带默认值的扩展名获取
println!(get_parent!("src/lib.rs")); // 获取父目录
println!(get_parent!(default = "/home", "/")); // 带默认值的父目录获取
// mime_guess特性(可选)
#[cfg(feature = "mime_guess")]
{
println!(mime_guess!("src/lib.rs")); // 猜测文件MIME类型
println!(mime_guess!(default = "application/octet-stream", "Cargo.lock")); // 带默认值的MIME类型猜测
}
// tuple特性(可选)
#[cfg(feature = "tuple")]
{
println!(path!(("foo",))); // 使用元组作为路径参数
println!(path!(("foo", "bar"))); // 嵌套元组路径
println!(path!("a", ("foo", "bar"))); // 混合路径参数
println!(path!(("foo", "bar"), "a")); // 反向混合路径参数
println!(path!(("foo", "bar"), ("a", "b"))); // 多级元组路径
println!(path!(("foo", "bar", ("a", "b")), ("c", "d"))); // 深度嵌套元组路径
}
完整示例代码
// 在你的Cargo.toml中添加依赖项:
// manifest-dir-macros = "0.1.18"
// 示例代码:使用manifest-dir-macros获取项目文件路径
#[macro_use] extern crate manifest_dir_macros;
fn main() {
// 打印Cargo.toml的完整路径
println!("Cargo.toml路径: {}", path!("Cargo.toml"));
// 检查src/main.rs是否存在
if exist_path!("src/main.rs") {
println!("src/main.rs存在");
} else {
println!("src/main.rs不存在");
}
// 获取文件的父目录
let parent_dir = get_parent!("src/lib.rs");
println!("src/lib.rs的父目录: {}", parent_dir);
// 使用mime_guess特性获取文件MIME类型
#[cfg(feature = "mime_guess")]
{
println!("src/lib.rs的MIME类型: {}", mime_guess!("src/lib.rs"));
}
// 组合路径示例
let config_path = path!("config", "app.toml");
println!("配置文件路径: {}", config_path);
// 获取文件扩展名(带默认值)
let ext = get_extension!(default = "txt", "README");
println!("文件扩展名: {}", ext);
// 使用tuple特性组合路径
#[cfg(feature = "tuple")]
{
let assets_path = path!(("assets", "images"), "logo.png");
println!("资源文件路径: {}", assets_path);
}
}
许可证
MIT
1 回复
Rust宏库manifest-dir-macros使用指南
manifest-dir-macros
是一个实用的Rust宏库,用于在编译时获取项目的Cargo.toml
文件所在目录的绝对路径。
功能特点
- 提供
manifest_dir!()
宏,返回包含Cargo.toml目录的&'static str
- 编译时确定路径,无运行时开销
- 支持跨平台路径分隔符
安装方法
在Cargo.toml
中添加依赖:
[dependencies]
manifest-dir-macros = "0.1"
基本用法示例
use manifest_dir_macros::manifest_dir;
fn main() {
// 获取Cargo.toml所在目录路径
let project_dir = manifest_dir!();
println!("项目目录: {}", project_dir);
// 构建文件路径
let config_path = format!("{}/config/settings.toml", project_dir);
println!("配置文件路径: {}", config_path);
}
高级用法示例
与其他路径操作结合
use std::path::Path;
use manifest_dir_macros::manifest_dir;
fn load_config() {
let project_dir = manifest_dir!();
let config_path = Path::new(project_dir)
.join("config")
.join("app_config.json");
println!("完整配置路径: {}", config_path.display());
// 这里可以继续文件操作...
}
在测试中使用
#[cfg(test)]
mod tests {
use super::*;
use manifest_dir_macros::manifest_dir;
use std::fs;
#[test]
fn test_read_project_file() {
let test_data_path = format!("{}/tests/data/sample.txt", manifest_dir!());
let content = fs::read_to_string(test_data_path).expect("读取测试文件失败");
assert!(!content.is_empty());
}
}
完整示例demo
下面是一个综合使用manifest-dir-macros
的完整示例:
use manifest_dir_macros::manifest_dir;
use std::path::Path;
use std::fs;
fn main() {
// 1. 基本用法 - 获取项目目录
let project_dir = manifest_dir!();
println!("项目根目录: {}", project_dir);
// 2. 构建配置文件路径
let config_path = Path::new(project_dir)
.join("config")
.join("app.toml");
println!("配置文件路径: {}", config_path.display());
// 3. 检查文件是否存在
if config_path.exists() {
println!("配置文件存在");
} else {
println!("配置文件不存在,将创建默认配置");
// 创建config目录
fs::create_dir_all(config_path.parent().unwrap())
.expect("创建目录失败");
// 写入默认配置
fs::write(&config_path, "[default]\nkey = \"value\"")
.expect("写入配置文件失败");
}
// 4. 读取配置文件内容
let content = fs::read_to_string(&config_path)
.expect("读取配置文件失败");
println!("配置文件内容:\n{}", content);
}
#[cfg(test)]
mod tests {
use super::*;
use manifest_dir_macros::manifest_dir;
use std::fs;
#[test]
fn test_project_structure() {
// 测试项目目录结构
let project_dir = manifest_dir!();
assert!(Path::new(project_dir).join("Cargo.toml").exists());
assert!(Path::new(project_dir).join("src").exists());
}
#[test]
fn test_config_creation() {
// 测试配置文件创建
let test_config = Path::new(manifest_dir!())
.join("test_config.toml");
fs::write(&test_config, "test = true")
.expect("创建测试文件失败");
assert!(test_config.exists());
// 清理
fs::remove_file(&test_config)
.expect("删除测试文件失败");
}
}
注意事项
- 该宏返回的是编译时的路径,如果在不同机器上运行编译后的二进制文件,路径可能无效
- 对于可执行文件,考虑使用
std::env::current_exe()
获取运行时路径可能更合适 - 在库中使用时要小心,因为返回的是库项目的路径而不是主项目的路径
替代方案比较
与直接使用env!("CARGO_MANIFEST_DIR")
相比,这个宏提供了更简洁的语法,但功能上是等价的。
// 等效代码
let dir = env!("CARGO_MANIFEST_DIR");
manifest-dir-macros
只是对这个功能进行了简单的封装,使代码更易读。