Rust - Call functions from a c lib under windows with .dll file - rust

I'm working on a project that need to call a C project shared lib in Windows.
Suppose I have the my-math.dll file under rust src folder. I already add libc crate in Cargo.toml and following is my main.rs code:
extern crate libc;
#[link(name = "my-math")]
extern {
}
fn main() {
}
When I tried to build the project, it came with the error note: LINK : fatal error LNK1181: cannot open input file 'my-math.lib'
Seems the #[link(name="my-math")] converted to my-math.lib automatically. But I only have the .dll file. Is there anyway to switch to dll file instead of lib file.
I don't want to use the header file with bindgen crate for some special reasons.

Related

How to get the binary output of cargo run <rust.rs>?

When we compile a c file using gcc test.c -o test.
We can get the binary file as test.
But while running a file using cargo run test.rs in rust.
can we get the binary like we got in the C program?
The original hello.c file:
void main() {
// printf() displays the string inside quotation
printf("Hello, World!");
}
The rust program:
extern "C" {
fn printf(_: *const libc::c_char, _: ...) -> libc::c_int;
}
unsafe fn main_0() {
// printf() displays the string inside quotation
printf(b"Hello, World!\x00" as *const u8 as *const libc::c_char);
}
pub fn main() { unsafe { main_0() } ::std::process::exit(0i32); }
When using cargo it compiles and runs perfectly.
└─$ cargo run hello.rs
Compiling Rust_testing v0.1.0 (/home/pegasus/Documents/Rust_testing)
warning: crate `Rust_testing` should have a snake case name
|
= note: `#[warn(non_snake_case)]` on by default
= help: convert the identifier to snake case: `rust_testing`
warning: `Rust_testing` (bin "Rust_testing") generated 1 warning
Finished dev [unoptimized + debuginfo] target(s) in 0.17s
Running `target/debug/Rust_testing hello.rs`
Hello, world!
Here's my Cargo.toml file:
[package]
name = "Rust_testing"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libc = "0.2"
I have a rust program named hello.rs.
The program is I'm unable to compile it using rustc. I generated the hello.rs using c2rust online transpiler. But if I use cargo run hello.rs the program runs smoothly.
while using rustc new.rs -o test,
I can get the x86 test binary.
How to get similar kind of file while using the cargo run new.rs?
I looked into the target/debug directory.
But there are so many directories and so many files there. How to know which on is created for which .rs file?
┌──(pegasus㉿pegasus)-[~/Documents/Rust_testing/target/debug]
└─$ ls
build deps examples incremental Rust_testing Rust_testing.d
If you do cargo build, you will find the binary in target/debug/. If you build in release via cargo build --release, you will find it in target/release/.
Be aware that cargo run hello.rs does not compile hello.rs. It will always compile src/main.rs. hello.rs will be passed to the compiled program as a command line argument.
How to know which on is created for which .rs file?
There isn't one file for one .rs file. If your crate is a binary crate, then there will be exactly one executable with the name of your crate. In your case it's Rust_testing. You can run it with ./target/debug/Rust_testing, or copy it somewhere else and execute it directly.
You can add multiple binaries per crate by putting them in the src/bin folder. For example, if you put your hello.rs file in src/bin and then execute cargo build --all, it will create a target/debug/hello executable that you can run.
For more information about cargo's folder layout, read the cargo documentation.
If you are new to Rust, I highly recommend reading the Rust book. It will guide you through how to use rustup, rustc and cargo step by step.

Pass Rustc flags to crate in workspace

I have a workspace with two crates: lib and app, where I want to use code from lib in app.
Additionally, I want to have the following Cargo config only in the lib crate to insturment the lib crate with LLVMs SanitizeCoverage (I provide the callback functions of the SanitizeCoverage in the app crate, because they must not be instrumented, otherwise there would be a stack overflow):
[build]
rustflags = [
"-Cpasses=sancov-module",
"-Cllvm-args=-sanitizer-coverage-level=1",
"-Cllvm-args=-sanitizer-coverage-trace-pc-guard",
]
Unfortunately, Cargo does not use this config file if it is included in lib/.cargo/config.toml.
I tried to pass the config with a build.rs of the lib crate:
pub fn main() {
println!("cargo:rustc-env=RUSTFLAGS=\"-Cpasses=sancov-module -Cllvm-args=-sanitizer-coverage-level=1 -Cllvm-args=-sanitizer-coverage-trace-pc-guard\"");
}
But this also does not work (The code is not instrumented, as I've checked with the disassembly afterwards).
Is there any way to do this? I also tried to create two different crates, without a workspace, but then the Cargo config file of the lib crate is also ignored.
I also tried to manually create a rlib and link to it manually, but while this works more or less, it is really problematic as I have to export a C interface in that case. Also, this fails if I want to execute it in the Fortanix SGX framework (which is my ultimate goal).

Changing the icon of an .exe file in Rust

So I did some research and found out about rs.exe in Windows to convert my resources.rs file containing a name to_do and PATH to ico to res. The only problem is after navigating to its directory and running the command rs resource.exe. I get the error RC1109 which im told is that the rc.exe can not find the path.
What am I doing wrong? should I keep my resources.rs file in the same folder as the rc.exe?
do I have to format the text included in the file in some sort of way?
As always thanks for your help!
You can use the winres crate to set an icon for the .exe when you run cargo build or cargo run.
Add this to your Cargo.toml:
[package]
...
build = "build.rs"
[build-dependencies]
winres = "0.1"
Then create a build.rs file in the same directory where the Cargo.toml is located, with the following content:
extern crate winres;
fn main() {
if cfg!(target_os = "windows") {
let mut res = winres::WindowsResource::new();
res.set_icon("my_icon.ico"); // Replace this with the filename of your .ico file.
res.compile().unwrap();
}
}
Then you have to copy your .ico file in that same directory, too. Don't forget to change the filename in build.rs.

Rust #![no_std]: unresolved external symbol _mainCRTStartup

I wanted to start a Rust no_std project, so I simply created a new cargo package and wrote in main.rs the following lines:
#![feature(lang_items, start)]
#![no_std]
extern crate libc;
#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize{
1
}
#[panic_handler]
fn panic(_: &core::panic::PanicInfo) -> !{
loop{}
}
#[lang = "eh_personality"] extern fn eh_personality() {}
The Cargo.toml file looks like that:
[dependencies]
libc = "0.2.71"
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
I ran cargo build and the linker printed:
LINK : error LNK2001: unresolved external symbol _mainCRTStartup
What could be the reason behind that error ?
Default build target on windows uses mscv toolchain, which includes a dynamically-linked libc. This ones is a C-runtime, which, in particularly, includes an undefined main symbol (which assumed to be defined by a programmer), therefore at linking stage the linker cannot find this missing symbol. You need explicitly specify that you don't need it via #![no_main] at the beginning of main.rs.
I also would suggest you reading A Freestanding Rust Binary which explain much more in details.

How to link main.rs to lib.rs dynamically?

I have a crate with both src/lib.rs and src/main.rs.
main.rs is just using extern crate programname (which is lib.rs) and uses certain functions from lib.rs and it's submodules.
The documentation on linking says:
Pure-Rust dependencies are statically linked by default so you can use created binaries and libraries without installing Rust everywhere.
How can I change this behavior so a binary created from main.rs will be dynamically linked to library produced by lib.rs?
I've added the following to Cargo.toml
[lib]
path = "src/lib.rs"
crate-type = ["dylib"]
[[bin]]
name = "programname"
path = "src/main.rs"
But it does not compile and gives me errors like:
error: cannot satisfy dependencies so `std` only shows up once
help: having upstream crates all available in one format will likely make this go away
If I add "rlib" to lib section, it compiles, but the binary is not linked against libprogramname.so

Resources