How can I use a preprocessor in Rust to detect the version number? [duplicate] - rust

In C++, you could use something like __clang_version__. Is there something similar for Rust? I searched on the internet, but found nothing.

Not directly.
There is the rustc_version crate which tells you the version of rustc accessible on the command-line; this is designed to be used in a build script. There's also rustc_version_runtime which does something similar, but exposes the information as a runtime call (i.e. it detects the compiler version at compile time, but exposes it at runtime).
Standard disclaimer: be very careful writing anything that depends on compiler version. You should ideally only test for minimum versions for which features are supported using semver (which both of the above libraries support directly).

Related

How to extract nightly features used in a crate?

I want to extract all nightly features used by a crate for some research purposes.
Just to be clear, "nightly features" means codes like #![feature(...)]", but not crate provided optional features.
I tried using regex, and it works, but not accurate enough. cfg defined features may not be detected: #![cfg_attr(target_os = "macos", feature(...))].
So I turn to rustc compiler, I wish to modify some source code and print out what features crate uses. Now I'm still trying to find out how rustc deals with nightly features.
I hope someone can give me some tips and help about the process of rustc dealing with nightly features. I'm almost lost in codes.
Access to enabled features is done via rustc_session::Session::features. You can add code after they are set in rustc_interface, or look at how they're computed.
If you are at a later stage, you probably have access to the Session of the compiled crate. For example, TyCtxt has a sess() method (but also a features() method for direct access using the query system), and InferCtxt has a tcx member to access the TyCtxt.

what does this mean? "This is precisely because a library should not be deterministically recompiled for all users of the library."

I am new to Rust and is trying to understand the Cargo thing. I read in their FAQ about "why do binaries have Cargo.lock in version control, but not libraries?" but do not understand what this means.
"Users dependent on the library will not inspect the library’s Cargo.lock (even if it exists). This is precisely because a library should not be deterministically recompiled for all users of the library.
If a library ends up being used transitively by several dependencies, it’s likely that just a single copy of the library is desired (based on semver compatibility). If Cargo used all of the dependencies' Cargo.lock files, then multiple copies of the library could be used, and perhaps even a version conflict."
Appreciate if anyone can explain this. Thanks.
Say we have the following crates:
string-tools: this is some kind of commonly used library exporting a FastString struct that has faster implementations of some commonly needed functions. This library has two versions: 1.0.1 and 1.0.2. Version 1.0.2 was recently released.
database: a library to interface with your favorite database. It needs to do some string processing, and so it uses the string-tools library. One of the public methods in database has a signature like this:
fn get_username(id: u64) -> string_tools::FastString
The library has not had a chance or need to update to version 1.0.2 of string-tools - maybe it's unaffected by any of the bugs that were fixed in the patch. Consequently, it's Cargo.lock pins the version of string-tools to 1.0.1.
client: this library is for interacting with the client. It also depends on string-tools, and has a method like this:
fn show_name(name: string_tools::FastString)
This library is using the most recent version of string-tools, version 1.0.2. That is also the version in its Cargo.lock.
You would like to write a website that makes use of the database and client libraries. When you build your project, Cargo compiles each library's dependencies with the versions that are specified in the Cargo.lock. This means that database uses version 1.0.1 of string-tools and client uses version 1.0.2. But now imagine that you've written some code like this:
client::show_name(database::get_username(id));
This should compile. After all, the get_username function returns a string_tools::FastString, which is accepted by the show_name function. But it doesn't! That's because the FastString returned by get_username comes from version 1.0.1 of string_tools, while show_name wants a FastString from version 1.0.2! This can't work; after all, when the patch to string-tools for version 1.0.2 was written, it's possible that the author added an additional field to the type. There's nothing reasonable for the compiler to do.
This kind of issue is avoided by having Cargo ignore the Cargo.lock file on libraries. Instead what it does is compile both database and client against the 1.0.2 version of string_tools. This is correct because 1.0.1 and 1.0.2 are "semver compatible versions." That means it is ok to change out one for the other, things must still compile. Now you no longer get a compiler error, because the types that the one function returns and the other function accepts are no longer different.

Is it documented that Cargo can download and bundle multiple versions of the same crate?

By forking and playing with some code, I noticed that Cargo can download and bundle multiple versions of the same crate in the same project (native-tls 0.1.5 and 0.2.1, for example). I have wasted so much time by looking at the documentation of the wrong version.
I have looked for some information about this behaviour but I was not able to find anything. Is this documented somewhere?
Is there an easy way to determine/detect the version used by the code you're working on (current edited file)? Or can we tell Cargo to show some warnings/prevent the build if two versions the same crate are required?
It was a conscious decision when designing Rust to allow multiple versions of the same crate.
You have probably heard of Dependency Hell before, which occurs when 2 (or more) dependencies A and B have a common dependency C but each require a version which is incompatible with the other.
Rust was designed to ensure that this would not be an issue.
In general, cargo will attempt to find a common version which satisfies all requirements. As long as crate authors use SemVer correctly, and the requirements give enough leeway, a single version of the dependency can be computed and used successfully.
Sometimes, however, multiple versions of the same dependency are necessary, such as in your case since 0.1.x and 0.2.x are considered two different major versions. In this case, Rust has two features to allow the two versions to be used within the same binary:
a unique hash per version is appended to each symbol.
the type system considers the same type Foo from two versions of C to be different types.
There is a limitation, of course. If a function of A returns an instance of C::Foo and you attempt to pass it to a function of B, the compiler will refuse it (it considers the two types to be different). This is an intractable problem1.
Anytime the dependency on C is internal, or the use of C is isolated, it otherwise works automatically. As your experience shows, it is so seamless that the user may not even realize it is happening.
1 See the dtolnay trick that crate authors can use to allow some types to be interchangeable.
Cargo can indeed link multiple versions of some crate, but only one of those versions can be a direct dependency. The others are indirect references.
The direct reference is always the version referenced by Cargo.toml and on top-level of Cargo.lock (while the indirect references are in the dependencies subsections).
I am not sure how much it is documented, unfortunately.

What is the proper way to use bit array in Rust?

I need a class with functionality equal to vector<bool> in C++. The Rust documentation tells about BitVec, but use std::collections::BitVec causes Unresolved import error during compiling. According to a pull request, BitVec has been removed. Is there any adequate replacement for it?
There does not exist a dedicated bit-vector in the standard library and Vec<bool> is not specialized like C++'s vector<bool>. Rust advocates the use of external crates instead of building a huge standard library. The de-facto crate for this use case is bit-vec.
You appear to have found a link to an old standard library documentation: https://doc.rust-lang.org/1.2.0/std/collections/struct.BitVec.html. Note the 1.2.0 in the url! The current version of Rust is 1.25 (as of April 2018), which means that 1.2 is already more than two years old. Apart from that, BitVec is marked as unstable in the 1.2 docs; it was removed later.

Is there a way to detect the compiler version from within a Rust program?

In C++, you could use something like __clang_version__. Is there something similar for Rust? I searched on the internet, but found nothing.
Not directly.
There is the rustc_version crate which tells you the version of rustc accessible on the command-line; this is designed to be used in a build script. There's also rustc_version_runtime which does something similar, but exposes the information as a runtime call (i.e. it detects the compiler version at compile time, but exposes it at runtime).
Standard disclaimer: be very careful writing anything that depends on compiler version. You should ideally only test for minimum versions for which features are supported using semver (which both of the above libraries support directly).

Resources