【问题标题】:How do I use macro_rules to define a struct with optional #[cfg]?如何使用 macro_rules 定义带有可选 #[cfg] 的结构?
【发布时间】:2025-12-25 04:20:19
【问题描述】:

我正在编写一个从 C DLL 动态加载一些函数的 Rust 程序。我编写了一个辅助结构来加载它们:

// some function pointer definitions
// type func1_ptr = unsafe extern "C" func1() -> ();
// .....

pub struct FuncWrapper {
    pub func1: func1_type,
}

impl FuncWrapper {
    pub fn new() -> Self {
        Self {
            func1: unsafe { mem::transmute(load_function(lib, "func1")) },
        }
    }
}

由于要加载 100 多个函数,所以我编写了一个宏来完成这项繁琐的工作:

use paste::paste;

macro_rules! define_load_functions {
  ($v:vis $name:ident { $($func_name:ident),* $(,)?}) => {
  paste! {
    $v struct $name {
    $(
      pub $func_name: [<$func_name _ptr>],
    )*
    }

    impl $name {
      pub fn new() -> Self {
        Self {
          $(
          $func_name: unsafe {
            mem::transmute(load_function(ptr, stringify!($func_name)))
          },
          )*
        }
      }
    }
  }
  }
}

macro_rules! define_load_functions {
pub FuncWrapper {
    func1,
}
}

但是有些函数是平台相关的,我想给它们添加#[cfg(target_os)]。如何更改此宏以匹配可选的#[cfg]?我想让它在以下示例代码上工作:

macro_rules! define_load_functions {
pub FuncWrapper {
    func1,
    func2,
    #[cfg(target_os = "windows")] func3,
    #[cfg(target_os = "linux")] func4,
}
}

谢谢。

【问题讨论】:

    标签: rust macros


    【解决方案1】:

    以下方法有用吗?

    macro_rules! define_load_functions {
        (
            $struct_vis: vis $struct_name: ident {
                $( $(#[cfg($os_attr: meta)])? $fn_name: ident $(,)? )*
            }
        ) => {
            $struct_vis struct $struct_name {
                $(
                    $(#[cfg($os_attr)])?
                    $fn_name: String,
                )*
            }
            
            impl $struct_name {
                pub fn new() -> Self {
                    Self {
                        $(
                            $(#[cfg($os_attr)])?
                            $fn_name: "Example".to_owned(),
                        )*
                    }
                }
            }
        };
    }
    
    define_load_functions!(pub Example {
        func1,
        #[cfg(target_os = "linux")] func2,
        #[cfg(target_os = "windows")] func3,
        #[cfg(target_os = "macos")] func4,
        #[cfg(target_os = "linux")] func5,
        func6,
    });
    

    在基于 Linux 的系统上扩展上述宏会得到以下结果:

    pub struct Example {
        func1: String,
        #[cfg(target_os = "linux")]
        func2: String,
        #[cfg(target_os = "linux")]
        func5: String,
        func6: String,
    }
    
    impl Example {
        pub fn new() -> Self {
            Self {
                func1: "Example".to_owned(),
                #[cfg(target_os = "linux")]
                func2: "Example".to_owned(),
                #[cfg(target_os = "linux")]
                func5: "Example".to_owned(),
                func6: "Example".to_owned(),
            }
        }
    }
    

    【讨论】:

      最近更新 更多