基于proc_macro的条件编译:检测crate环境并按需实现代码
可以通过条件编译+可选依赖实现需求
你可以通过Rust的条件编译机制和可选依赖,让token_parser crate在特定环境下编译From<proc_macro::TokenTree>的实现,同时保证普通场景下的可用性。以下是具体实现方式:
1. 配置Cargo.toml
首先将proc-macro设为可选依赖,避免普通场景下引入不必要的依赖:
[dependencies] # 仅在需要时引入proc-macro依赖 proc-macro = { version = "1.0", optional = true }
如果需要让依赖方主动开启proc-macro支持(推荐,因为无法自动检测依赖方是否为proc-macro crate),可以添加一个feature:
[features] # 开启proc-macro转换支持 proc-macro-support = ["proc-macro"]
2. 编写条件编译的代码
根据你的需求选择对应的条件编译方式:
场景A:当token_parser自身是proc-macro crate时启用实现
如果你的token_parser本身需要作为proc-macro crate使用(即Cargo.toml中设置了proc-macro = true),直接使用内置的proc_macro cfg:
pub struct Group; pub struct Ident; pub struct Punct; pub struct Literal; pub enum Token { Group(Group), Ident(Ident), Punct(Punct), Literal(Literal) } // 仅当当前crate是proc-macro类型时编译该实现 #[cfg(proc_macro)] impl From<proc_macro::TokenTree> for Token { fn from(token: proc_macro::TokenTree) -> Self { match token { proc_macro::TokenTree::Group(_) => Token::Group(Group), proc_macro::TokenTree::Ident(_) => Token::Ident(Ident), proc_macro::TokenTree::Punct(_) => Token::Punct(Punct), proc_macro::TokenTree::Literal(_) => Token::Literal(Literal), } } }
场景B:当其他proc-macro crate依赖token_parser时启用实现
如果token_parser是普通库,需要依赖方主动开启proc-macro支持,使用feature条件编译:
pub struct Group; pub struct Ident; pub struct Punct; pub struct Literal; pub enum Token { Group(Group), Ident(Ident), Punct(Punct), Literal(Literal) } // 仅当开启proc-macro-support feature时编译该实现 #[cfg(feature = "proc-macro-support")] impl From<proc_macro::TokenTree> for Token { fn from(token: proc_macro::TokenTree) -> Self { match token { proc_macro::TokenTree::Group(_) => Token::Group(Group), proc_macro::TokenTree::Ident(_) => Token::Ident(Ident), proc_macro::TokenTree::Punct(_) => Token::Punct(Punct), proc_macro::TokenTree::Literal(_) => Token::Literal(Literal), } } }
此时,proc-macro crate依赖token_parser时,只需在其Cargo.toml中开启feature:
[dependencies] token_parser = { version = "0.1", features = ["proc-macro-support"] }
3. 普通场景的兼容性
因为proc-macro是可选依赖,且转换实现被条件编译包裹,普通crate依赖token_parser时不会引入proc-macro,也不会编译该实现,完全可以正常使用Token枚举。
注意事项
- Rust内置的
#[cfg(proc_macro)]仅针对当前crate的编译环境,无法自动检测依赖自己的crate是否为proc-macro类型。 - 如果你的
token_parser不需要作为proc-macro crate使用,推荐使用feature的方式,让依赖方主动开启功能,灵活性更高。
内容的提问来源于stack exchange,提问作者MaxCross
相关产品推荐
相关产品推荐

