Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parse no_mangle in cfg_attr #41

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,10 @@ When you define a feature like this
```toml
[features]
default = []
reload = ["dep:hot-lib-reloader"]
reload = ["lib/reload", "dep:hot-lib-reloader"]

[dependencies]
lib = { path = "lib" }
hot-lib-reloader = { version = "^0.6", optional = true }
```

Expand All @@ -283,13 +284,13 @@ use lib::*;
mod hot_lib { /*...*/ }
```

To run the static version just use `cargo run` the hot reloadable variant with `cargo run --features reload`.


### Disable `#[no-mangle]` in release mode
You can also conditionally use `#[no_mangle]` in your library:

To not pay a penalty for exposing functions using `#[no_mangle]` in release mode where everything is statically compiled (see previous tip) and no functions need to be exported, you can use the [no-mangle-if-debug attribute macro](./macro-no-mangle-if-debug). It will conditionally disable name mangling, depending on wether you build release or debug mode.
```rust
#[cfg_attr(feature = "reload", no_mangle)]
```

To run the static version just use `cargo run` the hot reloadable variant with `cargo run --features reload`.

### Use serialization or generic values for changing types

Expand Down
2 changes: 1 addition & 1 deletion examples/reload-feature/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ log = "*"

[features]
default = []
reload = ["dep:hot-lib-reloader"]
reload = ["lib/reload", "dep:hot-lib-reloader"]
4 changes: 4 additions & 0 deletions examples/reload-feature/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,7 @@ edition = "2021"

[lib]
crate-type = ["rlib", "dylib"]

[features]
default = []
reload = []
2 changes: 1 addition & 1 deletion examples/reload-feature/lib/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#[no_mangle]
#[cfg_attr(feature = "reload", no_mangle)]
pub fn do_stuff() {
println!("step called");
}
48 changes: 42 additions & 6 deletions macro/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,49 @@ pub fn read_functions_from_file(
// we can optionally assume that the function will be unmangled
// by other means than a direct attribute
if !ignore_no_mangle {
let no_mangle = fun
.attrs
.iter()
.filter_map(|attr| attr.path.get_ident())
.any(|ident| *ident == "no_mangle");
fn cfg_no_mangle<'a>(
mut cfg_items: impl Iterator<Item = &'a syn::NestedMeta>,
) -> bool {
let _predicate = cfg_items.next();
// TODO: return false if predicate is false
// false positives are unlikely, but can still compile error

if !no_mangle {
cfg_items.any(|meta| {
let meta = match meta {
syn::NestedMeta::Meta(m) => m,
_ => return false,
};
match meta {
syn::Meta::Path(path) => path.is_ident("no_mangle"),
syn::Meta::List(m) => cfg_no_mangle(m.nested.iter()),
_ => false,
}
})
}

fn is_no_mangle<'a>(
mut attrs: impl Iterator<Item = &'a syn::Attribute>,
) -> bool {
attrs.any(|attr| {
let ident = match attr.path.get_ident() {
Some(i) => i,
None => return false,
};
if *ident == "no_mangle" {
true
} else if *ident == "cfg_attr" {
let nested = match attr.parse_meta() {
Ok(syn::Meta::List(m)) => m.nested,
_ => return false,
};
cfg_no_mangle(nested.iter())
} else {
false
}
})
}

if !is_no_mangle(fun.attrs.iter()) {
continue;
};
}
Expand Down