How it works...

In this recipe, we created a Rust project that can be used as a third-party package C application in the Rust code.

We used the libc crate, which is used as a library for types and bindings to native C functions that are often found in other common platform libraries. This project dependency is mentioned in the Cargo.toml file under the dependencies field, and, then, in the build-dependencies section of the manifest, we have gcc = 0.3, which is the dependency of the build script.

The build script does not have the access to dependencies listed in the dependencies of the Cargo.toml manifest section. The build dependencies will not be available to the package files; this is done by the Cargo tool so that the package and the build script are compiled separately, so their dependencies need not coincide.

Rust provides a build script support where some packages need to compile third-party non-Rust code; for example, in our case we have a C script called double.c. The packages needed to link to C script, which can either be located on the system or possibly need to be built from source. Cargo does not replace other tools for building these packages, but it integrates them with the build configuration option, like, in our case, in the package section of the manifest, where we have a file named build with the build.rs script.

The Rust file designated by the build command, which, in our case, is build.rs, will be compiled first, before anything else is compiled in the package. This allows your Rust code to depend on the built or generated artifacts. In the build.rs script, we are building the native C code as part of the package; this package will later be used by the Rust code. We use an external crate named gcc, which invokes the externally maintained C compiler.

The build script starts out in the main function where gcc::Config::new().file("src/double.c").compile("libdouble.a") starts off by compiling our C file into an object file (by invoking gcc) and then converting the object file (double.o) into a static library (libdouble.a). The object file is stored in target/debug/build/<package>/out location.

In the src directory, we have the Rust project package file in which we have the native C script, double.c. The double.c script has a function named double_input, which takes in an integer argument named input and returns input * 2, which basically doubles the value passed.

In main.rs, we first import the libc crate and then define the function signature in the extern block (since it's a third-party package) as fn double_input(input: libc::c_int) -> libc::c_int. Here, we use the libc type so that there is a smooth conversion of types between Rust and C, which we do not have to handle while calling the foreign function, double_input. From the main function, we place it in the unsafe block.

The extern block is a list of function signatures in a foreign library and the foreign functions are assumed to be unsafe. So, when we call them, they need to be wrapped with the unsafe block as a promise to the compiler that everything contained within is truly safe.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.10.1