I am new to Rust and attempting to build a test project with Cargo. My Cargo.toml looks like:
[package]
name = "rust-play"
version = "0.0.1"
authors = [ "Bradley Wogsland <omitted>" ]
(but the actual TOML file doesn't omit my email). When I cargo build I am getting the following error:
error: failed to parse manifest at /Users/wogsland/Projects/rust-play/Cargo.toml
Caused by:
no targets specified in the manifest
either src/lib.rs, src/main.rs, a [lib] section, or [[bin]] section must be present
My main function is in a src/test.rs file. Do I need to specify that in the TOML file? If so, how? I tried adding
target = "src/test.rs"
to no avail.
As the error says:
either src/lib.rs, src/main.rs, a [lib] section, or [[bin]] section must be present
So the direct answer is to add a [[bin]] section:
[[bin]]
name = "test"
path = "src/test.rs"
However, it's far more usual to just place the file in the expected location: src/main.rs. You could also place it in src/bin/test.rs if you plan on having multiple binaries.
If it's actually for testing your code, then unit tests go in the same file as the code they are testing and integration tests go in tests/foo.rs.
Alternative issue and solution: You can also be faced with this error if you have copied Cargo.toml file to a parent folder of the crate.
I ran into this issue on Ubuntu 20.04 after having inadvertently copied Cargo.toml to my home folder. Even though my working directory had a properly defined Cargo.toml, the copy in $HOME was taking precedence and causing builds to fail.
In my case and probably in your case as well, the rs file was not named main.rs while Cargo assumes that src/main.rs is the crate root of a binary crate. So, the rule is that If project is an executable, name the main source file src/main.rs. If it is a library, name the main source file src/lib.rs.
Additionally, Cargo will also treat any files located in src/bin/*.rs as executables like mentioned in the previous answer.
As a summary:
If you use cargo new xxx --bin, you will find the file in the src directory is named main.rs. And when you check the file Cargo.toml. It is the same as you written. So the first way is to change the file in src to main.rs
As the cargo report, we can use the [[bin]] to set the file. #Shepmaster has solved it.
Both two ways can work.
I also had this issue and it was because the parent directory also contained a Cargo.toml file and it was prioritising that over the one in the current directory
Related
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.
So I have a header library (a directory of .h files) that I need to make use of in my rust code. To get this working I have been looking into various crates to help me achieve the this and it seems like bindgen is the most promising option.
i followed the documentation for bindgen and have created a wrapper.h and a build.rs file.
in the build.rs file i have whitelisted all the needed functions, and the link parameter mentioned in the documentation specified as println! ("cargo:rustc-link-lib=C/complete path to my header files");.
when doing a cargo build this however fails with this error:
error: linking with link.exe failed: exit code: 1181
which I have not been able to find a solution for.
Any help or suggestions are greatly appreciated.
rustc-link-lib directive is only for .a/.so/.dll and cannot work with either .h or .rs files. It's completely inappropriate here.
If you make your build.rs script write to a directory specified by std::env::var("OUT_DIR") path, then your main library code can include it dynamically with:
include!(concat!(env!("OUT_DIR"), "/temp_file_built_by_build_dot_rs.rs"));
Alternatively, don't bother with build.rs at all. Use command-line bindgen and include generated .rs file as a module in your project (just as a regular source code file).
I created a "hello world" Rust app using cargo new. When I executed git status it showed a bunch of files:
A rust/welcomec/Cargo.lock
A rust/welcomec/Cargo.toml
A rust/welcomec/src/main.rs
A rust/welcomec/target/debug/.cargo-lock
A rust/welcomec/target/debug/.fingerprint/welcomec-2d68725c8fae6fd1/bin-welcome-2d68725c8fae6fd1
A rust/welcomec/target/debug/.fingerprint/welcomec-2d68725c8fae6fd1/bin-welcome-2d68725c8fae6fd1.json
A rust/welcomec/target/debug/.fingerprint/welcomec-2d68725c8fae6fd1/dep-bin-welcome-2d68725c8fae6fd1
A rust/welcomec/target/debug/deps/welcome-2d68725c8fae6fd1
A rust/welcomec/target/debug/welcome
A rust/welcomec/target/debug/welcome.d
Can I safely ignore any of these files and/or directories?
Summary
.gitignore for library crates
# Generated files
/target/
# The library shouldn't decide about the exact versions of
# its dependencies, but let the downstream crate decide.
Cargo.lock
.gitignore for executable crates
# Generated files
/target/
Details
You need one or two entries in your .gitignore, depending on what kind of crate you're building. The target/ folder can be ignore completely regardless of crate type; it only contains generated files (e.g. compile artifacts).
The Cargo.lock file should be included in the repository if you're writing an executable, and should be ignored if you're writing a library. You can read more about this in the FAQ. To quote the most important part:
The purpose of a Cargo.lock is to describe the state of the world at the time of a successful build. [...]
This property is most desirable from applications and projects which are at the very end of the dependency chain (binaries). As a result, it is recommended that all binaries check in their Cargo.lock.
For libraries the situation is somewhat different. [...] 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 all libraries were to check in their Cargo.lock, then multiple copies of the library would be used, and perhaps even a version conflict.
Also, please note that cargo new and cargo init automatically generates a .gitignore file in the project, unless the parameter --vcs none is passed.
You can take some inspiration from GitHub's gitignore for Rust. At the time of writing, the file goes as follows:
# Generated by Cargo
# will have compiled files and executables
debug/
target/
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
Cargo.lock
# These are backup files generated by rustfmt
**/*.rs.bk
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb
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!
I'm having difficulty working with the capnpc crate. I'm running Arch Linux and have installed capnp from the AUR and compiled capnpc-rust from the github project and put it in /usr/local/bin. I can manually compile the .capnp file easily with the command
capnp compile -orust --src-prefix=capnp capnp/message.capnp
I tried cloning the capnpc project and compiling the .capnp test file in the test directory and that didn't work either. I'm not getting any errors (whereas earlier I was getting "File not found") so it seems like capnpc is working, but I can't find files anywhere.
build.rs
extern crate capnpc;
fn main() {
::capnpc::compile("capnp", &["capnp/message.capnp"]).unwrap();
}
Cargo.toml
...
build = "build.rs"
[lib]
name = "rustp2p"
path = "src/lib.rs"
[build-dependencies]
capnpc = "*"
[dependencies]
capnp = "0.5.0"
Edit: .rs file builds out into /target/debug/build/.../out.
When you invoke capnpc::compile from a Cargo build script, the generated code goes in a subdirectory of target/ that can be found at main compile time through the OUT_DIR environment variable. This strategy is described in the Cargo documentation.
You shouldn't need to install the capnpc-rust binary in /usr/local/bin or anywhere else for this to work.
Your build.rs and Cargo.toml files look fine to me.
You might find it helpful to consult the addressbook example.