How to compile to both wasm and binary in a Rust crate? - rust

I'm writing the back-end for a web application and would like to reuse some logic for client-side. I want to use wasm to generate a library which Javascript can use. Suppose the logic is in lib.rs. What should I do, so that:
The back-end can import and use the code in lib.rs as normal, also cargo build generates a binary as expected.
Rust generates a wasm library for lib.rs
I tried adding these to my cargo file (by following this: Rust package with both a library and a binary?):
[lib]
crate-type = ["cdylib", "rlib"]
[[bin]]
name = "mybin"
path = "src/main.rs"
But it seems like cargo is building my binary for the browser, so it is missing all the sys crate.

You can ask for only your library to be built using the --lib option.
cargo build --lib --target wasm32-unknown-unknown

So my current approach is to create a separate package for lib.rs and use it as a dependency for the back-end, as outlined in here:
What is an idiomatic way to have shared utility functions for integration tests and benchmarks?
It seems to work well enough.

Related

rust libraries with cargo (rlib)

I am trying to create a library in rust to be used with rust executables. In C you can just create your .a or .so (or .lib or .dll on windows) and use tools like CMake to link everything, however rust does not seem to have this kind of infrastructure?
It is possible to make an executable with cargo (cargo new ) and create a library by adding the --lib flag (cargo new --lib), but then how would you use the resulting .rlib file (from the library cargo project)? I managed to link the .rlib file as follows:
rustc main.rs --extern foo=libfoo.rlib
and that works beautifully, though, I am not interested in writing a thousand rustc commands to build the final executable (which depends on the .rlib) if there is cargo that can do that for you. I tried working with a build script (which works perfectly for any C library, static or dynamic), but if I try it with the .rlib file, cargo says that it cannot find "foo" (-lfoo), the build script:
fn main() {
println!("cargo:rustc-link-search=.");
println!("cargo:rustc-link-lib=foo");
}
I tried replacing the path (search) to different directories (whilst also moving the .rlib file to the correct directory), also tried different combinations of libfoo, libfoo.rlib, ... (note that for the C libaries, foo is sufficient).
So my question really is: How can you create a rust library for private use, and how do you use it with a rust executable in a proper way, avoiding manual rustc commands? Are there tools that do this? Am I missing something in the build script? Perhaps there exists something like CMake for rust?
I suppose it is possible to just create a C interface over the rust code and compile another C project as that does work with cargo.
I do NOT want to publish the code to crates.io as I want this library strictly for private use.
Cargo does not support using pre-compiled .rlibs. Cargo is designed to compile programs fully from source (not counting native libraries).
How can you create a rust library for private use … I do NOT want to publish the code to crates.io as I want this library strictly for private use.
To use a private library, you write a dependency using a path or git dependency (or use a private package registry, but that's more work to set up).
[dependencies]
my-lib-a = { path = "../my-lib-a/" }
my-lib-b = { git = "https://my-git-host.example/my-lib-b", branch = "stable" }
Your private library is now compiled exactly like a “public” one.

How to use ext4 Rust Crate [duplicate]

I'm trying to work with the rust-http library, and I'd like to use it as the basis for a small project.
I have no idea how to use something that I can't install via rustpkg install <remote_url>. In fact, I found out today that rustpkg is now deprecated.
If I git clone the library and run the appropriate make commands to get it built, how do I use it elsewhere? I.e. how do I actually use extern crate http?
Since Rust 1.0, 99% of all users will use Cargo to manage the dependencies of a project. The TL;DR of the documentation is:
Create a project using cargo new
Edit the generated Cargo.toml file to add dependencies:
[dependencies]
old-http = "0.1.0-pre"
Access the crate in your code:
Rust 2021 and 2018
use old_http::SomeType;
Rust 2015
extern crate old_http;
use old_http::SomeType;
Build the project with cargo build
Cargo will take care of managing the versions, building the dependencies when needed, and passing the correct arguments to the compiler to link together all of the dependencies.
Read The Rust Programming Language for further details on getting started with Cargo. Specifying Dependencies in the Cargo book has details about what kinds of dependencies you can add.
Update
For modern Rust, see this answer.
Original answer
You need to pass the -L flag to rustc to add the directory which contains the compiled http library to the search path. Something like rustc -L path-to-cloned-rust-http-repo/build your-source-file.rs should do.
Tutorial reference
Not related to your post, but it is to your title. Also, cargo based.
Best practice:
external crate named foo
use ::foo;
module (which is part of your code/crate) named foo
use crate::foo;
In both the cases, you can use use foo; instead, but it can lead to confusion.
Once you've built it, you can use the normal extern crate http; in your code. The only trick is that you need to pass the appropriate -L flag to rustc to tell it where to find libhttp.
If you have a submodule in your project in the rust-http directory, and if it builds into its root (I don't actually know where make in rust-http deposits the resulting library), then you can build your own project with rustc -L rust-http pkg.rs. With that -L flag, the extern crate http; line in your pkg.rs will be able to find libhttp in the rust-http subfolder.
I ran into a similar issue. I ended up doing this in my Cargo.toml
[dependencies]
shell = { git = "https://github.com/google/rust-shell" }
Then in my main.rs I was able to add this and compile with success. Note that this cargo package is a macro in my case. Often you will not want to have the #[macro_use] before the extern call.
#[macro_use] extern crate shell;

Why Rust build.rs is unable to find C headers?

Basically I am trying to cargo build a crate which has a build.rs file.
This crate is located inside a bigger project and it's supposed to be a lib crate.
And inside this build.rs file, I am trying to compile a .C file which includes a couple of headers.
Fun fact: I got this build.rs file and crate structure from another little demo crate, and in that demo crate I had no problem to compile this exact C file with these headers.
FULL ERROR HERE:
Here is a link to github: https://github.com/mihaidogaru2537/FirecrackerPlayground/tree/dpdk_component/firecracker/src/dpdk_component
There is the crate I am talking about and you can also see the bigger project in which it resides. In the README file you can see the full error.
Either I do cargo build from the root of the big project or from the root of this problematic crate, the error is the same.
"cargo:warning=/usr/include/asm-generic/errno.h:5:10: fatal error: asm-generic/errno-base.h: No such file or directory
cargo:warning= 5 | #include <asm-generic/errno-base.h>"
The missing file might change depending on the .flag("-I/path/..") calls I am doing inside the build.rs
As you can see, right now it's unable to find errno-base.h, but I am including the path to asm-generic.
Here is the code of the build.rs file from the crate where the compilation of this C file works, as you can see, I did not have to add any include flags before calling compile.
fn main() {
// Tell cargo to tell rustc to link the system bzip2
// shared library.
// println!("cargo:rustc-link-lib=rte_ring");
// println!("cargo:rustc-link-lib=rte_mempool");
// Tell cargo to invalidate the built crate whenever the wrapper changes
// println!("cargo:rerun-if-changed=wrapper.h");
let _src = ["src/static-functions.c"];
println!("cargo:rerun-if-changed=build.rs");
let mut builder = cc::Build::new();
let build = builder
.file("src/static-functions.c")
.flag("-Wno-unused-parameter");
build.compile("foo");
}
Additional info:
The problematic crate is pretty small, see the link above. There is the build.rs file, C file and header file is inside the include directory.
One thing that I suspect, is that the target of the bigger project:
TARGET = Some("x86_64-unknown-linux-musl")
might affect the way the C file is compiled.
In the project where the compilation is working, I am not using that linux-musl stuff.
I am a total noob when it comes to Rust, but I do have a decent understanding of how C/C++ works.
I am running the project on Ubuntu 20.04
Those missing headers are a result of importing DPDK headers, I have DPDK libraries installed on the machine in question.
Let me know if you have any questions, sorry for the long read and thank you.
I somehow managed to fix it by adjusting the cargo build command to use x86_64-unknown-linux-gnu as target instead of x86_64-unknown-linux-musl (By default cargo build was doing the musl target somehow)
So if you are trying to build a rust app which is using DPDK libraries and you are getting missing headers, make sure to try the following:
cargo build --target=x86_64-unknown-linux-gnu
Well if you have to use musl and there is no alternative, I don't have an answer. But to me this was enough.
If someone has an explanation why musl is not working in this scenario, please let us know.
Reddit Rust community helped me as well, check this link out if you are interested:
https://www.reddit.com/r/rust/comments/mo3i08/unable_to_compile_c_file_inside_buildrs_headers/
So Why build.rs was unable to find .C headers?
ANSWER
Because I was using x86_64-unknown-linux-musl as target.

What is the difference between library crates and normal crates in Rust?

While reading the official book, I stumbled upon packages and crates. To create a new "project", this is what I ran:
$ cargo new my-project
Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs
The book states the following:
A package must contain zero or one library crates, and no more. It can contain as many binary crates as you’d like, but it must contain at least one crate (either library or binary).
My doubt is, what is the difference between binary crates and normal crates?
The difference is between binary crate and library crate. There are no "normal" crates.
A binary crate is an executable program.
A library crate is a library of reusable components that can be included in another library crate or in a binary crate.

Build only `lib` target

I want to build a dynamic link library (dll).
My Cargo.toml currently looks like this:
[package]
name = "sample"
version = "0.1.0"
authors = ["author"]
[lib]
name = "main"
crate-type = ["dylib"]
[dependencies]
I use VS Code with the RustyCode plugin as my IDE on windows.
When I run the build command this builds into a sample.exe and main.dll.
I know I can run cargo build --lib to only build my lib target but I dont have access to this command inside VS Code (afaik).
Is there anyway to specify that I only want to build the lib target in my Cargo.toml file so I can use the VS Code build command which runs cargo build/cargo run?
Cargo builds files using convention over configuration approach. When it finds a main.rs it builds an executable, and when it encounters lib.rs it expects to build a library.
Calling your lib main managed to confuse Cargo. The only solution I managed to find is to either change name of your crate from name = "main" to name = "foo" (and then rename your main.rs into foo.rs) or to change its name to lib.rs, as you did.
Just figured it: Rename the src/main.rs to src/lib.rs and it only builds the lib target!

Resources