{"id":13503022,"url":"https://github.com/lu-zero/cargo-c","last_synced_at":"2025-05-15T12:04:15.050Z","repository":{"id":34996165,"uuid":"188232648","full_name":"lu-zero/cargo-c","owner":"lu-zero","description":"build and install C-compatible libraries","archived":false,"fork":false,"pushed_at":"2025-05-02T06:27:38.000Z","size":356,"stargazers_count":498,"open_issues_count":28,"forks_count":61,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-05-02T07:37:50.099Z","etag":null,"topics":["cargo","cargo-subcommand","hacktoberfest"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lu-zero.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"liberapay":"lu_zero","github":"lu-zero"}},"created_at":"2019-05-23T12:46:07.000Z","updated_at":"2025-05-02T06:27:42.000Z","dependencies_parsed_at":"2023-02-15T12:35:26.332Z","dependency_job_id":"634e416c-17bb-482d-b0a6-63152f2b3e82","html_url":"https://github.com/lu-zero/cargo-c","commit_stats":{"total_commits":395,"total_committers":40,"mean_commits":9.875,"dds":"0.25063291139240507","last_synced_commit":"be1b9c32fb9a4dbe3dd5b6768339e9aebf45ff2a"},"previous_names":[],"tags_count":87,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lu-zero%2Fcargo-c","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lu-zero%2Fcargo-c/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lu-zero%2Fcargo-c/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lu-zero%2Fcargo-c/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lu-zero","download_url":"https://codeload.github.com/lu-zero/cargo-c/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254337612,"owners_count":22054253,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cargo","cargo-subcommand","hacktoberfest"],"created_at":"2024-07-31T22:02:33.780Z","updated_at":"2025-05-15T12:04:10.036Z","avatar_url":"https://github.com/lu-zero.png","language":"Rust","funding_links":["https://liberapay.com/lu_zero","https://github.com/sponsors/lu-zero"],"categories":["Rust","HarmonyOS"],"sub_categories":["Windows Manager"],"readme":"# Cargo C-ABI helpers\n\n[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n[![Crates.io](https://img.shields.io/crates/v/cargo-c.svg)](https://crates.io/crates/cargo-c)\n[![Build Status](https://github.com/lu-zero/cargo-c/workflows/Rust/badge.svg)](https://github.com/lu-zero/cargo-c/actions?query=workflow:Rust)\n[![cargo-c chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://rust-av.zulipchat.com/#narrow/stream/254255-cargo-c)\n[![dependency status](https://deps.rs/repo/github/lu-zero/cargo-c/status.svg)](https://deps.rs/repo/github/lu-zero/cargo-c)\n\n[cargo](https://doc.rust-lang.org/cargo) applet to build and install C-ABI compatible dynamic and static libraries.\n\nIt 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.\n\n## Installation\n**cargo-c** may be installed from [crates.io](https://crates.io/crates/cargo-c).\n``` sh\ncargo install cargo-c\n```\n\nThe `rustc` version supported is the same as the one supported by the `cargo` version embedded in the package version, or as set in the\n[rust-version](https://doc.rust-lang.org/cargo/reference/manifest.html#the-rust-version-field) field.\n\nYou must have the **cargo** build [requirements](https://github.com/rust-lang/cargo#compiling-from-source) satisfied in order to build **cargo-c**:\n* `git`\n* `pkg-config` (on Unix, used to figure out the host-provided headers/libraries)\n* `curl` (on Unix)\n* OpenSSL headers (only for Unix, this is the `libssl-dev` package on deb-based distributions)\n\nYou may pass `--features=vendored-openssl` if you have problems building openssl-sys using the host-provided OpenSSL.\n\n``` sh\ncargo install cargo-c --features=vendored-openssl\n```\n\n## Usage\n``` sh\n# build the library, create the .h header, create the .pc file\n$ cargo cbuild --destdir=${D} --prefix=/usr --libdir=/usr/lib64\n```\n``` sh\n# build the library, create the .h header, create the .pc file, build and run the tests\n$ cargo ctest\n```\n``` sh\n# build the library, create the .h header, create the .pc file and install all of it\n$ cargo cinstall --destdir=${D} --prefix=/usr --libdir=/usr/lib64\n```\n\nFor a more in-depth explanation of how `cargo-c` works and how to use it for\nyour crates, read [Building Crates so they Look Like C ABI Libraries][dev.to].\n\n### The TL;DR:\nThis is the ideal setup for a project that wants to keep their C-API within the main crate:\n- [Create][diff-1] a `capi.rs` with the C-API you want to expose and use\n  ~~`#[cfg(cargo_c)]`~~`#[cfg(feature=\"capi\")]` to hide it when you build a normal rust library.\n- [Make sure][diff-2] you have a lib target and if you are using a workspace\n  the first member is the crate you want to export, that means that you might\n  have [to add a \".\" member at the start of the list][diff-3].\n- ~~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.\n- You may use the feature `capi` to add C-API-specific optional dependencies.\n  \u003e **NOTE**: It must be always present in `Cargo.toml`\n- Remember to [add][diff-4] a [`cbindgen.toml`][cbindgen-toml] and fill it with\n  at least the include guard and probably you want to set the language to C (it\n  defaults to C++)\n- Once you are happy with the result update your documentation to tell the user\n  to install `cargo-c` and do `cargo cinstall --prefix=/usr\n  --destdir=/tmp/some-place` or something along those lines.\n\nIf you plan to keep the bindings as a separate crate and do not need to autogenerate the headers you may just [populate Cargo.toml][diff-5]:\n- Add a `capi` feature, since it is used by cargo-c to identify packages that has to be built as C-libraries within a workspace.\n- Set the entry in `package.metadata.capi.header.generate` to `false`.\n- Optionally override the path to the header to a custom one instead of the default one.\n\n[diff-1]: https://github.com/RustAudio/lewton/pull/50/commits/557cb4ce35beedf6d6bfaa481f29936094a71669\n[diff-2]: https://github.com/RustAudio/lewton/pull/50/commits/e7ea8fff6423213d1892e86d51c0c499d8904dc1\n[diff-3]: https://github.com/xiph/rav1e/pull/1381/commits/7d558125f42f4b503bcdcda5a82765da76a227e0#diff-80398c5faae3c069e4e6aa2ed11b28c0R94\n[diff-4]: https://github.com/RustAudio/lewton/pull/51/files\n[diff-5]: https://github.com/linebender/resvg/commit/c0777c7ce26bf40efed7ba38d0a70e5af83feb78\n[cbindgen-toml]: https://github.com/eqrion/cbindgen/blob/master/docs.md#cbindgentoml\n\n## Advanced\nYou may override various aspects of `cargo-c` via settings in `Cargo.toml` under the `package.metadata.capi` key\n\n```toml\n[package.metadata.capi]\n# Configures the minimum required cargo-c version. Trying to run with an\n# older version causes an error.\nmin_version = \"0.6.10\"\n```\n\n### Header Generation\n\n```toml\n[package.metadata.capi.header]\n# Used as header file name. By default this is equal to the crate name.\n# The name can be with or without the header filename extension `.h`\nname = \"new_name\"\n# Install the header into a subdirectory with the name of the crate. This\n# is enabled by default, pass `false` or \"\" to disable it.\nsubdirectory = \"libfoo-2.0/foo\"\n# Generate the header file with `cbindgen`, or copy a pre-generated header\n# from the `assets` subdirectory. By default a header is generated.\ngeneration = true\n# Can be use to disable header generation completely.\n# This can be used when generating dynamic modules instead of an actual library.\nenabled = true\n```\n\n### `pkg-config` File Generation\n\n```toml\n[package.metadata.capi.pkg_config]\n# Used as the package name in the pkg-config file and defaults to the crate name.\nname = \"libfoo\"\n# Used as the pkg-config file name and defaults to the crate name.\nfilename = \"libfoo-2.0\"\n# Used as the package description in the pkg-config file and defaults to the crate description.\ndescription = \"some description\"\n# Used as the package version in the pkg-config file and defaults to the crate version.\nversion = \"1.2.3\"\n# Used as the Requires field in the pkg-config file, if defined\nrequires = \"gstreamer-1.0, gstreamer-base-1.0\"\n# Used as the Requires.private field in the pkg-config file, if defined\nrequires_private = \"gobject-2.0, glib-2.0 \u003e= 2.56.0, gmodule-2.0\"\n# Strip the include search path from the last n components, useful to support installing in a\n# subdirectory but then include with the path. By default it is 0.\nstrip_include_path_components = 1\n\n```\n\n### Library Generation\n\n```toml\n[package.metadata.capi.library]\n# Used as the library name and defaults to the crate name. This might get\n# prefixed with `lib` depending on the target platform.\nname = \"new_name\"\n# Used as library version and defaults to the crate version. How this is used\n# depends on the target platform.\nversion = \"1.2.3\"\n# Used to install the library to a subdirectory of `libdir`.\ninstall_subdir = \"gstreamer-1.0\"\n# Used to disable versioning links when installing the dynamic library\nversioning = false\n# Instead of using semver, select a fixed number of version components for your SONAME version suffix:\n# Setting this to 1 with a version of 0.0.0 allows a suffix of `.so.0`\n# Setting this to 3 always includes the full version in the SONAME (indicate any update is ABI breaking)\n#version_suffix_components = 2\n# Add `-Cpanic=abort` to the RUSTFLAGS automatically, it may be useful in case\n# something might panic in the crates used by the library.\nrustflags = \"-Cpanic=abort\"\n# Used to disable the generation of additional import library file in platforms\n# that have the concept such as Windows\nimport_library = false\n```\n\n### Custom data install\n```toml\n[package.metadata.capi.install.data]\n# Used to install the data to a subdirectory of `datadir`. By default it is the same as `name`\nsubdirectory = \"foodata\"\n# Copy the pre-generated data files found in {root_dir}/{from} to {datadir}/{to}/{matched subdirs}\n# If {from} is a single path instead of a glob, the destination is {datapath}/{to}.\n# datapath is {datadir}/{subdirectory}\nasset = [{from=\"pattern/with/or/without/**/*\", to=\"destination\"}]\n# Copy the pre-generated data files found in {OUT_DIR}/{from} to {includedir}/{to}/{matched subdirs}\n# If {from} is a single path instead of a glob, the destination is {datapath}/{to}.\n# datapath is {datadir}/{subdirectory}\ngenerated = [{from=\"pattern/with/or/without/**/*\", to=\"destination\"}]\n\n[package.metadata.capi.install.include]\n# Copy the pre-generated includes found in {root_dir}/{from} to {includedir}/{to}/{matched subdirs}\n# If {from} is a single path instead of a glob, the destination is {includepath}/{to}.\n# includepath is {includedir}/{header.subdirectory}\nasset = [{from=\"pattern/with/or/without/**/*\", to=\"destination\"}]\n# Copy the pre-generated includes found in {OUT_DIR}/{from} to {includedir}/{to}/{matched subdirs}\n# If {from} is a single path instead of a glob, the destination is {includedpath}/{to}.\n# includepath is {includedir}/{header.subdirectory}\ngenerated = [{from=\"pattern/with/or/without/**/*\", to=\"destination\"}]\n```\n\n### Notes\n\nDo **not** pass `RUSTFLAGS` that are managed by cargo through other means, (e.g. the flags driven by `[profiles]` or the flags driven by `[target.\u003c\u003e]`), cargo-c effectively builds as if the *target* is always explicitly passed.\n\n## Users\n\n- [ebur128](https://github.com/sdroege/ebur128#c-api)\n- [gcode-rs](https://github.com/Michael-F-Bryan/gcode-rs)\n- [gst-plugins-rs](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs)\n- [lewton](https://github.com/RustAudio/lewton)\n- [libdovi](https://github.com/quietvoid/dovi_tool/tree/main/dolby_vision#libdovi-c-api)\n- [libimagequant](https://github.com/ImageOptim/libimagequant#building-with-cargo-c)\n- [librsvg](https://github.com/GNOME/librsvg/blob/main/rsvg/meson.build)\n- [rav1e](https://github.com/xiph/rav1e)\n- [rustls-ffi](https://github.com/rustls/rustls-ffi)\n- [sled](https://github.com/spacejam/sled/tree/master/bindings/sled-native)\n- [pathfinder](https://github.com/servo/pathfinder#c)\n- [udbserver](https://github.com/bet4it/udbserver)\n\n## Status\n\n- [x] cli\n  - [x] build command\n  - [x] install command\n  - [x] test command\n  - [x] cargo applet support\n- [x] build targets\n  - [x] pkg-config generation\n  - [x] header generation (cbindgen integration)\n- [x] `staticlib` support\n- [x] `cdylib` support\n- [x] Generate version information in the header\n  - [ ] Make it tunable\n- [x] Extra Cargo.toml keys\n- [x] Better status reporting\n\n[dev.to]: https://dev.to/luzero/building-crates-so-they-look-like-c-abi-libraries-1ibn\n[using]: https://dev.to/luzero/building-crates-so-they-look-like-c-abi-libraries-1ibn#using-cargoc\n\n## Availability\n\n[![Packaging status](https://repology.org/badge/vertical-allrepos/cargo-c.svg)](https://repology.org/project/cargo-c/versions)\n\n## Troubleshooting\n\n### Shared libraries are not built on musl systems\n\nWhen running on a musl-based system (e.g. Alpine Linux), it could be that using the `cdylib` library type results in the following error (as reported [here](https://github.com/lu-zero/cargo-c/issues/180)):\n\n\u003e Error: CliError { error: Some(cannot produce cdylib for \u003cpackage\u003e as the target x86_64-unknown-linux-musl does not support these crate types), exit_code: 101 }\n\nThis suggests that Rust was not built with `crt-static=false` and it typically happens if Rust has been installed through rustup.\n\nShared libraries can be enabled manually in this case, by editing the file `.cargo/config` like so:\n\n```toml\n# .cargo/config\n\n[target.x86_64-unknown-linux-musl]\nrustflags = [\n    \"-C\", \"target-feature=-crt-static\",\n]\n```\n\nHowever, it is preferred to install Rust through the system package manager instead of rustup (e.g. with `apk add rust`), because the provided package should already handle this (see e.g. [here](https://git.alpinelinux.org/aports/tree/main/rust/APKBUILD?h=3.19-stable#n232)).\n\n### On Debian-like system the libdir includes the host triplet by default\n\nIn order to accomodate Debian's [multiarch](https://wiki.debian.org/Multiarch/Implementation) approach the `cargo-c` default for the `libdir` is `lib/\u003ctriplet\u003e` on such system.\nEither pass an explicit `--libdir` or pass `--target` to return to the common `libdir=lib` default.\n\n## Acknowledgements\n\nThis software has been partially developed in the scope of the H2020 project SIFIS-Home with GA n. 952652.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flu-zero%2Fcargo-c","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flu-zero%2Fcargo-c","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flu-zero%2Fcargo-c/lists"}