1# Cargo C-ABI helpers 2 3[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) 4[![Crates.io](https://img.shields.io/crates/v/cargo-c.svg)](https://crates.io/crates/cargo-c) 5[![Build Status](https://github.com/lu-zero/cargo-c/workflows/Rust/badge.svg)](https://github.com/lu-zero/cargo-c/actions?query=workflow:Rust) 6[![cargo-c chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://rust-av.zulipchat.com/#narrow/stream/254255-cargo-c) 7 8[cargo](https://doc.rust-lang.org/cargo) applet to build and install C-ABI compatible dynamic and static libraries. 9 10It produces and installs a correct [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) file, a static library and a dynamic library, and a C header to be used by any C (and C-compatible) software. 11 12## Installation 13**cargo-c** may be installed from [crates.io](https://crates.io/crates/cargo-c). 14``` sh 15cargo install cargo-c 16``` 17 18You must have the **cargo** build [requirements](https://github.com/rust-lang/cargo#compiling-from-source) satisfied in order to build **cargo-c**: 19* `git` 20* `pkg-config` (on Unix, used to figure out the host-provided headers/libraries) 21* `curl` (on Unix) 22* OpenSSL headers (only for Unix, this is the `libssl-dev` package on deb-based distributions) 23 24You may pass `--features=vendored-openssl` if you have problems building openssl-sys using the host-provided OpenSSL. 25 26``` sh 27cargo install cargo-c --features=vendored-openssl 28``` 29 30## Usage 31``` sh 32# build the library, create the .h header, create the .pc file 33$ cargo cbuild --destdir=${D} --prefix=/usr --libdir=/usr/lib64 34``` 35``` sh 36# build the library, create the .h header, create the .pc file, build and run the tests 37$ cargo ctest 38``` 39``` sh 40# build the library, create the .h header, create the .pc file and install all of it 41$ cargo cinstall --destdir=${D} --prefix=/usr --libdir=/usr/lib64 42``` 43 44For a more in-depth explanation of how `cargo-c` works and how to use it for 45your crates, read [Building Crates so they Look Like C ABI Libraries][dev.to]. 46 47### The TL;DR: 48 49- [Create][diff-1] a `capi.rs` with the C-API you want to expose and use 50 ~~`#[cfg(cargo_c)]`~~`#[cfg(feature="capi")]` to hide it when you build a normal rust library. 51- [Make sure][diff-2] you have a lib target and if you are using a workspace 52 the first member is the crate you want to export, that means that you might 53 have [to add a "." member at the start of the list][diff-3]. 54- ~~Since Rust 1.38, also add "staticlib" to the "lib" `crate-type`.~~ Do not specify the `crate-type`, cargo-c will add the correct library target by itself. 55- You may use the feature `capi` to add C-API-specific optional dependencies. 56 > **NOTE**: It must be always present in `Cargo.toml` 57- Remember to [add][diff-4] a [`cbindgen.toml`][cbindgen-toml] and fill it with 58 at least the include guard and probably you want to set the language to C (it 59 defaults to C++) 60- Once you are happy with the result update your documentation to tell the user 61 to install `cargo-c` and do `cargo cinstall --prefix=/usr 62 --destdir=/tmp/some-place` or something along those lines. 63 64[diff-1]: https://github.com/RustAudio/lewton/pull/50/commits/557cb4ce35beedf6d6bfaa481f29936094a71669 65[diff-2]: https://github.com/RustAudio/lewton/pull/50/commits/e7ea8fff6423213d1892e86d51c0c499d8904dc1 66[diff-3]: https://github.com/xiph/rav1e/pull/1381/commits/7d558125f42f4b503bcdcda5a82765da76a227e0#diff-80398c5faae3c069e4e6aa2ed11b28c0R94 67[diff-4]: https://github.com/RustAudio/lewton/pull/51/files 68[cbindgen-toml]: https://github.com/eqrion/cbindgen/blob/master/docs.md#cbindgentoml 69 70## Advanced 71You may override various aspects of `cargo-c` via settings in `Cargo.toml` under the `package.metadata.capi` key 72 73```toml 74[package.metadata.capi] 75# Configures the minimum required cargo-c version. Trying to run with an 76# older version causes an error. 77min_version = "0.6.10" 78``` 79 80### Header Generation 81 82```toml 83[package.metadata.capi.header] 84# Used as header file name. By default this is equal to the crate name. 85# The name can be with or without the header filename extension `.h` 86name = "new_name" 87# Install the header into a subdirectory with the name of the crate. This 88# is enabled by default, pass `false` or "" to disable it. 89subdirectory = "libfoo-2.0/foo" 90# Generate the header file with `cbindgen`, or copy a pre-generated header 91# from the `assets` subdirectory. By default a header is generated. 92generation = true 93# Can be use to disable header generation completely. 94# This can be used when generating dynamic modules instead of an actual library. 95enabled = true 96``` 97 98### `pkg-config` File Generation 99 100```toml 101[package.metadata.capi.pkg_config] 102# Used as the package name in the pkg-config file and defaults to the crate name. 103name = "libfoo" 104# Used as the pkg-config file name and defaults to the crate name. 105filename = "libfoo-2.0" 106# Used as the package description in the pkg-config file and defaults to the crate description. 107description = "some description" 108# Used as the package version in the pkg-config file and defaults to the crate version. 109version = "1.2.3" 110# Used as the Requires field in the pkg-config file, if defined 111requires = "gstreamer-1.0, gstreamer-base-1.0" 112# Used as the Requires.private field in the pkg-config file, if defined 113requires_private = "gobject-2.0, glib-2.0 >= 2.56.0, gmodule-2.0" 114# Strip the include search path from the last n components, useful to support installing in a 115# subdirectory but then include with the path. By default it is 0. 116strip_include_path_components = 1 117 118``` 119 120### Library Generation 121 122```toml 123[package.metadata.capi.library] 124# Used as the library name and defaults to the crate name. This might get 125# prefixed with `lib` depending on the target platform. 126name = "new_name" 127# Used as library version and defaults to the crate version. How this is used 128# depends on the target platform. 129version = "1.2.3" 130# Used to install the library to a subdirectory of `libdir`. 131install_subdir = "gstreamer-1.0" 132# Used to disable versioning links when installing the dynamic library 133versioning = false 134# Add `-Cpanic=abort` to the RUSTFLAGS automatically, it may be useful in case 135# something might panic in the crates used by the library. 136rustflags = "-Cpanic=abort" 137``` 138 139### Custom data install 140```toml 141[package.metadata.capi.install.data] 142# Used to install the data to a subdirectory of `datadir`. By default it is the same as `name` 143subdirectory = "foodata" 144# Copy the pre-generated data files found in {root_dir}/{from} to {datadir}/{to}/{matched subdirs} 145# If {from} is a single path instead of a glob, the destination is {datapath}/{to}. 146# datapath is {datadir}/{subdirectory} 147assets = [{from="pattern/with/or/without/**/*", to="destination"}] 148# Copy the pre-generated data files found in {OUT_DIR}/{from} to {includedir}/{to}/{matched subdirs} 149# If {from} is a single path instead of a glob, the destination is {datapath}/{to}. 150# datapath is {datadir}/{subdirectory} 151generated = [{from="pattern/with/or/without/**/*", to="destination"] 152 153[package.metadata.capi.install.include] 154# Copy the pre-generated includes found in {root_dir}/{from} to {includedir}/{to}/{matched subdirs} 155# If {from} is a single path instead of a glob, the destination is {includepath}/{to}. 156# includepath is {includedir}/{header.subdirectory} 157assets = [{from="pattern/with/or/without/**/*", to="destination"}] 158# Copy the pre-generated includes found in {OUT_DIR}/{from} to {includedir}/{to}/{matched subdirs} 159# If {from} is a single path instead of a glob, the destination is {includedpath}/{to}. 160# includepath is {includedir}/{header.subdirectory} 161generated = [{from="pattern/with/or/without/**/*", to="destination"] 162``` 163 164### Notes 165 166Do **not** pass `RUSTFLAGS` that are managed by cargo through other means, (e.g. the flags driven by `[profiles]` or the flags driven by `[target.<>]`), cargo-c effectively builds as if the *target* is always explicitly passed. 167 168## Users 169 170- [gcode-rs](https://github.com/Michael-F-Bryan/gcode-rs) 171- [lewton](https://github.com/RustAudio/lewton) 172- [rav1e](https://github.com/xiph/rav1e) 173- [sled](https://github.com/spacejam/sled/tree/master/bindings/sled-native) 174- [pathfinder](https://github.com/servo/pathfinder#c) 175 176## Status 177 178- [x] cli 179 - [x] build command 180 - [x] install command 181 - [x] test command 182 - [x] cargo applet support 183- [x] build targets 184 - [x] pkg-config generation 185 - [x] header generation (cbindgen integration) 186- [x] `staticlib` support 187- [x] `cdylib` support 188- [x] Generate version information in the header 189 - [ ] Make it tunable 190- [x] Extra Cargo.toml keys 191- [x] Better status reporting 192 193[dev.to]: https://dev.to/luzero/building-crates-so-they-look-like-c-abi-libraries-1ibn 194[using]: https://dev.to/luzero/building-crates-so-they-look-like-c-abi-libraries-1ibn#using-cargoc 195 196## Acknowledgements 197 198This software has been partially developed in the scope of the H2020 project SIFIS-Home with GA n. 952652. 199