Rust宏库manifest-dir-macros的使用:轻松获取Cargo.toml目录路径的宏工具

Rust宏库manifest-dir-macros的使用:轻松获取Cargo.toml目录路径的宏工具

Manifest Dir Macros

CI状态

这个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("删除测试文件失败");
    }
}

注意事项

  1. 该宏返回的是编译时的路径,如果在不同机器上运行编译后的二进制文件,路径可能无效
  2. 对于可执行文件,考虑使用std::env::current_exe()获取运行时路径可能更合适
  3. 在库中使用时要小心,因为返回的是库项目的路径而不是主项目的路径

替代方案比较

与直接使用env!("CARGO_MANIFEST_DIR")相比,这个宏提供了更简洁的语法,但功能上是等价的。

// 等效代码
let dir = env!("CARGO_MANIFEST_DIR");

manifest-dir-macros只是对这个功能进行了简单的封装,使代码更易读。

回到顶部