#198 automatically generate license information for a crate's dependencies
Opened 3 months ago by decathorpe. Modified 2 months ago

Generating the "effective" license of statically linked Rust binaries is one of the last, really annoying manual steps in Rust packaging. It would be great if we could automate at least some of the steps that are required here.

I used to use this script to output the list of licenses for all installed Rust crates in the RPM buildroot after a mock build with "--without check" (to skip dev-dependencies, which are not linked into shipped binaries):

for i in $(rpm -qa | grep "rust-.*-devel"); do
   rpm -q $i --qf "%{LICENSE}\n";
done | sort | uniq

This works fine, but it doesn't list the licenses by individual components, which would be necessary for a license breakdown.

As a better version, I started to use this:

dnf repoquery --cacheonly "rust-*-devel" --installed --qf "%{LICENSE}: %{source_name} %{version}"

This prints a list of "crate: license" (including compat packages) that can be included in .spec files.

However, both approaches are slightly wrong, insofar as they exclude dev-dependencies (only required for building / running test executables, not the shipped binary), but they don't exclude build-dependencies.

@alebastr did some digging and came up with a way to query cargo itself for the information we need:

cargo tree --workspace --offline --edges 'normal' --prefix none --format '{l}: {p}#' | cut -d\# -f1 | grep -v "($PWD" | sort -u

This command will print the list of "$LICENSE: $CRATE $VERSION". It also works when run during %build stage of an RPM build, using the local RPM based crate registry as source of data.

It would be great if we could put that into a new macro, something like %cargo_license, which would write this information to a file, like LICENSE.dependencies, which can then be included as %license LICENSE.dependencies in %files. I've started doing this manually, but having a macro to do all the heavy lifting would be great (and it would also eliminate the need to keep track of this list in a separate file).

rust2rpm could even automatically include usage of the new %cargo_license macro if it detects that a package builds a binary. Or even include it unconditionally in %cargo_build, since it doesn't hurt to run it for all builds, either, I guess.

Then the packager would only need to collect the licenses into the value of the "License" tag of the subpackage that contains the binary, which is much less work than what's required today (and which is also very confusing to Rust packaging newcomers).

Metadata Update from @decathorpe:
- Issue set to the milestone: 23

3 months ago

I managed to simplify the "cargo tree" command a little, and also made small adaptations:

cargo tree --workspace --offline --edges normal,no-proc-macro --no-dedupe --target all --prefix none --format "{l}: {p}" | sed -e "s: ($(pwd))::g" | sort -u
  • proc-macro dependencies are pruned from the tree (they are only run to produce code, they are not linked into the final binary themselves)
  • do not deduplicate dependencies (this simplifies processing, because no random (*) markers for "deduplicated dependencies" appear in the list)
  • include dependencies for all targets (this might be wrong in general, but we already strip all foreign dependencies for everything we ship in our "local registry", so this is actually correct)

cargo tree also supports setting feature flags like other cargo commands (i.e. -f foo,bar and --all-features are both valid arguments)

Can we make this into some kind of official RPM macro, similar to %cargo_build et al.?

Login to comment on this ticket.

Related Pull Requests
  • #217 Last updated 2 months ago