Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package cargo-c for openSUSE:Factory checked in at 2026-09-10 11:46:52 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/cargo-c (Old) and /work/SRC/openSUSE:Factory/.cargo-c.new.1265 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "cargo-c" Thu Sep 10 11:46:52 2026 rev:26 rq:1376515 version:0.10.25 Changes: -------- --- /work/SRC/openSUSE:Factory/cargo-c/cargo-c.changes 2026-08-15 22:40:03.148374788 +0200 +++ /work/SRC/openSUSE:Factory/.cargo-c.new.1265/cargo-c.changes 2026-09-10 11:47:16.321207812 +0200 @@ -1,0 +2,19 @@ +Wed Sep 09 03:34:35 UTC 2026 - William Brown <[email protected]> + +- bsc#1278238 - CVE-2026-82247 - gitoxide's gix-url crate (<= 0.32.0, fixed in 0.37.1) uses a hand-rolled URL parser that does not treat '?' or '#' as terminating the authority +- bsc#1278228 - CVE-2026-82251 - gitoxide before 0.52.1 fails to validate submodule names from .gitmodules configuration, allowing path traversal +- bsc#1278129 - CVE-2026-82250 - gitoxide gix-packetline versions before 0.21.5 contain a panic vulnerability in the TextRef implementation +- bsc#1278107 - CVE-2026-82253 - gitoxide (Rust crates gix <= 0.72.0 and gix-validate <= 0.10.0) contains a path traversal vulnerability. +- bsc#1277888 - CVE-2026-82254 - gitoxide before 0.69.0 contains unchecked array indexing in delta application +- Update to version 0.10.25: + * Bump object version + * Split README metadata into docs/ + * Add plugin mode for dlopen modules + * Simplify the CI + * Sync up compile_with_exec functionality + * Bump to cargo 0.99 + * Bump dependencies + * Address clippy lints + * Document how to use cheadergen with cargo-c + +------------------------------------------------------------------- Old: ---- cargo-c-0.10.23.tar.xz New: ---- cargo-c-0.10.25.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ cargo-c.spec ++++++ --- /var/tmp/diff_new_pack.LO6eae/_old 2026-09-10 11:47:17.851271956 +0200 +++ /var/tmp/diff_new_pack.LO6eae/_new 2026-09-10 11:47:17.853272039 +0200 @@ -18,7 +18,7 @@ Name: cargo-c -Version: 0.10.23 +Version: 0.10.25 Release: 0 Summary: Helper to build and install c-like libraries from Rust License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.LO6eae/_old 2026-09-10 11:47:17.918274765 +0200 +++ /var/tmp/diff_new_pack.LO6eae/_new 2026-09-10 11:47:17.922274932 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/lu-zero/cargo-c.git</param> <param name="versionformat">@PARENT_TAG@+git@TAG_OFFSET@.%h</param> <param name="scm">git</param> - <param name="revision">v0.10.23</param> + <param name="revision">v0.10.25</param> <param name="match-tag">*</param> <param name="versionrewrite-pattern">v?([^+]+)(\+git0.*)?(\+git[1-9][0-9]*.*)?</param> <param name="versionrewrite-replacement">\1\3</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.LO6eae/_old 2026-09-10 11:47:17.952276190 +0200 +++ /var/tmp/diff_new_pack.LO6eae/_new 2026-09-10 11:47:17.955276316 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/lu-zero/cargo-c.git</param> - <param name="changesrevision">cfdb2752fabf40711d535011c371a8b1c20a1be2</param></service></servicedata> + <param name="changesrevision">a228fd974eb1334dc4c8033bc401a4832b3b4ab4</param></service></servicedata> (No newline at EOF) ++++++ cargo-c-0.10.23.tar.xz -> cargo-c-0.10.25.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cargo-c-0.10.23/.github/workflows/example-project.yml new/cargo-c-0.10.25/.github/workflows/example-project.yml --- old/cargo-c-0.10.23/.github/workflows/example-project.yml 2026-06-01 08:21:05.000000000 +0200 +++ new/cargo-c-0.10.25/.github/workflows/example-project.yml 2026-08-23 22:16:10.000000000 +0200 @@ -1,6 +1,9 @@ name: Build example project -on: [push, pull_request] +on: + push: + branches: [master] + pull_request: env: CARGO_TERM_COLOR: always diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cargo-c-0.10.23/.github/workflows/rust.yml new/cargo-c-0.10.25/.github/workflows/rust.yml --- old/cargo-c-0.10.23/.github/workflows/rust.yml 2026-06-01 08:21:05.000000000 +0200 +++ new/cargo-c-0.10.25/.github/workflows/rust.yml 2026-08-23 22:16:10.000000000 +0200 @@ -1,6 +1,9 @@ name: Rust -on: [push, pull_request] +on: + push: + branches: [master] + pull_request: jobs: @@ -26,7 +29,7 @@ args: --all -- -D warnings coverage: - needs: arch-test + needs: rustfmt-clippy name: Code coverage runs-on: ubuntu-latest steps: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cargo-c-0.10.23/Cargo.toml new/cargo-c-0.10.25/Cargo.toml --- old/cargo-c-0.10.23/Cargo.toml 2026-06-01 08:21:05.000000000 +0200 +++ new/cargo-c-0.10.25/Cargo.toml 2026-08-23 22:16:10.000000000 +0200 @@ -1,6 +1,6 @@ [package] name = "cargo-c" -version = "0.10.23+cargo-0.97.1" +version = "0.10.25+cargo-0.99.0" authors = ["Luca Barbato <[email protected]>"] description = "Helper program to build and install c-like libraries" license = "MIT" @@ -9,7 +9,7 @@ repository = "https://github.com/lu-zero/cargo-c" categories = ["command-line-utilities", "development-tools::cargo-plugins"] keywords = ["cargo", "cdylib"] -rust-version = "1.94" +rust-version = "1.96" [[bin]] name = "cargo-capi" @@ -28,7 +28,7 @@ path = "src/bin/ctest.rs" [dependencies] -cargo = "0.97.1" +cargo = "0.99.0" cargo-util = "0.2" semver = "1.0.3" log = "0.4" @@ -42,9 +42,9 @@ anyhow = "1.0" cc = "1.0" glob = "0.3" -itertools = "0.14" +itertools = "0.15" implib = "0.6.0" -object = { version = "0.39.1", default-features = false, features = ["std", "read_core", "pe"] } +object = { version = "0.40.0", default-features = false, features = ["std", "read_core", "pe"] } cargo-platform = "0.3.1" clap_complete = "4.5.65" camino = "1.2.2" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cargo-c-0.10.23/README.md new/cargo-c-0.10.25/README.md --- old/cargo-c-0.10.23/README.md 2026-06-01 08:21:05.000000000 +0200 +++ new/cargo-c-0.10.25/README.md 2026-08-23 22:16:10.000000000 +0200 @@ -67,7 +67,7 @@ If 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]: - 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. -- Set the entry in `package.metadata.capi.header.generate` to `false`. +- Set the entry in `package.metadata.capi.header.generation` to `false`. - Optionally override the path to the header to a custom one instead of the default one. [diff-1]: https://github.com/RustAudio/lewton/pull/50/commits/557cb4ce35beedf6d6bfaa481f29936094a71669 @@ -77,118 +77,12 @@ [diff-5]: https://github.com/linebender/resvg/commit/c0777c7ce26bf40efed7ba38d0a70e5af83feb78 [cbindgen-toml]: https://github.com/eqrion/cbindgen/blob/master/docs.md#cbindgentoml -## Advanced -You may override various aspects of `cargo-c` via settings in `Cargo.toml` under the `package.metadata.capi` key +## Documentation -```toml -[package.metadata.capi] -# Configures the minimum required cargo-c version. Trying to run with an -# older version causes an error. -min_version = "0.6.10" -``` - -### Header Generation - -```toml -[package.metadata.capi.header] -# Used as header file name. By default this is equal to the crate name. -# The name can be with or without the header filename extension `.h` -name = "new_name" -# Install the header into a subdirectory with the name of the crate. This -# is enabled by default, pass `false` or "" to disable it. -subdirectory = "libfoo-2.0/foo" -# Generate the header file with `cbindgen`, or copy a pre-generated header -# from the `assets` subdirectory. By default a header is generated. -generation = true -# Can be use to disable header generation completely. -# This can be used when generating dynamic modules instead of an actual library. -enabled = true -# Whether to emit library version constants (e.g. `FOO_MAJOR`, `FOO_MINOR` and -# `FOO_PATCH`) at the top of the header file. Enabled by default. -emit_version_constants = true -``` - -### `pkg-config` File Generation - -```toml -[package.metadata.capi.pkg_config] -# Used as the package name in the pkg-config file and defaults to the crate name. -name = "libfoo" -# Used as the pkg-config file name and defaults to the crate name. -filename = "libfoo-2.0" -# Used as the package description in the pkg-config file and defaults to the crate description. -description = "some description" -# Used as the package version in the pkg-config file and defaults to the crate version. -version = "1.2.3" -# Used as the Requires field in the pkg-config file, if defined -requires = "gstreamer-1.0, gstreamer-base-1.0" -# Used as the Requires.private field in the pkg-config file, if defined -requires_private = "gobject-2.0, glib-2.0 >= 2.56.0, gmodule-2.0" -# Strip the include search path from the last n components, useful to support installing in a -# subdirectory but then include with the path. By default it is 0. -strip_include_path_components = 1 - -``` - -### Library Generation - -```toml -[package.metadata.capi.library] -# Used as the library name and defaults to the crate name. This might get -# prefixed with `lib` depending on the target platform. -name = "new_name" -# Used as library version and defaults to the crate version. How this is used -# depends on the target platform. -version = "1.2.3" -# Used to install the library to a subdirectory of `libdir`. -install_subdir = "gstreamer-1.0" -# Used to disable versioning links when installing the dynamic library -versioning = false -# Instead of using semver, select a fixed number of version components for your SONAME version suffix: -# Setting this to 1 with a version of 0.0.0 allows a suffix of `.so.0` -# Setting this to 3 always includes the full version in the SONAME (indicate any update is ABI breaking) -#version_suffix_components = 2 -# Add `-Cpanic=abort` to the RUSTFLAGS automatically, it may be useful in case -# something might panic in the crates used by the library. -rustflags = "-Cpanic=abort" -# Used to disable the generation of additional import library file in platforms -# that have the concept such as Windows -import_library = false - -[package.metadata.capi.library.target.'cfg(target_os = "linux")'] -# Add target-specific rustflags, the are folded with the main rustflags above -# Note that multiple --version-script support is heavily linker dependent. -rustflags = "-Clink-arg=-Wl,--version-script=assets/version.map" -``` - -### Custom data install -```toml -[package.metadata.capi.install.data] -# Used to install the data to a subdirectory of `datadir`. By default it is the same as `name` -subdirectory = "foodata" -# Copy the pre-generated data files found in {root_dir}/{from} to {datadir}/{to}/{matched subdirs} -# If {from} is a single path instead of a glob, the destination is {datapath}/{to}. -# datapath is {datadir}/{subdirectory} -asset = [{from="pattern/with/or/without/**/*", to="destination"}] -# Copy the pre-generated data files found in {OUT_DIR}/{from} to {includedir}/{to}/{matched subdirs} -# If {from} is a single path instead of a glob, the destination is {datapath}/{to}. -# datapath is {datadir}/{subdirectory} -generated = [{from="pattern/with/or/without/**/*", to="destination"}] - -[package.metadata.capi.install.include] -# Copy the pre-generated includes found in {root_dir}/{from} to {includedir}/{to}/{matched subdirs} -# If {from} is a single path instead of a glob, the destination is {includepath}/{to}. -# includepath is {includedir}/{header.subdirectory} -asset = [{from="pattern/with/or/without/**/*", to="destination"}] -# Copy the pre-generated includes found in {OUT_DIR}/{from} to {includedir}/{to}/{matched subdirs} -# If {from} is a single path instead of a glob, the destination is {includedpath}/{to}. -# includepath is {includedir}/{header.subdirectory} -generated = [{from="pattern/with/or/without/**/*", to="destination"}] -``` - -### Notes - -Do **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. +- [Configuration](docs/configuration.md) — `package.metadata.capi` keys +- [Plugin directory vs plugin module](docs/plugins.md) +- [Header generation](docs/headers.md) — cbindgen and cheadergen +- [Troubleshooting](docs/troubleshooting.md) ## Users @@ -229,34 +123,6 @@ [](https://repology.org/project/cargo-c/versions) -## Troubleshooting - -### Shared libraries are not built on musl systems - -When 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)): - -> Error: CliError { error: Some(cannot produce cdylib for <package> as the target x86_64-unknown-linux-musl does not support these crate types), exit_code: 101 } - -This suggests that Rust was not built with `crt-static=false` and it typically happens if Rust has been installed through rustup. - -Shared libraries can be enabled manually in this case, by editing the file `.cargo/config` like so: - -```toml -# .cargo/config - -[target.x86_64-unknown-linux-musl] -rustflags = [ - "-C", "target-feature=-crt-static", -] -``` - -However, 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)). - -### On Debian-like system the libdir includes the host triplet by default - -In order to accomodate Debian's [multiarch](https://wiki.debian.org/Multiarch/Implementation) approach the `cargo-c` default for the `libdir` is `lib/<triplet>` on such system. -Either pass an explicit `--libdir` or pass `--target` to return to the common `libdir=lib` default. - ## Acknowledgements This software has been partially developed in the scope of the H2020 project SIFIS-Home with GA n. 952652. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cargo-c-0.10.23/docs/configuration.md new/cargo-c-0.10.25/docs/configuration.md --- old/cargo-c-0.10.23/docs/configuration.md 1970-01-01 01:00:00.000000000 +0100 +++ new/cargo-c-0.10.25/docs/configuration.md 2026-08-23 22:16:10.000000000 +0200 @@ -0,0 +1,119 @@ +# Configuration + +Override cargo-c through `package.metadata.capi` in `Cargo.toml`. + +```toml +[package.metadata.capi] +# Configures the minimum required cargo-c version. Trying to run with an +# older version causes an error. +min_version = "0.6.10" +``` + +## Header generation + +See also [Header generation](headers.md) for cbindgen vs cheadergen. + +```toml +[package.metadata.capi.header] +# Used as header file name. By default this is equal to the crate name. +# The name can be with or without the header filename extension `.h` +name = "new_name" +# Install the header into a subdirectory with the name of the crate. This +# is enabled by default, pass `false` or "" to disable it. +subdirectory = "libfoo-2.0/foo" +# Generate the header file with `cbindgen`, or copy a pre-generated header +# from the `assets` subdirectory. By default a header is generated. +generation = true +# Can be use to disable header generation completely. +# This can be used when generating dynamic modules instead of an actual library. +enabled = true +# Whether to emit library version constants (e.g. `FOO_MAJOR`, `FOO_MINOR` and +# `FOO_PATCH`) at the top of the header file. Enabled by default. +emit_version_constants = true +``` + +## `pkg-config` file generation + +```toml +[package.metadata.capi.pkg_config] +# Used as the package name in the pkg-config file and defaults to the crate name. +name = "libfoo" +# Used as the pkg-config file name and defaults to the crate name. +filename = "libfoo-2.0" +# Used as the package description in the pkg-config file and defaults to the crate description. +description = "some description" +# Used as the package version in the pkg-config file and defaults to the crate version. +version = "1.2.3" +# Used as the Requires field in the pkg-config file, if defined +requires = "gstreamer-1.0, gstreamer-base-1.0" +# Used as the Requires.private field in the pkg-config file, if defined +requires_private = "gobject-2.0, glib-2.0 >= 2.56.0, gmodule-2.0" +# Strip the include search path from the last n components, useful to support installing in a +# subdirectory but then include with the path. By default it is 0. +strip_include_path_components = 1 +``` + +## Library generation + +```toml +[package.metadata.capi.library] +# Used as the library name and defaults to the crate name. This might get +# prefixed with `lib` depending on the target platform. +name = "new_name" +# dlopen plugin *module*. See docs/plugins.md. +# Requires `install_subdir`. Incompatible with `versioning = true`. +plugin = false +# Used as library version and defaults to the crate version. How this is used +# depends on the target platform. +version = "1.2.3" +# Used to install the library to a subdirectory of `libdir`. +# Required when `plugin = true`. +install_subdir = "gstreamer-1.0" +# Used to disable versioning links when installing the dynamic library +versioning = false +# Instead of using semver, select a fixed number of version components for your SONAME version suffix: +# Setting this to 1 with a version of 0.0.0 allows a suffix of `.so.0` +# Setting this to 3 always includes the full version in the SONAME (indicate any update is ABI breaking) +#version_suffix_components = 2 +# Add `-Cpanic=abort` to the RUSTFLAGS automatically, it may be useful in case +# something might panic in the crates used by the library. +rustflags = "-Cpanic=abort" +# Used to disable the generation of additional import library file in platforms +# that have the concept such as Windows +import_library = false + +[package.metadata.capi.library.target.'cfg(target_os = "linux")'] +# Add target-specific rustflags, the are folded with the main rustflags above +# Note that multiple --version-script support is heavily linker dependent. +rustflags = "-Clink-arg=-Wl,--version-script=assets/version.map" +``` + +## Custom data install + +```toml +[package.metadata.capi.install.data] +# Used to install the data to a subdirectory of `datadir`. By default it is the same as `name` +subdirectory = "foodata" +# Copy the pre-generated data files found in {root_dir}/{from} to {datadir}/{to}/{matched subdirs} +# If {from} is a single path instead of a glob, the destination is {datapath}/{to}. +# datapath is {datadir}/{subdirectory} +asset = [{from="pattern/with/or/without/**/*", to="destination"}] +# Copy the pre-generated data files found in {OUT_DIR}/{from} to {includedir}/{to}/{matched subdirs} +# If {from} is a single path instead of a glob, the destination is {datapath}/{to}. +# datapath is {datadir}/{subdirectory} +generated = [{from="pattern/with/or/without/**/*", to="destination"}] + +[package.metadata.capi.install.include] +# Copy the pre-generated includes found in {root_dir}/{from} to {includedir}/{to}/{matched subdirs} +# If {from} is a single path instead of a glob, the destination is {includepath}/{to}. +# includepath is {includedir}/{header.subdirectory} +asset = [{from="pattern/with/or/without/**/*", to="destination"}] +# Copy the pre-generated includes found in {OUT_DIR}/{from} to {includedir}/{to}/{matched subdirs} +# If {from} is a single path instead of a glob, the destination is {includedpath}/{to}. +# includepath is {includedir}/{header.subdirectory} +generated = [{from="pattern/with/or/without/**/*", to="destination"}] +``` + +## Notes + +Do **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. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cargo-c-0.10.23/docs/headers.md new/cargo-c-0.10.25/docs/headers.md --- old/cargo-c-0.10.23/docs/headers.md 1970-01-01 01:00:00.000000000 +0100 +++ new/cargo-c-0.10.25/docs/headers.md 2026-08-23 22:16:10.000000000 +0200 @@ -0,0 +1,64 @@ +# Header generation + +By default cargo-c generates a C header with [cbindgen](https://github.com/mozilla/cbindgen). +See [`package.metadata.capi.header`](configuration.md#header-generation) for the +keys that control the filename, install subdirectory, and whether a header is +generated at all. + +Add a [`cbindgen.toml`](https://github.com/eqrion/cbindgen/blob/master/docs.md#cbindgentoml) +with at least an include guard; set `language = "C"` if you do not want C++. + +If the bindings live in a separate crate and the header is hand-written or +produced elsewhere: + +- Keep a `capi` feature so cargo-c can identify the package in a workspace. +- Set `package.metadata.capi.header.generation` to `false` (or `enabled = false` + to skip headers completely). +- Optionally install a pre-generated header with + [`package.metadata.capi.install.include`](configuration.md#custom-data-install). + +## Using cheadergen + +Instead of `cbindgen`, you can use [`cheadergen`](https://cheadergen.com/) to +generate C headers. cheadergen uses the `rustdoc-json` output from the Rust +compiler to generate more accurate bindings, including doc comments from your +Rust code. + +1. Install cheadergen and its required nightly toolchain: + + ```sh + cargo install cheadergen_cli + rustup install nightly -c rust-docs-json + ``` + +2. Disable cargo-c's automatic header generation (which uses cbindgen): + + ```toml + [package.metadata.capi.header] + generation = false + ``` + +3. Add a build script that runs cheadergen before cargo-c: + + ```rust + // build.rs + fn main() { + // Generate header with cheadergen + std::process::Command::new("cheadergen") + .arg("generate") + .arg("--output") + .arg("include/my_crate.h") + .status() + .expect("cheadergen failed"); + } + ``` + +4. Configure cargo-c to install the pre-generated header: + + ```toml + [package.metadata.capi.install.include] + asset = [{ from = "include/my_crate.h", to = "" }] + ``` + +For more details on cheadergen, see the +[official documentation](https://cheadergen.com/getting-started/install). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cargo-c-0.10.23/docs/plugins.md new/cargo-c-0.10.25/docs/plugins.md --- old/cargo-c-0.10.23/docs/plugins.md 1970-01-01 01:00:00.000000000 +0100 +++ new/cargo-c-0.10.25/docs/plugins.md 2026-08-23 22:16:10.000000000 +0200 @@ -0,0 +1,76 @@ +# Plugin directory vs plugin module + +`install_subdir` and `plugin` are two different layers. Mixing them up is how +unprefixed, versioned libraries end up in the default libdir. + +| | C library (default) | Plugin directory (`install_subdir` only) | Plugin module (`plugin = true`) | +|---|---|---|---| +| Example | rav1e, rustls-ffi | [gst-plugins-rs](https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs) | PAM, Apache | +| Prefix | `lib{name}` | `lib{name}` | `{name}` | +| Versioning | default on | usually off | forced off | +| Install | `$libdir` | `$libdir/$subdir` | `$libdir/$subdir` only | +| `.a` / `.pc` / headers / implib | yes | yes (GST static) | skipped (headers default off) | +| SONAME / install_name | `lib{name}.so.*` | same | `{name}.so` | + +`library.name` is always the unprefixed identifier. Only `plugin = true` stops +cargo-c from adding `lib`. rustc still emits `lib$name.so` in the build +directory; only the installed name and the linker soname drop the prefix. + +## Plugin directory + +A C library that happens to be loaded from a subdirectory of `libdir`. +GStreamer is the reference: + +```toml +[lib] +name = "gstcdg" +crate-type = ["cdylib", "rlib"] + +[features] +capi = [] + +[package.metadata.capi.header] +enabled = false + +[package.metadata.capi.library] +install_subdir = "gstreamer-1.0" +versioning = false +import_library = false +``` + +`cargo cinstall --prefix=/usr` installs `libgstcdg.so` into +`/usr/lib/gstreamer-1.0`. The `lib` prefix stays; `.a` / `.pc` are still +produced for static linking. On Windows, `install_subdir` already copies the +rustc DLL name into that subdirectory instead of `bindir`. + +Do **not** set `plugin = true` for this case. + +## Plugin module + +A dlopen module, not something linked with `-lfoo`. PAM, Apache modules, and +similar loaders look up a basename that is the public name: + +```toml +[lib] +name = "pam_cgroup" +crate-type = ["cdylib", "rlib"] + +[features] +capi = [] + +[package.metadata.capi.library] +plugin = true +install_subdir = "security" +name = "pam_cgroup" +``` + +That installs `$libdir/security/pam_cgroup.so` (no `lib` prefix, no +`pam_cgroup.so.0.1.0`). The linker soname / install_name matches the installed +file. `.a`, `.pc`, and Windows import libraries are not installed; headers +default to off unless `package.metadata.capi.header.enabled` is set explicitly. + +`plugin = true` without a non-empty `install_subdir`, or together with +`versioning = true`, is an error. + +NSS-style `libnss_files.so.2` is a versioned, prefixed library that happens to +be dlopened: leave `plugin` unset. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cargo-c-0.10.23/docs/troubleshooting.md new/cargo-c-0.10.25/docs/troubleshooting.md --- old/cargo-c-0.10.23/docs/troubleshooting.md 1970-01-01 01:00:00.000000000 +0100 +++ new/cargo-c-0.10.25/docs/troubleshooting.md 2026-08-23 22:16:10.000000000 +0200 @@ -0,0 +1,37 @@ +# Troubleshooting + +## Shared libraries are not built on musl systems + +When 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)): + +> Error: CliError { error: Some(cannot produce cdylib for \<package\> as the target x86_64-unknown-linux-musl does not support these crate types), exit_code: 101 } + +This suggests that Rust was not built with `crt-static=false` and it typically +happens if Rust has been installed through rustup. + +Shared libraries can be enabled manually in this case, by editing the file +`.cargo/config` like so: + +```toml +# .cargo/config + +[target.x86_64-unknown-linux-musl] +rustflags = [ + "-C", "target-feature=-crt-static", +] +``` + +However, 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)). + +## On Debian-like systems the libdir includes the host triplet by default + +In order to accommodate Debian's +[multiarch](https://wiki.debian.org/Multiarch/Implementation) approach the +`cargo-c` default for the `libdir` is `lib/<triplet>` on such systems. +Either pass an explicit `--libdir` or pass `--target` to return to the common +`libdir=lib` default. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cargo-c-0.10.23/src/build.rs new/cargo-c-0.10.25/src/build.rs --- old/cargo-c-0.10.23/src/build.rs 2026-06-01 08:21:05.000000000 +0200 +++ new/cargo-c-0.10.25/src/build.rs 2026-08-23 22:16:10.000000000 +0200 @@ -11,7 +11,9 @@ use cargo::core::{FeatureValue, Package, PackageId, Target, TargetKind, Workspace}; use cargo::ops::{self, CompileFilter, CompileOptions, FilterRule, LibRule}; use cargo::util::command_prelude::{ArgMatches, ArgMatchesExt, ProfileChecking, UserIntent}; +use cargo::util::context::WarningHandling; use cargo::util::interning::InternedString; +use cargo::util::log_message::LogMessage; use cargo::util::BuildLogger; use cargo::{CliResult, GlobalContext}; @@ -168,7 +170,14 @@ writeln!(def_file, "EXPORTS")?; for export in dll_file.exports()? { - def_file.write_all(export.name())?; + let export = export?; + let name = match export.name() { + object::read::NameOrOrdinal::Name(n) => n, + object::read::NameOrOrdinal::Ordinal(o) => { + anyhow::bail!("ordinal-only export {o} cannot be listed in a .def file") + } + }; + def_file.write_all(name)?; def_file.write_all(b"\n")?; } @@ -381,9 +390,23 @@ pub version_suffix_components: Option<VersionSuffix>, pub import_library: bool, pub rustflags: Vec<String>, + /// dlopen plugin module: unprefixed name, no SONAME versioning, + /// `install_subdir` required. Refuses unprefixed/versioned installs into + /// the default libdir. Distinct from a C library that merely uses + /// `install_subdir` as a plugin directory (e.g. GStreamer). + pub plugin: bool, } impl LibraryCApiConfig { + /// `libfoo` or `foo`, for soname / install basename without extension. + pub fn unix_basename(&self) -> String { + if self.plugin { + self.name.clone() + } else { + format!("lib{}", self.name) + } + } + pub fn sover(&self) -> String { let major = self.version.major; let minor = self.version.minor; @@ -402,6 +425,32 @@ } } +/// Plugin modules are dlopened, not linked with `-lfoo`. The installed +/// basename is unprefixed, so they must not land in the default libdir and +/// must not grow SONAME versioning. +pub(crate) fn validate_plugin_mode( + plugin: bool, + install_subdir: Option<&str>, + versioning_explicitly_true: bool, +) -> anyhow::Result<()> { + if !plugin { + return Ok(()); + } + if !install_subdir.is_some_and(|s| !s.is_empty()) { + anyhow::bail!( + "`plugin = true` requires a non-empty `install_subdir` \ + (unprefixed libraries must not be installed into the default libdir)" + ); + } + if versioning_explicitly_true { + anyhow::bail!( + "`plugin = true` cannot be combined with `versioning = true` \ + (versioned unprefixed names are a footgun)" + ); + } + Ok(()) +} + #[derive(Debug, Default, Hash)] pub struct InstallCApiConfig { pub include: Vec<InstallTarget>, @@ -530,7 +579,9 @@ }) .unwrap_or_else(|| Ok(String::from(name)))?; - let header = if let Some(capi) = capi { + let header_enabled_explicit = header.as_ref().and_then(|h| h.get("enabled")).is_some(); + + let mut header = if let Some(capi) = capi { HeaderCApiConfig { name: header .as_ref() @@ -623,6 +674,7 @@ let mut version_suffix_components = None; let mut import_library = true; let mut rustflags = Vec::new(); + let mut plugin = false; if let Some(library) = library { if let Some(override_name) = library.get("name").and_then(|v| v.as_str()) { @@ -663,6 +715,11 @@ .and_then(|v| v.as_bool()) .unwrap_or(true); + plugin = library + .get("plugin") + .and_then(|v| v.as_bool()) + .unwrap_or(false); + if let Some(args) = library.get("rustflags").and_then(|v| v.as_str()) { rustflags.extend(make_args(args)); } @@ -690,6 +747,23 @@ versioning = false; } + let versioning_explicitly_true = library + .and_then(|l| l.get("versioning")) + .and_then(|v| v.as_bool()) + == Some(true); + validate_plugin_mode( + plugin, + install_subdir.as_deref(), + versioning_explicitly_true, + )?; + if plugin { + versioning = false; + import_library = false; + if !header_enabled_explicit { + header.enabled = false; + } + } + let library = LibraryCApiConfig { name: lib_name, version, @@ -698,6 +772,7 @@ version_suffix_components, import_library, rustflags, + plugin, }; let default_assets_include = InstallTargetPaths { @@ -903,6 +978,33 @@ } } +fn build_logger(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<Option<BuildLogger>> { + let logger = BuildLogger::maybe_new(ws, &options.build_config)?; + + if let Some(ref logger) = logger { + let rustc = ws.gctx().load_global_rustc(Some(ws))?; + let num_cpus = std::thread::available_parallelism() + .ok() + .map(|x| x.get() as u64); + logger.log(LogMessage::BuildStarted { + command: std::env::args_os() + .map(|arg| arg.to_string_lossy().into_owned()) + .collect(), + cwd: ws.gctx().cwd().to_path_buf(), + host: rustc.host.to_string(), + jobs: options.build_config.jobs, + num_cpus, + profile: options.build_config.requested_profile.to_string(), + rustc_version: rustc.version.to_string(), + rustc_version_verbose: rustc.verbose_version.clone(), + target_dir: ws.target_dir().as_path_unlocked().to_path_buf(), + workspace_root: ws.root().to_path_buf(), + }); + } + + Ok(logger) +} + fn compile_with_exec( ws: &Workspace<'_>, options: &CompileOptions, @@ -911,9 +1013,13 @@ root_output: &Path, args: &ArgMatches, ) -> CargoResult<HashMap<PackageId, PathBuf>> { - ws.emit_warnings()?; + let parse_pass_output = cargo::diagnostics::passes::emit_parse_diagnostics( + ws, + cargo::diagnostics::rules::PARSE_PASS_RULES, + )?; let interner = UnitInterner::new(); - let logger = BuildLogger::maybe_new(ws, &options.build_config)?; + let logger = build_logger(ws, options)?; + let mut bcx = create_bcx(ws, options, &interner, logger.as_ref())?; let unit_graph = &bcx.unit_graph; let extra_compiler_args = &mut bcx.extra_compiler_args; @@ -956,9 +1062,20 @@ unit_graph::emit_serialized_unit_graph(&bcx.roots, &bcx.unit_graph, ws.gctx())?; return Ok(HashMap::new()); } + cargo::core::gc::auto_gc(bcx.gctx); let cx = cargo::core::compiler::BuildRunner::new(&bcx)?; - let r = cx.compile(exec)?; + let r = if options.build_config.dry_run { + cx.dry_run()? + } else { + cx.compile(exec)? + }; + + if ws.gctx().warning_handling()? == WarningHandling::Deny + && (r.lint_warning_count + parse_pass_output.lint_warning_count) > 0 + { + anyhow::bail!("warnings are denied by `build.warnings` configuration") + } let out_dirs = r .cdylibs @@ -1418,10 +1535,41 @@ version_suffix_components: None, import_library: true, rustflags: vec![], + plugin: false, } } #[test] + fn unix_basename_adds_lib_prefix_by_default() { + let library = make_test_library_config("0.1.0"); + assert_eq!(library.unix_basename(), "libexample"); + } + + #[test] + fn unix_basename_drops_lib_prefix_for_plugin() { + let mut library = make_test_library_config("0.1.0"); + library.plugin = true; + library.name = "pam_cgroup".into(); + assert_eq!(library.unix_basename(), "pam_cgroup"); + } + + #[test] + fn plugin_mode_requires_install_subdir() { + let err = validate_plugin_mode(true, None, false).unwrap_err(); + assert!(err.to_string().contains("install_subdir")); + let err = validate_plugin_mode(true, Some(""), false).unwrap_err(); + assert!(err.to_string().contains("install_subdir")); + validate_plugin_mode(true, Some("security"), false).unwrap(); + validate_plugin_mode(false, None, true).unwrap(); + } + + #[test] + fn plugin_mode_rejects_versioning() { + let err = validate_plugin_mode(true, Some("security"), true).unwrap_err(); + assert!(err.to_string().contains("versioning")); + } + + #[test] pub fn test_semver_zero_zero_zero() { let library = make_test_library_config("0.0.0"); let sover = library.sover(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cargo-c-0.10.23/src/build_targets.rs new/cargo-c-0.10.25/src/build_targets.rs --- old/cargo-c-0.10.23/src/build_targets.rs 2026-06-01 08:21:05.000000000 +0200 +++ new/cargo-c-0.10.25/src/build_targets.rs 2026-08-23 22:16:10.000000000 +0200 @@ -67,7 +67,7 @@ capi_config: &CApiConfig, use_meson_naming_convention: bool, ) -> anyhow::Result<BuildTargets> { - let pc = targetdir.join(format!("{}.pc", &capi_config.pkg_config.filename)); + let pc = targetdir.join(format!("{}.pc", capi_config.pkg_config.filename)); let include = if capi_config.header.enabled && capi_config.header.generation { Some(targetdir.join(&capi_config.header.name).with_extension("h")) } else { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cargo-c-0.10.23/src/install.rs new/cargo-c-0.10.25/src/install.rs --- old/cargo-c-0.10.23/src/install.rs 2026-06-01 08:21:05.000000000 +0200 +++ new/cargo-c-0.10.25/src/install.rs 2026-08-23 22:16:10.000000000 +0200 @@ -121,13 +121,13 @@ impl UnixLibNames { pub(crate) fn new(lib_type: LibType, library: &LibraryCApiConfig) -> Option<Self> { - let lib_name = &library.name; let lib_version = &library.version; let main_version = library.sover(); + let base = library.unix_basename(); match lib_type { LibType::So => { - let lib = format!("lib{lib_name}.so"); + let lib = format!("{base}.so"); let lib_with_full_ver = format!( "{}.{}.{}.{}", lib, lib_version.major, lib_version.minor, lib_version.patch @@ -141,12 +141,12 @@ }) } LibType::Dylib => { - let lib = format!("lib{lib_name}.dylib"); - let lib_with_main_ver = format!("lib{lib_name}.{main_version}.dylib"); + let lib = format!("{base}.dylib"); + let lib_with_main_ver = format!("{base}.{main_version}.dylib"); let lib_with_full_ver = format!( - "lib{}.{}.{}.{}.dylib", - lib_name, lib_version.major, lib_version.minor, lib_version.patch + "{}.{}.{}.{}.dylib", + base, lib_version.major, lib_version.minor, lib_version.patch ); Some(Self { canonical: lib, @@ -193,6 +193,44 @@ } } +#[cfg(test)] +mod unix_lib_names_tests { + use super::*; + use crate::build::LibraryCApiConfig; + use semver::Version; + + fn lib(plugin: bool) -> LibraryCApiConfig { + LibraryCApiConfig { + name: "pam_cgroup".into(), + version: Version::parse("0.1.0").unwrap(), + install_subdir: plugin.then(|| "security".into()), + versioning: !plugin, + version_suffix_components: None, + import_library: true, + rustflags: vec![], + plugin, + } + } + + #[test] + fn so_keeps_lib_prefix_by_default() { + let n = UnixLibNames::new(LibType::So, &lib(false)).unwrap(); + assert_eq!(n.canonical, "libpam_cgroup.so"); + } + + #[test] + fn plugin_so_has_no_lib_prefix() { + let n = UnixLibNames::new(LibType::So, &lib(true)).unwrap(); + assert_eq!(n.canonical, "pam_cgroup.so"); + } + + #[test] + fn plugin_dylib_has_no_lib_prefix() { + let n = UnixLibNames::new(LibType::Dylib, &lib(true)).unwrap(); + assert_eq!(n.canonical, "pam_cgroup.dylib"); + } +} + pub fn cinstall(ws: &Workspace, packages: &[CPackage]) -> anyhow::Result<()> { for pkg in packages { let paths = &pkg.install_paths; @@ -209,15 +247,17 @@ let install_path_data = append_to_destdir(destdir.as_deref(), &paths.datadir); create_dir_all(&install_path_lib)?; - create_dir_all(&install_path_pc)?; + if !capi_config.library.plugin { + create_dir_all(&install_path_pc)?; - ws.gctx().shell().status("Installing", "pkg-config file")?; + ws.gctx().shell().status("Installing", "pkg-config file")?; - copy( - ws, - &build_targets.pc, - install_path_pc.join(build_targets.pc.file_name().unwrap()), - )?; + copy( + ws, + &build_targets.pc, + install_path_pc.join(build_targets.pc.file_name().unwrap()), + )?; + } if capi_config.header.enabled { ws.gctx().shell().status("Installing", "header file")?; @@ -238,10 +278,12 @@ } if let Some(ref static_lib) = build_targets.static_lib { - ws.gctx().shell().status("Installing", "static library")?; - let file_name = build_targets.static_output_file_name().unwrap(); + if !capi_config.library.plugin { + ws.gctx().shell().status("Installing", "static library")?; + let file_name = build_targets.static_output_file_name().unwrap(); - copy(ws, static_lib, install_path_lib.join(file_name))?; + copy(ws, static_lib, install_path_lib.join(file_name))?; + } } if let Some(ref shared_lib) = build_targets.shared_lib { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cargo-c-0.10.23/src/pkg_config_gen.rs new/cargo-c-0.10.25/src/pkg_config_gen.rs --- old/cargo-c-0.10.23/src/pkg_config_gen.rs 2026-06-01 08:21:05.000000000 +0200 +++ new/cargo-c-0.10.25/src/pkg_config_gen.rs 2026-08-23 22:16:10.000000000 +0200 @@ -301,6 +301,7 @@ version_suffix_components: None, import_library: true, rustflags: Vec::default(), + plugin: false, }, install: Default::default(), }, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cargo-c-0.10.23/src/target.rs new/cargo-c-0.10.25/src/target.rs --- old/cargo-c-0.10.23/src/target.rs 2026-06-01 08:21:05.000000000 +0200 +++ new/cargo-c-0.10.25/src/target.rs 2026-08-23 22:16:10.000000000 +0200 @@ -94,6 +94,7 @@ let mut lines = Vec::new(); let lib_name = &capi_config.library.name; + let unix_name = capi_config.library.unix_basename(); let version = &capi_config.library.version; let major = version.major; @@ -106,7 +107,7 @@ let sover = capi_config.library.sover(); if os == "android" { - lines.push(format!("-Wl,-soname,lib{lib_name}.so")); + lines.push(format!("-Wl,-soname,{unix_name}.so")); } else if os == "linux" || os == "freebsd" || os == "dragonfly" @@ -117,18 +118,18 @@ || os == "hurd" { lines.push(if capi_config.library.versioning { - format!("-Wl,-soname,lib{lib_name}.so.{sover}") + format!("-Wl,-soname,{unix_name}.so.{sover}") } else { - format!("-Wl,-soname,lib{lib_name}.so") + format!("-Wl,-soname,{unix_name}.so") }); } else if os == "macos" || os == "ios" || os == "tvos" || os == "visionos" { let line = if capi_config.library.versioning { - format!("-Wl,-install_name,{1}/lib{0}.{5}.dylib,-current_version,{2}.{3}.{4},-compatibility_version,{5}", - lib_name, libdir.display(), major, minor, patch, sover) + format!("-Wl,-install_name,{1}/{0}.{5}.dylib,-current_version,{2}.{3}.{4},-compatibility_version,{5}", + unix_name, libdir.display(), major, minor, patch, sover) } else { format!( - "-Wl,-install_name,{1}/lib{0}.dylib", - lib_name, + "-Wl,-install_name,{1}/{0}.dylib", + unix_name, libdir.display() ) }; ++++++ cargo-c.obsinfo ++++++ --- /var/tmp/diff_new_pack.LO6eae/_old 2026-09-10 11:47:18.065280927 +0200 +++ /var/tmp/diff_new_pack.LO6eae/_new 2026-09-10 11:47:18.071281179 +0200 @@ -1,5 +1,5 @@ name: cargo-c -version: 0.10.23 -mtime: 1780294865 -commit: cfdb2752fabf40711d535011c371a8b1c20a1be2 +version: 0.10.25 +mtime: 1787516170 +commit: a228fd974eb1334dc4c8033bc401a4832b3b4ab4 ++++++ vendor.tar.xz ++++++ /work/SRC/openSUSE:Factory/cargo-c/vendor.tar.xz /work/SRC/openSUSE:Factory/.cargo-c.new.1265/vendor.tar.xz differ: char 15, line 1
