-
Notifications
You must be signed in to change notification settings - Fork 119
Crates with inner attributes in root module no longer build #229
Description
The Problem
The build system merged in #223 fails to build crates which have inner attributes in the root module.
Incomplete Example
// Inner attributes
#![no_std]
#![cfg_attr(
not(any(
feature = "example_feature"
)),
allow(dead_code, unused_extern_crates, unused_imports)
)]
// macro_use attribute is only allowed at the crate root.
#[macro_use]
extern crate lazy_static;
mod child_mod;
fn main() {
child_mod::do_something();
}
References
- include! macro fails if included file has top-level inner attributes rust-lang/rfcs#752
- Inner attributes cannot be specified in include! files rust-lang/rust#47995
- include! macro fails if included file has top-level inner attributes rust-lang/rust#18810
There is a proposed solution at the bottom of the issue. The following sections are included for discussion and documentation purposes.
Things that don't work.
Nested module with path attribute
For most uses of include!, this can be worked around by declaring an inner module and use the path attribute such at:
#[path="../real/main.rs"]
mod inner;
However, this solution is not feasible for our use case because:
- main is private and cannot be called
- Produces an error because
macro_useis no longer at the crate root. - Furthermore, although
no_stdwill compile, it will produce a warning since it is not at the crate level.
Embed main.rs into lib.rs
Simply moving the contents of the root module such as main.rs into lib.rs does not work. Since lib.rs is in a separate directory, it is unable to find any additional modules.
Hacky Solution
- Read the
main.rsand embed it in the generatedlib.rs - Extract troublesome statements like inner attributes and
macro_useand move them to top level. - Add
pubtomain. - Add
pathattribute so that child modules will be resolved.
Example:
// Inner attributes
#![no_std]
#![cfg_attr(
not(any(
feature = "example_feature"
)),
allow(dead_code, unused_extern_crates, unused_imports)
)]
// macro_use attribute is only allowed at the crate root.
#[macro_use]
extern crate lazy_static;
#[path="../real/"]
mod example {
mod child_mod;
// pub added to main
pub fn main() {
child_mod::do_something();
}
}
use example::*;
Proposed Solution - Create temporary file in user's source directory.
This solution is one I avoided experimenting with because it requires producing files outside of the target folder. However, it is the simplest. Because of is simplicity, it should be less fragile. I believe this solution should be implemented unless another one is proposed.
- Read root module such as
main.rs - Write it along with the current contents of cargo-apk's
lib.rsto a temporary file in the same folder asmain.rs. - Compile it.
Does anyone have thoughts about a better way to handle this case?
@mb64