Rust noob.. questions

So I am trying to create some mixed C & RUST examples

I found a crc32 - in rust example, and I am trying to create my own 'crate' as a learning exersize, and some things are not making sense. Hence my questions.

  1. I am familiar with the process for C static libraries, and I am trying to replicate that. It is my basic understanding that a "crate" - generally creates either (1) a static library, or (2) a dynamic (.so, or .dll) file that is used by a larger application or library. If one views the organization as branches, twigs and leaves - i have a directory full of leaves - i do not see an example of this.

  2. I desire to keep the content of the library/create "opaque" and I do not wish to expose the implementation. However it seems the rust language does not agree with this approach. Instead, rust (cargo?) seems to demand the source to every create be present and the crate must be visible.. Grr....

**QUESTION #1 ** Why is this a requirement? If my goal is "opaque" APIs how does that help?

QUESTION #2 Related: How can I create the equal to a C language header file that exposes the API, structures and enumerations but NOT the implementation of the crate (that I want to keep opaque)

  1. It seems the source code file must be named exactly 'lib.rs' - and that name is built into cargo and cargo will only accept the name: "lib.rs" as the source to my library. Sorry, but I really would like to organize or break up my static library into numerous functions, spread across multiple source code files.

QUESTION #3 How can I have a dozen or so separate .RS files in my crate static library. - cargo only compiles the one source file. Why is this?

  1. The example 'crc32' I am using (to learn with) starts with
const CRC32_TABLE: [u32; 256] = [ ... long list of numbers ...];
/* Then: */
fn crc32_rust( data: &[u8]) -> u32 {
   ...
   for byte in data {
        .. stuff that references CRC32_TABLE[]
   }
}

** Question #4 - ** This example does not pass a length or count of bytes in the data array, is the length passed as a hidden variable, or is an RUST array a more complex structure that contains both a length and the data?

** Question #5 - ** When I compile this - I see "warning constant CRC32_TABLE is never use."

But it is - it is used in the function 'crc32_rust()' - but I suspect it is not used for the reasons of the next question.

** Question #6 - ** Cargo also says: "function crc32_rust' is never used

How do I mark a function as: "this is a public function that will be used by external clients of this crate? I'll have several hundred of these so I'd like to better understand this process.

This is in effect a static library - so there is no, and will be no "main" function that will ever call this function from within this library. Thus, yes, I would think that because "crc32_rust()" is not used - it stands to reason that CRC32_TABLE would then also be not used. But that is not what I am trying to accomplish.

But - my example and question still holds for other reasons.

Say for example I have a large lookup table that is in a library. An example might be (A) a LOGO BITMAP image to display on a screen, or (B) a lookup table of floating point numbers for a sensor, (C) a data structure in a "BoardSupport" Package that represents the available UARTS on the embedded platform/board. The library might provide for example a "find_uart_by_name" function that traverses the array of data structures to find the specified UART. Each board would have its own 'board-support-package' create.

QUESTION #7 - How do I mark a data variable, or function as "this is a used thing" - it is not an unused thing and it must remain in the final static library that is being generated.

1 Like

I'd suggest reading chapter 7 of the book. It will explain most of your questions which are about the module system. I can also give more verbose answers tomorrow.

Edit: available here: https://doc.rust-lang.org/stable/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html

  1. I'm not sure I understand the question. Cargo will figure out the dependency tree and build and link everything you need.
  2. The reason most crates are available as source files is that rust has no stable ABI. That means you will need the .so compiled with exactly the same version of the compiler or it won't work. The only exception are extern "C" things.
  3. Each crate has one lib.rs as a root. You can declare other modules with mod foo to make it include a foo.rs or a foo/mod.rs file.
  4. An array has the length part of the type. Try changing the 256 to any other number: it won't compile. If you pass a reference to it, often written as &[u32], this is a fat pointer consisting of the length and the pointer to the actual data.
  5. & 6. & 7. If you want a thing in a library to be accessible from the outside (and not be optimized away) you need to make it pub.
2 Likes

the big problem i have is i cannot build the app with cargo that process is huge and way to complex to build with build.rs .

instead what is much easier is to have cargo build a static library with a c api that my c code can call

instead all of the rust/c examples i can find are the other way,
they focus on build/link the app using cargo and they only use a trivial single c function.. or file.. i have over 300 c source files and many (20-30) generated c and h files

so as a follow up… i understand the internal rust abi is unstable :frowning: is the FFI c api stable? OR do i need to run the cbindgen everytime? and fixup the c interface because the rust side changes internally?

No, generally a library crate creates a "Rust library" (rlib) that will be used by another cargo/rustc invocation.

If you want to produce a static/dynamic library you will have to specify the crate-type to be either staticlib (for producing static libraries) or dylib (for producing dynamic libraries).

If you create a staticlib/dylib you won't have to share the source code of your crate, just like you would do in C. However note that this has the same limitations you would have with C-produced staticlib/dylib, namely you can't export generic functions (well, C does not have them anyway), all functions and types exported should have a fixed ABI (e.g. extern "C" functions and #[repr(C)] for types) and when consuming them from Rust code they won't be considered different than C-produced libraries (e.g. you won't be able to import them in your Rust code like other Rust crates).

Check out cbindgen

A crate starts from a "root" file, the lib.rs file. If you want to include extra files in that same crate you'll have to declare them with mod from the root (or recursively, from other modules that where already included in the crate).

If you want to produce different staticlib/dylib for each file then you'll need different lib.rs files.

A slice reference (i.e. &[i32]) is a "fat" pointer containing both a pointer and a length. It is not FFI-safe, so I would advise against exposing it from a staticlib/dylib.

A rust array is e.g. a [i32; 4], and that consists of four i32 values (i.e. it is not a pointer).

Both the function and the const are not pub and hence not exported from your library. This means there's no way to use them, and hence are really unused.

For a staticlib/dylib however I would suggest using the no_mangle attribute to properly "export" it, as that will ensure the function receives a non-mangled name you can use to call it from code that imports those libraries.


That said I would suggest you to first learn the basics of Rust without trying to interface with external C code. Doing both at the same time will likely overload you due to missing knowledge.

6 Likes

the dylib crate type is for use by other Rust code, it expects lots of things that you won't generally have in C code. if you're trying have a self-contained dynamic library like C generally expects, you'll want to use cdylib. (yes, the naming is inconsistent with staticlib which is the equivalent of cdylib, iirc they're working on fixing the naming)

2 Likes

Note my targets tend to be bare metal

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.