Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cargo-c support #274

Merged
merged 5 commits into from Mar 8, 2024
Merged

cargo-c support #274

merged 5 commits into from Mar 8, 2024

Conversation

lu-zero
Copy link
Contributor

@lu-zero lu-zero commented Dec 10, 2022

Since @thesamesam asked here a minimal patchset

Improvements over the status-quo:

  • Produces correct dynamic and static libraries on pretty much all the rust tier-2 platforms.
  • Correctly embeds the version information in the C header
  • Supports cross compiling out of box
  • Distributions have already support for it

It does not require to change the other build systems.

@cpu
Copy link
Member

cpu commented Mar 3, 2023

@jsha I think CI might be jammed up on this branch. Could you kick it when you have a chance?

@lu-zero
Copy link
Contributor Author

lu-zero commented Mar 10, 2023

I freshened it again.

@cpu
Copy link
Member

cpu commented Aug 2, 2023

@jsha @ctz Do you folks have any thoughts on this PR? I've rebased on main because it seems like a worthwhile addition to me and it would be nice to get out of the PR queue one way or the other.

I think it might be nice to add CI coverage to prevent any regression in support, but naively adding a task that runs cargo install cargo-c adds 6m runtime to CI (example).

WDYT? If there's interest in merging this work should we do it without the CI task? Alternatively we could use a third party action like cargo-binstall to try and cut down on the runtime. (Worked out a better approach in later comments).

@thesamesam
Copy link
Contributor

We're still relying on this in Gentoo to build a dynamic lib for Apache and curl to use, and would very much appreciate this being merged. cargo-c makes life a lot easier for stuff like this.

@lu-zero
Copy link
Contributor Author

lu-zero commented Aug 2, 2023

@cpu I provide binaries for CI usage, see what we do in rav1e, it shouldn't impact your CI this much. I can try to look into it if you need help :)

@ctz
Copy link
Member

ctz commented Aug 2, 2023

I think if downstream users benefit from and value this, we should support it. What I'm not sure about is whether the existing build system has benefits compared to cargo-c (simplicity perhaps?) which means we should keep both supported in parallel?

@cpu
Copy link
Member

cpu commented Aug 2, 2023

provide binaries for CI usage, see what we do in rav1e, it shouldn't impact your CI this much. I can try to look into it if you need help :)

Ah thank you, that's helpful :-) That approach looks workable. I've added a commit to use it.

@lu-zero One question for you: it looks like the binary releases don't include the ctest subcommand. Is that intentional?

curl -L https://github.com/lu-zero/cargo-c/releases/download/v0.9.22/cargo-c-x86_64-unknown-linux-musl.tar.gz 2>/dev/null | tar -zf - --list
cargo-capi
cargo-cbuild
cargo-cinstall

@lu-zero
Copy link
Contributor Author

lu-zero commented Aug 2, 2023

It is not intentional, thank you for spotting it, ctest apparently is not used by many ^^;

@lu-zero
Copy link
Contributor Author

lu-zero commented Aug 3, 2023

The next release will have it, you can use cargo capi test in the mean time. (feedback on its usage very welcome btw)

@cpu
Copy link
Member

cpu commented Aug 3, 2023

you can use cargo capi test in the mean time.

Perfect, thank you! I've updated the CI task.

@cpu
Copy link
Member

cpu commented Aug 8, 2023

What I'm not sure about is whether the existing build system has benefits compared to cargo-c (simplicity perhaps?) which means we should keep both supported in parallel?

@lu-zero Is this topic something you might have thoughts on as the maintainer of cargo-c?

@lu-zero
Copy link
Contributor Author

lu-zero commented Aug 9, 2023

cargo-c is simpler to use and in general should always do the right thing regarding dylibs, if it is not provided pre-built it has the same level of annoyance of building cargo itself.

I wrote cargo-c after trying to integrate cargo with Makefile (and automake) myself, so at least in my experience cargo-c is what works the best, but I have no problems in building cargo and nowadays most platforms I focus on already distribute cargo-c by themselves :)

Copy link
Member

@cpu cpu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be merged since it has value to downstream consumers and I don't expect the maintenance burden to be large. We can revisit whether to remove existing parts of the build system separately.

@ctz @jsha Would one of you be willing to +1 or suggest changes? I've contributed code to this branch so I think it would be nice to have an independent approval.

@jsha
Copy link
Collaborator

jsha commented Aug 18, 2023

This looks good to me, and the fact that Gentoo is already finding cargo-c useful in packaging is a strong argument in its favor. Just to note, though: I haven't reviewed cargo-c and don't 100% know how it works.

One other thing to note: So far I intentionally haven't added a dynamic library output to the Makefile, because I felt rustls-ffi and rustls aren't stable enough to offer a dynamic library (which tends to carry the expectation of ABI compatbility over a moderately long period of time). I also wanted to read up more on the nuances of supporting dynamic libraries from Rust. However, it sounds like we've wound up accidentally supporting a dynamic library and it hasn't caused problems in practice, so perhaps we should just jump in with both feet?

Also if our goal is that packagers can rely on the cargo-c integration we should document it in the README.

@cpu
Copy link
Member

cpu commented Aug 18, 2023

Also if our goal is that packagers can rely on the cargo-c integration we should document it in the README.

I can take a crack at that in the next few days.

@cpu cpu mentioned this pull request Sep 26, 2023
@kpcyrd
Copy link
Contributor

kpcyrd commented Sep 28, 2023

I did some testing of this patch in #345 (but I'm not a cargo-c expert myself). Any way I can help out here to get this merged?

@cpu
Copy link
Member

cpu commented Sep 29, 2023

Any way I can help out here to get this merged?

If you wanted to pick up the request for documentation for cargo-c in the README that would be helpful! I haven't had a chance and my "in the next few days" estimate was wildly optimistic 😅

@thesamesam
Copy link
Contributor

This looks good to me, and the fact that Gentoo is already finding cargo-c useful in packaging is a strong argument in its favor. Just to note, though: I haven't reviewed cargo-c and don't 100% know how it works.

One other thing to note: So far I intentionally haven't added a dynamic library output to the Makefile, because I felt rustls-ffi and rustls aren't stable enough to offer a dynamic library (which tends to carry the expectation of ABI compatbility over a moderately long period of time). I also wanted to read up more on the nuances of supporting dynamic libraries from Rust. However, it sounds like we've wound up accidentally supporting a dynamic library and it hasn't caused problems in practice, so perhaps we should just jump in with both feet?

FWIW, I've not bound you to any sort of ABI guarantee here, so don't worry about that part unless you want to. That is, we build rustls-ffi with a SONAME equal to the version, and we rebuild all consumers on each new version.

Stable ABI would be nice if/when you want to offer it, but I've not sort of assumed a stable ABI or anything - so you have total freedom still.

Thanks for the support as well here folks!

@cpu
Copy link
Member

cpu commented Oct 16, 2023

Hi folks,

I've done some more homework looking into this topic and I'm keen on landing this work. I think it's the right direction and I'd like to commit to figuring out what the remaining concerns/blockers might be and how we can address them. Improving the quality of our packaged library and addressing the dynamic linking use case both feel like important steps towards making rustls and rustls-ffi a viable alternative to openssl longer term.

Pulling out some earlier comments to address directly:

This looks good to me, and the fact that Gentoo is already finding cargo-c useful in packaging is a strong argument in its favor.

Based on #345 and @kpcyrd's comments I think we can also say that it would be useful for the ArchLinux folks.

I've also done some poking around in NixPkgs and see a few cargo-c based packages there as well (rav1e, libdovi, gstreamer (for the rust bits), and libimagequant). The rustls-ffi package in NixPkgs is currently using the Makefile and a static lib but I suspect I could convert it over to cargo-c after this lands without much hassle.

In sum: I'm encouraged by the fact that three of the Linux distributions I associate most with high quality packaging find cargo-c a useful tool and appear to be invested in the ecosystem.

What I'm not sure about is whether the existing build system has benefits compared to cargo-c (simplicity perhaps?) which means we should keep both supported in parallel?

I think we should start by maintaining the two in parallel. I don't expect it will be much additional work (cargo-c is practically configuration-free and we already have the Makefile). The downstream availability of cargo-c in popular Linux distributions is also quite promising looking.

I do think there's a path towards removing the existing Makefile based tooling for generating the static library when we're ready. I'm less certain about the cmake CMakeLists.txt bits for Windows - I would appreciate folks with more experience with both CMake and Windows weighing in on that topic.

Just to note, though: I haven't reviewed cargo-c and don't 100% know how it works.

I've spent some time reviewing cargo-c and I think I have an OK sense of its mechanics. I also found this blog post helpful for understanding the motivation. If there are particular points you want to understand better I'd be happy to try and do the work to summarize them.

Above all, I'm very reassured by @lu-zero's participation in this issue, and others upstream (e.g. lu-zero/cargo-c#345). I get the sense we can find help with the upstream project when/if we need it.

One other thing to note: So far I intentionally haven't added a dynamic library output to the Makefile, because I felt rustls-ffi and rustls aren't stable enough to offer a dynamic library (which tends to carry the expectation of ABI compatbility over a moderately long period of time).

This was an important call-out. I think we absolutely need to be clear + direct about ABI compatibility being off the table at the current time.

I also wanted to read up more on the nuances of supporting dynamic libraries from Rust. However, it sounds like we've wound up accidentally supporting a dynamic library and it hasn't caused problems in practice, so perhaps we should just jump in with both feet?

+1 - My feeling here is that it will be hard to build confidence in this area without trying it and learning from our mistakes :-) I think if we make sure the ABI compatibility non-guarantee is well understood, and that we advertise dynamic library support as experimental we can build confidence in this area while also hopefully avoiding giving the impression that this is a battle-tested solution.

Also if our goal is that packagers can rely on the cargo-c integration we should document it in the README.

I've tacked on a commit here that updates the README with some documentation. In particular it:

  • Describes the current static library approach, mentioning some of the downsides and emphasizing use of the Makefile.
  • Describes ABI compatibility as an explicit non-goal at this time, and emphasizes the full library version should be used as the SONAME in all cases.
  • Describes using cargo-c to build the dynamic library, and linking it using pkg-config to do the heavy lifting.

I'm sure the wording I've used in some places could use adjustment, feedback is most welcome. It will also need to be reconciled with #355.

I also explicitly avoided describing using cargo-c to build the static library. This works fine as far as I can tell, but while we're getting our feet wet I think its better to keep static library users aimed towards the Makefile and emphasize cargo-c for the dynamic linking use-case.

FWIW, I've not bound you to any sort of ABI guarantee here, so don't worry about that part unless you want to. That is, we build rustls-ffi with a SONAME equal to the version, and we rebuild all consumers on each new version.

Great, 👍 This is what I've captured in the README's advice on ABI guarantees as well.


Thanks everyone. I hope we can get this across the line and in the meantime I do appreciate your patience as we work through the details.

@cpu
Copy link
Member

cpu commented Oct 17, 2023

It will also need to be reconciled with #355.

Done ☑️

@cpu
Copy link
Member

cpu commented Nov 29, 2023

There's another downstream consumer of rustls-ffi, hs-rustls, that provides Haskell bindings for Rustls. They're also carrying a patch to build a dynamic library for rustls-ffi.

@kpcyrd
Copy link
Contributor

kpcyrd commented Nov 29, 2023

The latest cargo-c now gives you more control over your SONAME and I consider lu-zero/cargo-c#345 as completed (let me know if you need more):

[package.metadata.capi.library]
name = "rustls"
version_suffix_components = 3
rustflags = "-Cmetadata=rustls-ffi"

This embeds the full version (all 3 components) into the shared object SONAME, e.g. librustls.so.0.11.0, so any new version is considered ABI breaking.

With a configuration like this, Arch Linux could remove patchelf --set-soname "librustls.so.${pkgver}" "target/$CARCH-unknown-linux-gnu/release/librustls.so" from the PKGBUILD and instead you get to configure this yourself through the source code you release.

lu-zero and others added 3 commits November 29, 2023 15:53
This will prevent bitrot with the cargo-c support.
This commit details our current thinking w.r.t static vs dynamic linking
for rustls-ffi. It also adds initial documentation of using `cargo-c` to
build a dynamic library. In particular we emphasize that:

a) we make **no** ABI stability guarantees
b) the dynamic library/cargo-c support is considered experimental
@cpu
Copy link
Member

cpu commented Nov 29, 2023

@kpcyrd Thanks! I updated the Cargo.toml metadata to specify version_suffix_components = 3.

@kpcyrd
Copy link
Contributor

kpcyrd commented Dec 7, 2023

Arch Linux is now shipping librustls 0.12.0 with this PKGBUILD:

# Maintainer: kpcyrd <kpcyrd[at]archlinux[dot]org>

pkgname=librustls
pkgver=0.12.0
pkgrel=1
pkgdesc="Use rustls from languages other than Rust"
arch=('x86_64')
license=('Apache-2.0' 'MIT')
url='https://github.com/rustls/rustls-ffi'
makedepends=(
  cargo-c
  rust
)
provides=('librustls.so')
options=(!lto)
source=(https://github.com/rustls/rustls-ffi/archive/v${pkgver}/${pkgname}-${pkgver}.tar.gz
        shared-linking.patch)
sha256sums=('7eaffd02528155f561742bd712f5454e68fb771b3eb55d63bf0520429ab717f1'
            '6f1fd82c456e106c265d9778c4a972e84de7fcfc992202993460edb0bd2fa300')

prepare() {
  cd rustls-ffi-${pkgver}
  cargo fetch --locked --target "$CARCH-unknown-linux-gnu"
  patch -Np1 -i ../shared-linking.patch
}

build() {
  cd rustls-ffi-${pkgver}
  RUSTC_BOOTSTRAP=1 cargo cbuild --release --frozen --prefix=/usr
}

package() {
  cd rustls-ffi-${pkgver}
  cargo cinstall --release --frozen --prefix /usr --destdir "${pkgdir}"
  install -Dm644 -t "${pkgdir}/usr/share/licenses/${pkgname}" LICENSE-*
}

# vim: ts=2 sw=2 et:

It's using the official dependency lockfile that is part of the 0.12.0 release and the applied patch is the latest version of this pull request. The patchelf call/dependency is not necessary anymore and has been removed.

Copy link
Collaborator

@jsha jsha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, let's land it!

README.md Outdated

## Static Library

In its current for rustls-ffi's `Makefile` infrastructure will generate a static
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
In its current for rustls-ffi's `Makefile` infrastructure will generate a static
In its current form rustls-ffi's `Makefile` infrastructure will generate a static

README.md Outdated
Comment on lines 113 to 114
pkg-config --libs rustls
pkg-config --cflags rustls
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this seems to suggest that these pkg-config commands directly manipulate $LDLIBS and $CFLAGS.

Suggested change
pkg-config --libs rustls
pkg-config --cflags rustls
LDLIBS="$(pkg-config --libs rustls)"
CFLAGS="$(pkg-config --cflags rustls)"

@jsha
Copy link
Collaborator

jsha commented Mar 8, 2024

Bypassing the branch protections for the Windows / CMake build (already broken, not by this branch).

@jsha jsha merged commit a2adbd1 into rustls:main Mar 8, 2024
19 of 22 checks passed
@cpu
Copy link
Member

cpu commented Mar 11, 2024

Thanks for merging! 🎉

@kpcyrd
Copy link
Contributor

kpcyrd commented Mar 11, 2024

Awesome to see this merged, can we get a new release? :)

@cpu
Copy link
Member

cpu commented Mar 11, 2024

can we get a new release? :)

I'm hoping we'll get a new major release shortly with Rustls 0.23 (#389) but in the meantime I agree it makes sense to do a point release. Preparing that in #395

@cpu
Copy link
Member

cpu commented Mar 21, 2024

can we get a new release? :)

@kpcyrd v0.12.1 is here, fresh from the crate factory.

@kpcyrd
Copy link
Contributor

kpcyrd commented Mar 21, 2024

Amazing, thanks! :)

Arch Linux is now distributing librustls using this PKGBUILD (no more patching, just plain tarballs and cargo-c):

# Maintainer: kpcyrd <kpcyrd[at]archlinux[dot]org>

pkgname=librustls
pkgver=0.12.1
pkgrel=1
pkgdesc="Use rustls from languages other than Rust"
arch=('x86_64')
license=('Apache-2.0' 'MIT')
url='https://github.com/rustls/rustls-ffi'
depends=(
  gcc-libs
  glibc
)
makedepends=(
  cargo-c
  rust
)
provides=('librustls.so')
options=(!lto)
source=(https://github.com/rustls/rustls-ffi/archive/v${pkgver}/${pkgname}-${pkgver}.tar.gz)
sha256sums=('3a545127987517faf4a200e746481b7eeab6f3c4058b6bf7dea143584c96947b')
b2sums=('0fddfcb5980811a1b80db2bfb578132d627ad8b47f1abeeaf052a7135f43b2e29888aa6aaa89ccd315299b73b147126cd67be41b104b1911d06c8324dee0b0e9')

prepare() {
  cd rustls-ffi-${pkgver}
  cargo fetch --locked --target "$(rustc -vV | sed -n 's/host: //p')"
}

build() {
  cd rustls-ffi-${pkgver}
  RUSTC_BOOTSTRAP=1 cargo cbuild --release --frozen --prefix=/usr
}

package() {
  cd rustls-ffi-${pkgver}
  cargo cinstall --release --frozen --prefix /usr --destdir "${pkgdir}"
  install -Dm644 -t "${pkgdir}/usr/share/licenses/${pkgname}" LICENSE-*
}

# vim: ts=2 sw=2 et:

It ships the following package content:

librustls /usr/
librustls /usr/include/
librustls /usr/include/rustls.h
librustls /usr/lib/
librustls /usr/lib/librustls.so
librustls /usr/lib/librustls.so.0.12.1
librustls /usr/lib/pkgconfig/
librustls /usr/lib/pkgconfig/rustls.pc
librustls /usr/share/
librustls /usr/share/licenses/
librustls /usr/share/licenses/librustls/
librustls /usr/share/licenses/librustls/LICENSE-APACHE
librustls /usr/share/licenses/librustls/LICENSE-ISC
librustls /usr/share/licenses/librustls/LICENSE-MIT

Let me know if anything needs to be changed at some point in the future. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants