Is it possible to override the crate-type specified in Cargo.toml from the command line when calling cargo build? - rust

I want to generate a static library from a Rust project that I do not maintain. The project allows building a dynamic library — the Cargo.toml specifies crate-type = ["cdylib"].
Modifying the crate type in the file works, but I want to keep the unmodified original project as git submodule in my project if possible.
Is there is any flag that can be passed to the cargo build command to override this setting?

You can't override it, but you can supplement it. Use cargo rustc and pass --crate-type=staticlib directly to the compiler:
% cargo build
Compiling example v0.1.0 (/private/tmp/example)
Finished dev [unoptimized + debuginfo] target(s) in 0.31s
% find target -name '*.a'
% cargo rustc -- --crate-type=staticlib
Compiling example v0.1.0 (/private/tmp/example)
Finished dev [unoptimized + debuginfo] target(s) in 0.29s
% find target -name '*.a'
target/debug/deps/libexample.a

You can provide the crate-type, but you cannot override the one specified in your Cargo.toml:
$ cargo rustc -- --crate-type=staticlib
Compiling example v0.1.0 (/dev/tmp)
Finished dev [unoptimized + debuginfo] target(s) in 0.34s
There is an tracking issue to add a --crate-type override. In the meantime, a workaround is to use cargo-crate-type:
$ cargo install cargo-crate-type
$ cargo crate-type static
$ cargo build
Note that this command will alter your Cargo.toml

Since Rust 1.64 it is possible to override the crate-type for libraries and examples. Please note the missing -- compared to the other answers. The --crate-type flag in this answer is a cargo rustc flag, while in the other answers cargo rustc was used to pass an additional flag to rustc (as opposed to replacing the flag like cargo rustc does).
$ cargo rustc --crate-type=staticlib

Related

Compile and run rust programs without creating separate cargo projects

While going through Rust by Example,
I found myself creating a new cargo project for each program in the tutorial.
This quickly turned cumbersome.
Another strategy I tried was having my working directory structured like this:
src\
guessing_game.rs
main.rs
temp.rs
where main.rs contains
mod guessing_game;
mod temp;
/// Hello
fn main() {
// guessing_game::play();
println!("{}", temp::is_prime(6));
}
and cargo.toml contains
[package]
name = "rust_prog_dump"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.8.4"
I would call the target function in main() and comment out the others.
Do we have an alternative?
I have seen this issue and Jon Cairns' post.
I use Windows, hence that script does not work for me.
Do we have an alternative?
One alternative is to compile by hand using rustc directly, however that is annoying if you want dependencies.
An other alternative is to have multiple binaries in the crate, then you can select the binary to compile (and run) using --bin:
> cargo new multibin
Created binary (application) `multibin` package
> cd multibin
> mkdir src/bin
> echo 'fn main() { println!("test 1"); }' > src/bin/test1.rs
> echo 'fn main() { println!("test 2"); }' > src/bin/test2.rs
> echo 'fn main() { println!("primary"); }' >| src/main.rs
> cargo r
error: `cargo run` could not determine which binary to run. Use the `--bin` option to specify a binary, or the `default-run` manifest key.
available binaries: multibin, test1, test2
> cargo r --bin multibin
Compiling multibin v0.1.0 (/private/tmp/multibin)
Finished dev [unoptimized + debuginfo] target(s) in 0.44s
Running `target/debug/multibin`
primary
> cargo r --bin test1
Compiling multibin v0.1.0 (/private/tmp/multibin)
Finished dev [unoptimized + debuginfo] target(s) in 0.10s
Running `target/debug/test1`
test 1
> cargo r --bin test2
Compiling multibin v0.1.0 (/private/tmp/multibin)
Finished dev [unoptimized + debuginfo] target(s) in 0.10s
Running `target/debug/test2`
test 2
As you can see you can have a src/main.rs which will inherit the crate's name, but usually if you start having multiple binaries you put them all in src/bin.
A third alternative is to use something like cargo-script (by far the most convenient but long unmaintained and IIRC only compatible with edition 2015) or runner or something along those lines (there are probably others).
Masklinn's multiple-binary solution works like a charm (one-click execution) when paired with a good IDE.
With IntelliJ Community Edition + the Rust and TOML plugins
Choose the TOML file when prompted. (Only when importing the project)
Go to Project Settings > Modules. Mark src/bin as a Source folder.
Restart the IDE. You will have Current File as an available run configuration.
With VS Code + the Code Runner extension
Click on the Run|Debug button that appears above fn main(). Note that the regular Run Code shortcut (Ctrl+Alt+N) may not work if you have dependencies.

Difference between `cargo doc` and `cargo rustdoc`

According to doc.rust-lang.org
cargo rustdoc
build[s] a package's documentation, using specified custom flags
cargo doc
build[s] a package's documentation
What is the difference between the two? From what I understand cargo rustdoc is just like cargo doc, but it allows for more lints—for instance:
#![deny(rustdoc::broken_intra_doc_links)]
Is this correct? Oddly enough, cargo rustdoc will also fail in certain situations where cargo doc doesn't. For instance
some/folder on some-branch [$!] via 🦀 v1.60.0-nightly
❯ cargo doc
Finished dev [unoptimized + debuginfo] target(s) in 0.53s
some/folder on some-branch [$!] via 🦀 v1.60.0-nightly
❯ cargo rustdoc
error: manifest path `some/folder/Cargo.toml` is a virtual manifest, but this command requires running against an actual package in this workspace
Also, cargo doc does not support adding the -D option, whereas cargo rustdoc does.
❯ cargo doc -- -D rustdoc::broken_intra_doc_links
error: Found argument '-D' which wasn't expected, or isn't valid in this context
USAGE:
cargo doc [OPTIONS]
For more information try --help
Their relationship is like between cargo build and cargo rustc: cargo doc performs all the usual work, for an entire workspace, including dependencies (by default). cargo rustdoc allows you to pass flags directly to rustdoc, and only works for a single crate.
Here is the execution code for cargo rustdoc. Here is the code for cargo doc. The only differences is that cargo rustdoc always specify to not check dependencies while cargo doc allows you to choose (by default it does, but you can specify the flag --no-deps), and that cargo rustc allows you to pass flags directly to rustdoc with the flags after the --.

Is there an option to get rustc to show a "successful" message?

When I compile a program using rustc I usually get errors. Once I've eliminated the errors, I get no message which means that compile was successful.
Is there an option to get rustc to show a "successful" message? It would be nice to see positive feedback.
Most Rust programmers don't invoke rustc directly, but instead do it through cargo, which prints a green success message for each crate that is compiled:
$ cargo build
Compiling cfg-if v0.1.10
Compiling lazy_static v1.4.0
Compiling bytes v0.5.6
Compiling mycrate v0.2.0 (/dev/rust/mycrate)
Finished dev [unoptimized + debuginfo] target(s) in 13.17s
You will also get a progress bar tracking the build process:
$ cargo build
Compiling cfg-if v0.1.10
Compiling lazy_static v1.4.0
Building [====================> ] 3/4: bytes
rustc is more bare-bones and does not output any success messages. However, you can use && to print a message manually if the compilation was successful:
$ rustc main.rs && echo "Compiled successfully"
Compiled successfully
If you want to get even more fancy, you can use ASCII escape codes to make the message green!
$ rustc main.rs && echo "\033[0;32mCompiled successfully"
Compiled successfully # <- this is green!

How can you compile a Rust library to target asm.js?

I've got a Rust library with the following usual structure:
Cargo.toml
src
|--lib.rs
.cargo
|--config (specifies target=asmjs-unknown-emscripten)
target
|......
When I do cargo build, I get a new directory under target called asmjs-unknown-emscripten, but the .js files that I'd expect are not there.
As this user notes, you've got to do something special to export functions to asm.js besides marking them public:
Basically you have this boilerplate right now:
#[link_args = "-s EXPORTED_FUNCTIONS=['_hello_world']"]
extern {}
fn main() {}
#[no_mangle]
pub extern fn hello_world(n: c_int) -> c_int {
n + 1
}
Then you can use this in your javascript to access and call the function:
var hello_world = cwrap('hello_world', 'number', ['number']);
console.log(hello_world(41));
However, Rust complains about the #[link_args...] directive as deprecated. Is there any documentation out there that can explain how this works?
Very interesting question! I was running into similar dependency issues with fable.
I have checked Compiling Rust to your Browser - Call from JavaScript, Advanced Linking - Link args and How to pass cargo linker args however was not able to use cargo in the same way as rustc --target asmjs-unknown-emscripten call-into-lib.rs.
The closer I was able to get was to run both cargo and rustc like
cd lib1
cargo build --target asmjs-unknown-emscripten
rustc --target=asmjs-unknown-emscripten src\lib.rs
cd ..
cd lib2
cargo build --target asmjs-unknown-emscripten
rustc --target=asmjs-unknown-emscripten src\lib.rs --extern lib1=..\lib1\target\asmjs-unknown-emscripten\debug\liblib1.rlib
cd ..
cd lib3
cargo build --target asmjs-unknown-emscripten
rem rustc --target=asmjs-unknown-emscripten src\lib.rs --extern webplatform=..\lib3\target\asmjs-unknown-emscripten\debug\deps\libwebplatform-80d107ece17b262d.rlib
rem the line above fails with "error[E0460]: found possibly newer version of crate `libc` which `webplatform` depends on"
cd ..
cd app
cargo build --target asmjs-unknown-emscripten
cd ..
see the so-41492672-rust-js-structure. It allows to have several libraries that compile together to the JavaScript in the final application.
I still think some manual linking would help. Would be interested to know.
P.S. to see what rustc uses to link, you can pass -Z print-link-args to it.

How to emit LLVM-IR from Cargo

How can I get cargo to emit LLVM-IR instead of a binary for my project? I know that you can use the --emit=llvm-ir flag in rustc, but I've read some Github issues that show it's impossible to pass arbitrary compiler flags to cargo.
Is there any way I can get cargo to emit LLVM-IR directly?
There is cargo rustc to pass arbitrary compiler flags through Cargo to rustc. So I think:
cargo rustc -- --emit=llvm-ir
is what you want!
This will genarate a ll file in target\debug\deps\.
EDIT: You should use Jacob's answer instead; a lot easier and less hacky.
Build the project with cargo normally but add on the -v flag to show verbose output. The command will have a result like this:
casey#casey-ubuntu:~/Documents/project$ cargo build -v
Fresh aster v0.22.1
Fresh num-traits v0.1.34
Fresh itoa v0.1.1
...
Compiling project v0.1.0 (file:///home/casey/Documents/project)
Running `rustc src/main.rs --crate-name ...`
Finished debug [unoptimized + debuginfo] target(s) in 3.54 secs
If the command produces no output, make a change somewhere in your project code to trick the compiler into rebuilding it, since it will only rebuild if it detects a change in one of the files.
Copy the rustc command from inside the ` markers on the line starting with "Running `rustc..." and append --emit=llvm-ir to it.
This will produce a .ll file in your /target/debug folder.

Resources