DEV Community

Luca Barbato
Luca Barbato

Posted on

cargo-c common questions

I wrote and maintain cargo-c a cargo applet custom subcommand that let you build a rust crate sporting a C-API as a proper C library and install it along with C headers and pkg-config files.

When I notice some rust software sporting a C-API that I'd consider packaging in Gentoo I tend to provide a patch to add the few metadata entries needed to have cargo-c do all the work, some other people politely ask if cargo-c is supported and sometimes it is an uphill battle usually because the project maintainer doesn't know the required effort is minimum or is not aware setting crate-type=cdylib is not enough.

I'm writing this to explain some of the problems cargo-c solves and hopefully give few pointers since the README containing all the documentation maybe grew to be fairly big.

Top 6 questions, and their answers

Why this exists, why cargo isn't doing all of this on its own?

It exists because cargo itself does not have all the logic needed to deal with the platform specifics that come when dealing with dynamic linking and the details that come with installing/packaging a library.

Depending on the platform, even if they all use ELF as binary format, you may have different rules on how to encode the version information, e.g: Linux distributions have rules on setting the version while Android and FreeBSD do follow others.

macOS uses a different binary format and it has different rules and so does Windows.

Linux distribution may have different preferred paths for the libraries, with Debian using a multiarch setup.

Both dynamic library details and installing/packaging are currently out of cargo scope.

I prefer doing it on my own, why should I use cargo-c

With cargo-c I try to use the best practices to support as many platform as possible, trying to stay in sync with what meson does. Sadly what is conceptually trivial, installing a package, has lots of details that are platform-specific.

If you want to use cdylib-link-lines to solve the library creation problem, you still have to deal with how every platform expects the library to be installed and sadly it gets annoying.

I'm fine with just giving a static library, the user can copy it as they want

You might, but the people distributing your software may then have to redo quite a bit of work, at least maintain a patch Cargo.toml to add the cargo-c metadata. Some might consider that is not worth the effort and drop your package from the distribution.

Does cargo-c require lots to set up?

cargo-c is widely distributed so all you need is to add to Cargo.toml the following lines

[features]
capi = []
Enter fullscreen mode Exit fullscreen mode

The capi feature is used by cargo-c to know which crate in a workspace has to be made into a C library and can be used to keep the C-API within the main crate and enable it only when building with cargo-c.

There are lots of optional features to accommodate different needs and tune all the details regarding how the library, the headers and the pkg-config needs to be generated and installed.

A fairly common one is:

[package.metadata.capi.header]
generation = false
Enter fullscreen mode Exit fullscreen mode

To not generate the header using cbindgen, it will copy the header {crate name}.h from the assets/ directory.

How secure is cargo-c?

In the wake of the xz utils supply chain attack some people started caring more, so I happened to be asked about it.

  • I rely on deps.rs to ensure cargo-c is not relying on compromised and/or outdated crates.
  • I track cargo as my upstream and I try to cut a release every time a new one is released.
  • The code is fully auditable on github and the binaries provided are built from the CI so even that process can be checked.

In general any method that can be used to ensure cargo itself is not compromised applies to cargo-c.

Since cargo-c is a cargo extension, why not move it in cargo?

In general cargo extensions exist to keep cargo as lean as possible, so the decision to keep the install subcommand as bare as possible and not deal with all the details I dealt with in cargo-c is intentional.

Making C-libraries out of crates is not a strictly core functionality and until we do not have a stable Rust-ABI the need to produce shared/dynamic libraries in a platform-correct fashion is not a priority.

Probably everything will change once there is enough progress in that regard, if somebody feel that it should be prioritized I'm open to sponsorship ;)

In closing

I hope this article helps people convince maintainers of crates trying to replace a C library to adopt it since it will spare quite a bit of headaches to distributors and make much simpler to foster adoption of memory-safer alternatives.

Top comments (0)