What the difference between Cargo.toml and .cargo/config.toml - rust

I am learning to write a kernel by using Rust.
I added [dependencies] bootloader = "0.9.8" to .cargo/config.toml, but I got an error.
I forgot the specific error, but when I move [dependencies] bootloader = "0.9.8" to Cargo.toml and then run "cargo bootimage" on terminal, everything goes well.

Cargo.toml is where you put everything your project need. Dependencies, project details, project settings etc..
cargo/config.toml is a configuration file for Cargo. You usually don't need to touch it, and it usually uses more advanced things. It can be configured per project, although also globally. It sets for example what commands Cargo will run, what environment variables it will set, etc..
All details about both are in the documentation - Cargo.toml, config.toml.

Related

How to install a Rust dependency in an environment with no internet?

I would like to use the tango client crate for a Rust project at work, however the environment that I will be developing this in does not have direct access to the internet. This means that the standard method of adding the dependency to Cargo.toml and running cargo build fails due to a network error.
The environment doesn't prevent me from copying data downloaded to an internet-connected computer, and so I was hoping that there would be a way for me to package the necessary files locally, and then point Cargo.toml to that location.
Is this possible? If so, how?
Answering my own question, thanks to a tip in a comment from #Dogbert.
The trick was to use cargo vendor on the machine that has an internet connection. This will produce a directory called vendor that can be transferred to the other environment. On that environment, and within the directory from which you will run cargo build, create a new file in .cargo/config.
[source]
[source.local_vendor]
directory = "vendor"
[source.crates-io]
replace-with = "local_vendor"
Once you've done this, then cargo build should work.

Adding Pallets to Substrate

This is a very basic question, but I am following the "nicks" tutorial from the Substrate network, and it's not very clear how - after I have added the pallet - I install or "pull in" these dependencies so I can inspect the code. I was expecting something like node_modules folder where everything is put once you run npm i, but that is a different environment. I have run cargo build but to no avail. Please advise.
When you add dependency in Cargo.toml, by default, the actual dependency will download and store on global Cargo registry $HOME/.cargo/ and specify the version in Cargo.lock inside project directory, not the actual dependency.
For a tutorial on Substrate, after adding Nick's pallet and running cargo build, you can check the code of downloaded pallet_nick in $HOME/.cargo/. The easiest way is to download rust_analyzer plugin to your VSCode and CRTL + Click to the dependency name inside Cargo.toml, it will take you to the library.

What does "manifest path is a virtual manifest, but this command requires running against an actual package" mean?

I'm trying to build a Rust project (xray). When running cargo run I get the following error message
error: manifest path D:\xray\building\xray\Cargo.toml is a virtual
manifest, but this command requires running against an actual package
in this workspace
What exactly does this mean and how can it be solved? I'm using Cargo version 0.25.0 and Rust version 1.24.1.
Your Cargo.toml is a virtual manifest.
In workspace manifests, if the package table is present, the workspace root crate will be treated as a normal package, as well as a workspace. If the package table is not present in a workspace manifest, it is called a virtual manifest.
When working with virtual manifests, package-related cargo commands, like cargo build, won't be available anymore. But, most of such commands support the --all option, will execute the command for all the non-virtual manifest in the workspace.
cargo run does not work, because cargo doesn't know what to run. There are two options:
--manifest-path <PATH>: Path to Cargo.toml of the crate you want to run.
-p, --package <SPEC>: Package you want to run.
In your case it's probably cargo run --package xray_cli
the manifest has both package and workspace sections can't works. please check the Cargo.toml and remove package from it.
Virtual Manifest is new concepts, please reading docs to familiar it. Hope it values for you.

How can I force `build.rs` to run again without cleaning my whole project?

How can I force build.rs to run again without cleaning my whole project? I checked cargo build --help but I couldn't find anything related to build.rs.
If you print
"cargo:rerun-if-changed=<FILE>"
the build will be triggered every time the file has changed.
rerun-if-changed=PATH is a path to a file or directory which indicates that the build script should be re-run if it changes (detected by a more-recent last-modified timestamp on the file). Normally build scripts are re-run if any file inside the crate root changes, but this can be used to scope changes to just a small set of files. -- source
I'm not aware of a solution without changing a file manually (I just put a whitespace anywhere in my build.rs, it will be removed by rustfmt though).
I have several buildscripts in my projects, and mostly these two lines give me a nice solution:
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=path/to/Cargo.lock");
but I guess you are looking for a command rustc/cargo command. Anyway, you can put in a small script, which will edit a certain file, which will trigger the build-process.
Register build.rs as a crate's bin target:
Add this to your Cargo.toml file:
[package]
edition = "2018"
build = "build.rs"
[[bin]]
name = "force-build"
path = "build.rs"
required-features = ["build_deps"] # only needed for build-dependencies
If you have any [build-dependencies] (e.g. some_crate = "1.2.3"), you need to add those to (the main) [dependencies] (sadly no [bin-dependencies] as of yet), but you can make them optional:
[dependencies]
some_crate = { version = "1.2.3", optional = true }
[features]
build_deps = ["some_crate"]
Then you can run the build script with:
$ cargo run --bin force-build --features build_deps
(or $ cargo run --bin force-build when no [build-dependencies])
You can even disable the automatic call of the build script by replacing the build = "build.rs" line in Cargo.toml with build = false
Note: since the OUT_DIR env var is not present for bin targets, if your build.rs script uses env!("OUT_DIR"), you may "fix this" by using concat!(env!("CARGO_MANIFEST_DIR"), "/target/") instead.
If build.rs changes, Cargo already rebuilds the project:
Note that if the build script itself (or one of its dependencies) changes, then it's rebuilt and rerun unconditionally, so cargo:rerun-if-changed=build.rs is almost always redundant (unless you want to ignore changes in all other files except for build.rs). doc
On Linux, I will just do touch build.rs && cargo build. For Windows, see Windows equivalent of the Linux command 'touch'?
If you got target under gitignore (which you should) this might be useful for any file changes when you're developing and testing the build script.
if Path::new(".git/HEAD").exists() {
println!("cargo:rerun-if-changed=.git/HEAD");
}
if you're trying to rebuild based on non-rust or include!() files that might've changed, you can use
const _: &[u8] = include_bytes!("foobar.baz");
to ensure that any changes to those files will trigger a new build. pretty sure this solution adds neither time nor filesize.
you can shove this into a macro too, so its easy to do a bunch of files.
macro_rules! build_on{($file:literal) => {
const _: &[u8] = include_bytes!($file);
}
build_on!("foobar.baz");

How to package source code from outside the project directory with Cargo?

I am trying to create Rust bindings for the C++ library cryptominisat. The actual code works, but I'm not sure how to properly package it up with Cargo.
The git repository looks like
src/
c++ code here
.gitignore
readme, etc.
I added a rust directory, and created my Cargo project inside of it like so
rust/
cryptominisat/
Cargo.toml
build.rs
src/
rust code here
src/
c++ code here
.gitignore
readme, etc.
Unfortunately, cargo package doesn't seem to want to package up anything outside of the rust/cryptominisat directory, which means it doesn't include the C++ code needed to actually build the library. What can I do? I don't want to move the entire repository into the rust directory if I can avoid it, since that would make it impossible to merge upstream.
The way it's generally solved:
Use a git submodule (or a script run before publishing) to embed a copy of the C++ repo inside the Rust repo (e.g. in rust/cryptominisat/vendor/). During development you could use a symlink instead to avoid having two copies of the C++ code.
Use build.rs to download a tarball/clone/rsync the code at build time. You can dump it into OUT_DIR env var specified by Cargo to avoid polluting user-visible directories.
Make the C++ code a system-level library. The Rust package would not build it, but expect it's already installed, and only search for it and specify link flags for it. That's how most *-sys crates work.

Resources