Giter Site home page Giter Site logo

rust-ffi-to-c's Introduction

How to call a C function from Rust πŸ¦€β˜ŽοΈ

I was working on a Rust project where we needed to interact with code written in C.

I had to learn how to work with FFI (Foreign Function Interface) in Rust and wrote up this little guide for others.

This repository is a working example of the final code from the tutorial I wrote below. Clone it and run it using cargo run.

$ cargo run
   Compiling rust-ffi-to-c v0.1.0
    Finished dev [unoptimized + debuginfo] target(s) in 0.93s
     Running `target/debug/rust-ffi-to-c`

[Rust] Hello from Rust! πŸ¦€
[Rust] Calling function in C..
[C] Hello from C!
[C] Input a is: 5000
[C] Input b is: 5
[C] Multiplying and returning result to Rust..
[Rust] Result: 25000

Tutorial

1. Define an external function

We use extern to reference the multiply() function, which is written in C (src/multiply.c).

In this case we want to multiply integers, so we import a C-compatible integer type into Rust from core:ffi. (See all the available types)

We then define the argument types and return type for our C function as c_int (equivalent to i32 in Rust).

extern crate core;
use core::ffi::c_int;

extern "C" {
    fn multiply(a: c_int, b: c_int) -> c_int;
}

2. Call the C function from Rust

Any use of foreign function is considered unsafe because the Rust compiler can't guarantee memory safety in foreign code. So in our main Rust file (src/main.rs) we call the function in an unsafe block, then pass in two i32 integers, and print the result.

unsafe {
    println!("Result: {}", multiply(5000, 5));
}

3. Compile and run

First we compile our multiply.c file using a C compiler:

clang src/multiply.c -c

The -c flag tells the C compiler to output a "object file (.o)" instead of an executable program. So it creates a multiply.o file that we can use as a shared dynamic library in our Rust code.

Second we create a static library file libmultiply.a using the ar tool:

ar rcs libmultiply.a multiply.o

Then we compile our program using the Rust compiler:

rustc src/main.rs -l multiply -L .

The -l multiply option tells the Rust compiler to link the shared library. The -L . option tells the Rust compiler to look for libraries in the current directory.

The compiler creates an executable named main which we can run:

./main
[Rust] Hello from Rust! πŸ¦€
[Rust] Calling function in C..
[C] Hello from C!
[C] Input a is: 5000 
[C] Input b is: 5 
[C] Multiplying and returning result to Rust..
[Rust] Result: 25000

4. Automate πŸ€–

It gets tedious to compile the files manually every time, so we will use cargo build script and the cc crate to automate this process.

Add cc to the projects build dependencies:

[build-dependencies]
cc = "1.0"

Create a build.rs and add compile instructions:

extern crate cc;

fn main() {
    cc::Build::new().file("src/multiply.c").compile("multiply");
}

And now we can use Cargo to build both the C and Rust code and run the program:

cargo run

Notes

  • From Rust 1.64.0 it is now recommended to use core::ffi instead of std::os::raw to access C types. The latter is now an alias to types in the core::ffi module. core is also available in places where the Rust standard library (std) is not, like embedded projects.

  • Mapping out functions manully using extern is fine for small projects, but as soon as you are dealing with a bigger library or codebase, you want to take a look at bindgen. It can automatically generate the bindings for C or C++ libraries, making using them in Rust a lot easier. See the bindgen User Guide.

  • We can control how our code is linked using the #[link()] attribute.. It allows us to specify or rename functions and change the type of linking to use, eg. to static:

    #[link(name = "multiply", kind = "static")]
    extern "C" { // ... }

Further reading

Further watching

rust-ffi-to-c's People

Contributors

coalooball avatar uggla avatar vanjacosic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

rust-ffi-to-c's Issues

I am getting error at step 3, rustc src/main.rs -l multiply.o -L .

Hi,

Firstly thanks for the tutorial. I follow the steps but I got this error at step 3. I am so new in rust and c, and could not solve the problems. However, when I run this ar rcs libmultiply.a multiply.o and then rustc -l static=multiply -L . src/main.rs, it works as expected. Are there any options to run without ar rcs?

error: linking with `cc` failed: exit status: 1
  |
  = note: LC_ALL="C" PATH="/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin:/home/erdi/miniconda3/bin:/home/erdi/miniconda3/condabin:/home/erdi/.cargo/bin:/home/erdi/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/bin" VSLANG="1033" "cc" "-m64" "/tmp/rustchwXAys/symbols.o" "main.main.b620efc257d42d9c-cgu.0.rcgu.o" "main.52fsdrpxr24z69pc.rcgu.o" "-Wl,--as-needed" "-L" "." "-L" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bdynamic" "-lmultiply.o" "-Wl,-Bstatic" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-6498d8891e016dca.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-3debdee1a9058d84.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libobject-8339c5bd5cbc92bf.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libmemchr-160ebcebb54c11ba.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libaddr2line-95c75789f1b65e37.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgimli-7e8094f2d6258832.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-bac9783ef1b45db0.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd_detect-a1cd87df2f2d8e76.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-7fd06d468d7dba16.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-5ac19487656e05bf.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libminiz_oxide-c7c35d32cf825c11.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libadler-c523f1571362e70b.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-85f17c92b770a911.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-598d3ba148dadcea.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-a58ec2dab545caa4.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-f9dda8cca149f0fc.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-7ba4c315dd7a3503.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-5ac2993e19124966.rlib" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-df2fb7f50dec519a.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/home/erdi/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs"
  = note: /usr/bin/ld: cannot find -lmultiply.o: No such file or directory
          collect2: error: ld returned 1 exit status
          

error: aborting due to previous error

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.