How to make `include!` work with macros defined in external crates? - rust

When using serde in stable as recommended by the respective blog post, one will have to use the built-in include! macro to pull in a file generated by serde-codegen.
The file linked here shows this in a more complex example which can use rustc nightly as well as rustc stable.
However, as the docs of include! suggest, it does not behave hygienically.
What this means was unclear to me until I ran into the issue that macros defined in an external crate, yup-hyper-mock, were not defined at include-time. Some tests showed that even something like extern crate foo-bar-snoo-snoo; will not trigger an error at include-time, showing that it was not yet evaluated at all.
The problem arises from include! trying to expand macros, and failing if these are coming from external crates which haven't been evaluated yet.
An attempt of mine to define empty macros with the correct signature cause the include! macro to work, but the compile would fail later as include! would actually expand the macro right away, which was empty at the time of the include.
Is there a way to make include! work with macros defined in external crates? Alternatively, can you imagine a workaround to make my particular case work?
Personally I think include! should not expand macros at all, but leave that to the next compile step which should bring in external crates - maybe we are looking at a bug in rustc, but I am not sure about that.
How to reproduce
Please note that both stable and nightly compilers show the same issues.
git clone --branch syntex https://github.com/Byron/yup-oauth2
cd yup-oauth2
git reset --hard f59d97d
# build and test fail because 'include!' runs before crates are pulled
# in, but still expands macros
cargo build
cargo test
Meta
stable
➜ yup-oauth2 git:(syntex) rustc --version --verbose
rustc 1.0.0 (a59de37e9 2015-05-13) (built 2015-05-14)
binary: rustc
commit-hash: a59de37e99060162a2674e3ff45409ac73595c0e
commit-date: 2015-05-13
build-date: 2015-05-14
host: x86_64-apple-darwin
release: 1.0.0
nightly
➜ yup-oauth2 git:(syntex) rustc --version --verbose
rustc 1.2.0-nightly (2228ce10c 2015-06-09)
binary: rustc
commit-hash: 2228ce10c6d83c17b6346396aa7c7ef9082f1c04
commit-date: 2015-06-09
host: x86_64-apple-darwin
release: 1.2.0-nightly

Related

Cannot install xargo when using rust nightly - "non-string literals in attributes, or string literals in top-level positions, are experimental"

I'm using a specific Rust nightly build for CS 140E. When I run the commands
rustup default nightly-2018-01-09
rustup component add rust-src
cargo install xargo
I end up with libc failing to build:
error: non-string literals in attributes, or string literals in top-level positions, are experimental (see issue #34981)
--> ~/.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.58/src/macros.rs:78:15
It also mentions
= help: add #![feature(attr_literals)] to the crate attributes to enable
Which I've done, which brings me to more complex errors that I have less confidence to fix. Is a nightly build failing in this manner expected? I've also tried rustup default nightly and rustup default stable and they both fail for other reasons.

Run `rustc` to check a program without generating any files

As cargo check shows, it's often useful to check if your program is well-formed without actually generating code (an often pretty time-consuming task). I want to check a single (library) Rust file with rustc directly (I cannot use Cargo!).
cargo check apparently works by calling this:
rustc --emit=metadata -Z no-codegen
This only emits metadata, a .rmeta file. Cargo actually needs that to check crates dependent on the checked crate. In my case I really don't need the metadata file.
I tried the following:
rustc --crate-type=lib --emit=
rustc --crate-type=lib --emit=nothing
But both didn't work. I use --crate-type=lib because my file doesn't have a main function. I need a platform-independent solution (I don't just want to use it on my machine, but use it in a public script).
How do I make rustc not write a single file?
You can just skip the --emit flag.
The final command would then be: rustc -Z no-codegen rust.rs
To quote my own GitHub comment about this very question, there are a few options for stable Rust:
rustc --emit=mir -o /dev/null seems to work in 1.18 and newer, writing nothing. (--emit=mir is the only helpful --emit option—the others try to create silly files like /dev/null.foo0.rcgu.o, except --emit=dep-info, which does no checking.)
rustc -C extra-filename=-tmp -C linker=true (i.e. use /bin/true as a “linker”) seems to work in all versions, writing some intermediate files but cleaning them up.
rustc --out-dir=<new empty temporary directory> is less clever and therefore perhaps less likely to break?
Note that linker errors, if any, will not be found by the first two options (nor by the nightly-only -Zno-codegen option).

How to execute cargo test using the nightly channel?

I'm trying to run my tests with nightly Rust using Windows Powershell. I run cargo test in the directory, and I get
Compiling rustcraft v0.1.0 (file:///C:/Users/Phoenix/Desktop/Rust/rustcraft)
error[E0554]: #![feature] may not be used on the stable release channel
--> C:\Users\Phoenix\Desktop\Rust\rustcraft\src\main.rs:1:1
|
1 | #![feature(integer_atomics)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0554]: #![feature] may not be used on the stable release channel
--> C:\Users\Phoenix\Desktop\Rust\rustcraft\src\main.rs:2:1
|
2 | #![feature(collections)]
| ^^^^^^^^^^^^^^^^^^^^^^^^
Obviously, I have to tell Cargo to compile it on the nightly channel, but how? I can't find any reference to specifying a channel in the help section, or any website I've found.
The command line solution may help you to configure your IDE:
cargo +nightly test
Provided, of course, that you have the nightly channel installed. If not, perhaps install it with rustup install nightly (no need to switch to it, but check you're still on stable: rustup show).
The +<toolchain> functionality comes from rustup, the Rust toolchain manager. It works for both cargo +<toolchain> as well as rustc +<toolchain>.
In addition, you can use
rustup run <toolchain> <any arbitrary command goes here>
Since your project requires nightly features, you can change into the directory and run rustup override set <toolchain> to always use the nightly toolchain in that directory.
Create a file called rust-toolchain in your directory containing the name of the toolchain required (e.g. nightly). This has the safe effect as an override, but can be committed to source control.
See also:
Is it possible to have multiple coexisting Rust installations?

How can I tell Cargo to rebuild when a file included with the include_bytes macro is changed?

I am using the include_bytes! macro to compile a GLSL shader into a rust program. It seems that Cargo is unaware of this however: when I modify just the shader file and test it with cargo run the updated file is not compiled in. Manually touching the .rs file that includes the shader does work.
Do I need to add something to my Cargo.toml to explictly state this dependency?
Version info:
$ rustc --version && cargo --version
rustc 1.0.0-nightly (ecf8c64e1 2015-03-21) (built 2015-03-22)
cargo 0.0.1-pre-nightly (e689383 2015-03-16) (built 2015-03-16)
This has been fixed in rustc: https://github.com/rust-lang/rust/pull/24423
Cargo has no way currently to add a file to the list of 'watched' files for changes. It won't know about files included with include_bytes! because that would involve special-casing that macro specifically.

How to make Travis CI work with Rust 0.12.0 and Cargo?

I am trying to make Travis CI build and test the contents of my GitHub repository, which is compatible with Rust 0.12.0 and an older Cargo:
rustc 0.12.0 (ba4081a5a 2014-10-07 13:44:41 -0700)
cargo 0.0.1-pre-nightly (861c07f 2014-10-07 23:29:57 +0000)
I have specified Rust 0.12.0 in the .travis.yml:
language: rust
rust: 0.12.0
script:
- cargo build --verbose
- cargo test --verbose
- rustdoc --test README.md -L target
- cargo doc
The issue I seem to be hitting is that Travis will pick the latest Cargo nightly:
cargo 0.0.1-pre-nightly (fd5d7a9 2014-12-25 04:28:40 +0000)
But this newer version is incompatible with Rust 0.12.0, as it is now using --emit=dep-info where it used to use --dep-info:
--dep-info [FILENAME]
Output dependency info to <filename> after compiling,
in a format suitable for use by Makefiles
This gives rustc invocation errors, as the value for is --emit is invalid:
Running `rustc src/sqlite3.rs --crate-name sqlite3 --crate-type lib -g -C metadata=1c7080eec8c6f90d -C extra-filename=-1c7080eec8c6f90d --out-dir target/deps --emit=dep-info,link -L target/deps -L target/deps -Awarnings`
...
error: unknown emission type: `dep-info`
...
Could not compile `sqlite3`.
I have been looking at other repositories for how to get around this, but it seems they either do not use Cargo with 0.12.0 (which works with Travis) or hit the same issue, like here: https://travis-ci.org/eliovir/rust-ini
I have failed to find any repository that works with Travis, rust 0.12.0 and Cargo. If I can specify the version of Cargo somewhere, I would be able to get around this, but I have failed to find a way to do so in the .travis.yml file.
Of course, with Rust 1.0 coming up, I will just wait for it, if there is no obvious solution that I have overlooked :-)
I agree that tracking nightly is probably the best bet. If there are dependencies you rely on that aren't being updated, then maybe that's a sign that they wont be updated come 1.0 time, either!
All that being said, Travis does allow you to install things before your build. This is completely untested, but you might be able to do something like
before_script:
- wget https://static.rust-lang.org/dist/rust-0.12.0-x86_64-unknown-linux-gnu.tar.gz
- tar -xvf rust-0.12.0-x86_64-unknown-linux-gnu.tar.gz
- ./rust-0.12.0-x86_64-unknown-linux-gnu/install.sh --prefix /tmp/rust-0.12/
- export PATH=$PATH:$PWD/tmp/rust-0.12/bin
- export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/tmp/rust-0.12/lib
This would download Rust 0.12, unpack and install it somewhere writable (doesn't really matter where). Then you setup env vars to point out where Rust is. Do the same to download a compatible version of Cargo.
If Travis has a "bare" language pack, that would be the best. Otherwise you could try using the Rust buildpack, or maybe just anything else (to avoid dealing with multiple rustc versions).

Resources