I would like to use the nix crate in a project.
However, this project also has an acceptable alternative implementation for OSX and Windows, where I would like to use a different crate.
What is the current way of expressing that I only want nix in Linux platforms?
There's two steps you need to make a dependency completely target-specific.
First, you need to specify this in your Cargo.toml, like so:
[target.'cfg(target_os = "linux")'.dependencies]
nix = "0.5"
This will make Cargo only include the dependency when that configuration is active. However, this means that on non-Linux OS, you'll get a compile error for every spot you use nix in your code. To remedy this, annotate those usages with a cfg attribute, like so:
#[cfg(target_os = "linux")]
use nix::foo;
Of course that has rippling effects as now other code using those items fails to compile as the import, function, module or whatever doesn't exist on non-Linux. One common way to deal with that is to put all usages of nix into one function and use a no-op function on all other OSes. For example:
#[cfg(target_os = "linux")]
fn do_stuff() {
nix::do_something();
}
#[cfg(not(target_os = "linux"))]
fn do_stuff() {}
fn main() {
do_stuff();
}
With this, on all platforms, the function do_stuff exists and can be called. Of course, you have to decide for yourself what the function should do on non Linux.
Related
Is it possible to somehow detect in a crate that it's used in proc_macro and include some items based on that?
Let's say I have a token_parser crate with a Token enum:
pub struct Group;
pub struct Ident;
pub struct Punct;
pub struct Literal;
pub enum Token {
Group(Group),
Ident(Ident),
Punct(Punct),
Literal(Literal)
}
It's intended to be a wrapper for a proc_macro::TokenTree, so I want to be able to use it inside a proc_macro crates. I don't want to manualy implement a converting logic in every crate, so I want something like this:
#[cfg(proc_macro)]
impl From<proc_macro::TokenTree> for Token {
fn from(token: proc_macro::TokenTree) -> Self
{
todo!()
}
}
while still having an option to use token_parser crate in normal crates.
P.S I'm aware of proc_macro2 crate. I will probably use it (or even syn) in the end, for now I'm just trying to understand how to do something like that myself properly.
There are primarily two ways I would reach for based on how I want to enable such functionality.
feature for project-based enabling
If you want it only available when opted for, that's a fantastic case to use a cargo feature. Crates that want to use such functionality can then choose to enable this feature while other crates can choose to not enable the feature. Whether this feature should be default typically depends on how the library author believes it should/is used most of the time.
cfg for platform-based enabling
As you may have seen from reading the proc_macro2 source, they conditionally enable a cfg in their build script1. On the wasm32 platform target it is disabled, otherwise it is enabled. This way is very useful in cases where enabling functionality mostly depends on the platform.
Recently, I started to learn rust. I'm currently at section 7.4 (bringing paths into scope). Tried hard, but I can't understand the purpose of self::some_sort_of_identifier in rust. Would you please explain what is the difference between use self::module_name::function_name and use module_name::function_name? I tried both and they both worked as expected in the example below:
mod my_mod {
pub fn func() {
print!("I'm here!");
}
}
use my_mod::func;
fn main() {
func();
}
Running this program, as expected, I can see this statement printed into the terminal:
I'm here
And this program here gives me exactly the same results and the rust compiler doesn't complain about anything:
mod my_mod {
pub fn func() {
print!("I'm here!");
}
}
use self::my_mod::func;
fn main() {
func();
}
So, is self:: useless in rust? Why should I even use self::my_mod::my_function(); when I can directly call it like so: my_mod::my_function();.
Are there any cases in which they might defer?
For your use-case, it's mainly a relict from the 2015 rust edition.
In this edition the following code would not compile:
use my_mod::func;
mod my_mod {
use my_mod2::func2;
pub fn func() {
func2();
}
mod my_mod2 {
pub fn func2() {
print!("I'm here!");
}
}
}
fn main() {
func();
}
The compiler complains:
error[E0432]: unresolved import my_mod2
--> src\main.rs:4:9
|
| use my_mod2::func2;
| ^^^^^^^ help: a similar path exists: self::my_mod2
Why did it change? You can see the note about the path and module system changes here.
Rust 2018 simplifies and unifies path handling compared to Rust 2015. In Rust
2015, paths work differently in use declarations than they do
elsewhere. In particular, paths in use declarations would always start
from the crate root, while paths in other code implicitly started from
the current scope. Those differences didn't have any effect in the
top-level module, which meant that everything would seem
straightforward until working on a project large enough to have
submodules.
In Rust 2018, paths in use declarations and in other code work the
same way, both in the top-level module and in any submodule. You can
use a relative path from the current scope, a path starting from an
external crate name, or a path starting with crate, super, or self.
The blog post Anchored and Uniform Paths from the language team also underlines this
The uniformity is a really big advantage, and the specific feature we’re changing -
no longer having to use self:: - is something I know is a big
stumbling block for new users and a big annoyance for advanced users
(I’m always having to edit and recompile because I tried to import
from a submodule without using self).
The keyword itself however is still useful in use statments to refer to the current module in the path itself. Like
use std::io::{self, Read};
being the same as
use std::io;
use std::io::Read;
I'm working on a Rust executable project (audio codec + driver) that needs to compile to ARM Cortex-M, as well as ARM64 and X86 Linux platforms. We would like to have the project structure such that target specific code can be put in separate target specific files and directories, while target independent code kept in only one place. For example, we would like the top level main.rs to conditionally include arm64/main.rs, thumb/main.rs, and x86/main.rs files, where each target specific main.rs file is likely to do vastly different things.
My questions are:
What's the best way to do such a thing? Usually, in C/C++ this is trivial, but I don't know how to do this using cfg! macros.
Is there a way to specify these things directly in Cargo.toml instead of having them in Rust source files?
Any help, or pointers to projects that do this sort of thing is highly appreciated.
You can use the #[cfg(...)] attribute on anything, including functions, modules, and individual blocks of code.
The simplest way would be to create several main functions in one file, where each has a #[cfg(...)] attribute on it. The reference has a big list of configuration options you can use.
#[cfg(target_arch = "x86_64")]
fn main() {
println!("Hello from x86_64");
}
#[cfg(target_arch = "arm")]
fn main() {
println!("Hello from ARM");
}
But you asked about multiple files. In Rust, each file is a module, and you can attach the same cfg attribute to the module declaration. For example, you might have two arch-specific files:
// main_x86_64.rs
pub fn main() {
println!("Hello from x86_64");
}
// main_arm.rs
pub fn main() {
println!("Hello from ARM");
}
Then, in the real main function, conditionally compile one of them in and conditionally call one main function or the other.
// main.rs
#[cfg(target_arch = "x86_64")]
mod main_x86_64;
#[cfg(target_arch = "arm")]
mod main_arm;
#[cfg(target_arch = "x86_64")]
fn main() {
main_x86_64::main();
}
#[cfg(target_arch = "arm")]
fn main() {
main_arm::main();
}
If you're looking for a broader pattern, I'd point you to the way core organizes platform-specific things. There's an arch module that conditionally compiles in each platform's submodule on just that platform. You can see in the source code that there's a cfg attribute for each submodule so that it only gets compiled in on that platform.
I'm working on a custom test-runner for a custom target, that doesn't have libtest available. However I would like to use the TestDescAndFn struct, which is defined in libtest, in my own test-runner. TestDescAndFn provides information about the tests such as if it should panic or not, the name of the test and others, so having this information would be really useful compared to just using #[test_case].
Since the #[test] annotation is resolved at compile-time and simply generates a test harness that calls a (custom) test-runner I can define with #![test_runner(my_test_runner)], I don't think I really need libtest aside from TestDescAndFnand the enums it contains. Is there any "good" way to use the definitions from libtest for TestDescAndFn, TestDesc etc., without actually building libtest?
The test crate provides TestDescAndFn and is provided by the compiler. So, your custom framework crate might do something like this:
#![feature(test)]
// provided by compiler, no need to specify dependency in Cargo.toml
extern crate test;
use ::test::TestDescAndFn;
pub fn run_tests(tests: &[&TestDescAndFn]) {
// ...
}
and then your crate under test would do this:
#![feature(custom_test_frameworks)]
#![test_runner(::my_framework::run_tests)]
// crate with #[test] as normal
mod front_of_house {
pub mod hosting {
pub fn add_to_waitlist() {}
}
}
use self::front_of_house::hosting;
pub fn eat_at_restaurant() {
hosting::add_to_waitlist();
hosting::add_to_waitlist();
hosting::add_to_waitlist();
}
The code is from Rust Book. In this case, if using the relative path, why bother to use self? I find that use front_of_house::hosting works well here.
So, any necessary reason to introduce self here?
The outcome of use front_of_house::hosting depends on the context. If the crate root contains extern crate front_of_house or front_of_house is a dependency in Cargo.toml, this will refer to hosting in that crate. In your case, however, there is the local module front_of_house, which takes priority over external crates. Conveniently, it's located just before the code that uses it, so it's obvious that it's the actual module being used. In larger files, however, there is a chance that the source of a module is ambiguous, i.e. if there is a dependency named the same as a local module. In that case, the extra self adds clarity to the code, helping you differentiate between dependencies and local modules. If, in that case, you wanted to use the dependency, you'd use ::front_of_house::hosting, which unconditionally refers to the dependency and fails if there isn't one named like that.