]> git.proxmox.com Git - dh-cargo.git/commitdiff
Generate ${cargo:Built-Using} and ${cargo:X-Cargo-Built-Using} substvars
authorXimin Luo <infinity0@debian.org>
Sun, 12 Aug 2018 19:25:21 +0000 (12:25 -0700)
committerXimin Luo <infinity0@debian.org>
Sun, 12 Aug 2018 19:25:21 +0000 (12:25 -0700)
cargo.pm
debian/changelog
debian/dh-cargo.install
dh-cargo-built-using [new file with mode: 0755]

index e67bf9d52ad5ebb581d01dd003aa960737def2cd..5dfd721b6c6cb7aeeb4d303f433acbf733d9c46b 100644 (file)
--- a/cargo.pm
+++ b/cargo.pm
@@ -168,6 +168,8 @@ sub test {
     doit("cargo", "build", "--verbose", "--verbose", @{$this->{j}},
         "--target", $this->{host_rust_type},
         "-Zavoid-dev-deps");
+    # test generating Built-Using fields
+    doit("env", "CARGO_CHANNEL=debug", "/usr/share/cargo/dh-cargo-built-using");
 }
 
 sub install {
@@ -204,7 +206,9 @@ sub install {
         # hopefully cargo will provide a better solution in future https://github.com/rust-lang/cargo/issues/5457
         my $out_dir = `ls -td "target/$this->{host_rust_type}/release/build/$this->{crate}"-*/out | head -n1`;
         $out_dir =~ s/\n$//;
-        doit("ln", "-sf", "../$out_dir", "debian/cargo_out_dir") if $out_dir ne "";
+        doit("ln", "-sfT", "../$out_dir", "debian/cargo_out_dir") if $out_dir ne "";
+        # generate Built-Using fields
+        doit("/usr/share/cargo/dh-cargo-built-using", $this->{binpkg});
     }
 }
 
index 66e10bab94f4bdfcec116a1343101abeb609bfb7..63407d62ccc8ad5823ab4eb766fd0276f306f52a 100644 (file)
@@ -1,3 +1,9 @@
+dh-cargo (8) UNRELEASED; urgency=medium
+
+  * Generate ${cargo:Built-Using} and ${cargo:X-Cargo-Built-Using} substvars.
+
+ -- Ximin Luo <infinity0@debian.org>  Sat, 11 Aug 2018 22:37:25 -0700
+
 dh-cargo (7) unstable; urgency=medium
 
   * Be more verbose, as recommended by Policy.
index b67121d2063909dfac7f7b39e52335af536294a9..15d6df1902a24d88b4bf959811346d654a6450c1 100644 (file)
@@ -1 +1,2 @@
 cargo.pm /usr/share/perl5/Debian/Debhelper/Buildsystem/
+dh-cargo-built-using /usr/share/cargo
diff --git a/dh-cargo-built-using b/dh-cargo-built-using
new file mode 100755 (executable)
index 0000000..649b5e7
--- /dev/null
@@ -0,0 +1,157 @@
+#!/bin/sh
+# Generates Built-Using after a successful cargo build.
+# Run this in the package top-level directory where debian/ is.
+
+set -e
+
+DEB_HOST_RUST_TYPE="${DEB_HOST_RUST_TYPE:-$(printf "include /usr/share/rustc/architecture.mk\nall:\n\techo \$(DEB_HOST_RUST_TYPE)\n" | make --no-print-directory -sf -)}"
+CARGO_REGISTRY="${CARGO_REGISTRY:-debian/cargo_registry}"
+CARGO_CHANNEL="${CARGO_CHANNEL:-release}"
+# useful for testing:
+# CARGO_REGISTRY="$HOME/.cargo/registry/src/github.com-1ecc6299db9ec823" DEB_HOST_RUST_TYPE="." CARGO_CHANNEL=debug
+
+CARGO_TARGET_DIR="target/$DEB_HOST_RUST_TYPE/$CARGO_CHANNEL"
+CARGO_TARGET_DIR_ABS="$(readlink -f "$CARGO_TARGET_DIR")"
+
+CPRIGHT_FORMAT="https://www.debian.org/doc/packaging-manuals/copyright-format/1.0"
+SRCLEFT_LICENSES="$(echo GPL LGPL AGPL GFDL MPL CDDL CPL Artistic Perl QPL | tr ' ' '\n')"
+pkg_has_srcleft_license() {
+       local pkg="$1"
+       local ver="$2"
+       local f="/usr/share/doc/$pkg/copyright"
+       if ! sed -nre 's        ^Format: (.*)   \1      gp' "$f" | grep -qiw "$CPRIGHT_FORMAT"; then
+               echo >&2 "$0: abort: Not in machine-readable format: $f"
+               echo 2
+       elif sed -nre 's        ^X-Binary-Requires-Source: (.*) \1      gp' "$f" | grep -qiw yes; then
+               echo 1
+       elif sed -nre 's        ^License: (.*)  \1      gp' "$f" | grep -qiwF "$SRCLEFT_LICENSES"; then
+               echo 1
+       else
+               echo 0
+       fi
+}
+
+rust_libs() {
+       cat "$CARGO_TARGET_DIR/deps"/*.d \
+       | sed -nre 's   ^(('"$PWD/"')?'"$CARGO_REGISTRY"'/[^/]*)/.*     \1      gp' \
+       | sort -u \
+       | xargs -r readlink -f \
+       | xargs -r dpkg -S \
+       | sed -nre 's   (.*): .*        \1      gp' \
+       | xargs -r dpkg-query --show \
+       | while read pkg ver; do echo "$pkg $ver $(pkg_has_srcleft_license "${pkg%:*}" "$ver")"; done
+       # pkg_has_srcleft_license should be accurate for all rust crates, no need to give a $containing_crate
+       # this is due to nature of crate copyright info, and the debian rust packaging policy
+}
+
+gcc_default_searchdirs() {
+       gcc -print-search-dirs \
+       | sed -nre 's   ^libraries: (.*)        \1      gp' \
+       | tr ':' '\n' \
+       | sed -e 's     ^=      '"$(gcc -print-sysroot)"'       g' \
+       | xargs readlink -m 2>/dev/null # suppress errors caused by early pipe closure
+}
+
+rust_search_lib() {
+       local lib="$1"
+       {
+       cat
+       # rust does not actually search normal paths when linking static libs
+       # - see https://github.com/rust-lang/rust/issues/43118
+       # - see also `fn link_rlib` in back/link.rs which calls
+       #   `pub fn find_library` in back/archive.rs which generates the error message
+       #gcc_default_searchdirs
+       } | while read searchdir; do
+               #echo >&2 "searching $searchdir for static lib $lib"
+               local f="$(readlink -m "$searchdir/lib${lib}.a")"
+               if test -f "$f"; then
+                       printf "%s\n" "$f"
+                       break
+               fi
+       done
+}
+
+native_libs() {
+       ls -1d "$CARGO_TARGET_DIR/build"/*/output 2>/dev/null | while read output; do
+               local containing_crate="$(basename "$(dirname "$output")")"
+               local lib=$(sed -nre 's ^cargo:rustc-link-lib=static=(.*)       \1      gp' "$output")
+               test -n "$lib" || continue
+               local libfile=$(sed -nre 's     ^cargo:rustc-link-search=native=(.*)    \1      gp' "$output" | rust_search_lib "$lib")
+               local srcleft=""
+               test -n "$libfile" || { echo >&2 "$0: abort: could not find static lib '$lib'; rustc should have failed already?"; exit 1; }
+               if [ "${libfile#$CARGO_TARGET_DIR_ABS/}" != "$libfile" ]; then
+                       # static library source code embedded in crate
+                       local srcstat="$(sed -nre 's    ^dh-cargo:deb-built-using='"$lib"'=([01]=.*)    \1      gp' "$output")"
+                       case "$srcstat" in
+                       0=*|1=*)
+                               srcleft="${srcstat%%=*}"
+                               libfile="${srcstat#*=}"
+                               if [ "$libfile" = "$PWD" ]; then
+                                       echo >&2 "$0: static library derived from $libfile which is the top-level crate being built, no need to add Built-Using"
+                                       continue
+                               fi
+                               ;;
+                       *)
+                               echo >&2 "$0: abort: could not determine source-distribution conditions of ${libfile#$CARGO_TARGET_DIR_ABS/}."
+                               echo >&2 "You must patch build.rs of ${containing_crate%-*} to output 'println!(\"dh-cargo:deb-built-using=$lib=\$s={}\", env::var(\"CARGO_MANIFEST_DIR\").unwrap());' where:"
+                               echo >&2 "- \$s is 1 if the license(s) of the included static libs require source distribution alongside binaries, otherwise 0"
+                               exit 1
+                               ;;
+                       esac
+               fi
+               local wpkg="$(dpkg -S "$libfile")"
+               test -n "$wpkg" || { echo >&2 "$0: abort: could not find Debian package for file $libfile"; exit 1; }
+               local pkgstat="$(echo "$wpkg" | sed -nre 's     (.*): .*        \1      gp' | xargs -r dpkg-query --show)"
+               local pkg="$(echo "$pkgstat" | cut -f1)"
+               local ver="$(echo "$pkgstat" | cut -f2)"
+               # static library source code embedded in crate (from earlier)
+               if [ -n "$srcleft" ]; then
+                       echo "$pkg $ver $srcleft"
+               # static libraries from another Debian package
+               elif sed -nre 's        ^dh-cargo:deb-built-using='"$lib"'=0~=(.*)      \1      gp' "$output" | { echo "${pkg%:*} $ver" | grep -qExf /dev/fd/3; } 3<&0; then
+                       echo "$pkg $ver 0"
+               elif sed -nre 's        ^dh-cargo:deb-built-using='"$lib"'=1~=(.*)      \1      gp' "$output" | { echo "${pkg%:*} $ver" | grep -qExf /dev/fd/3; } 3<&0; then
+                       echo "$pkg $ver 1"
+               else
+                       # guess the conditions based on the whole d/copyright file
+                       # this loses granularity, e.g. gcc is mostly distributed as GPL-3 but the libbacktrace portion is BSD-3
+                       # to retain granularity the crate package maintainer should patch build.rs as suggested
+                       echo >&2 "$0: warning: guessing source-distribution conditions of $libfile, this may be inaccurate."
+                       echo >&2 "$0: warning: patch build.rs to suppress the above warning"
+                       srcleft="$(pkg_has_srcleft_license "${pkg%:*}" "$ver")"
+                       if [ "$srcleft" -gt 1 ]; then
+                               echo >&2 "You must patch build.rs of ${containing_crate%-*} to output 'dh-cargo:deb-built-using=$lib=\$s~=\$PAT' where:"
+                               echo >&2 "- \$s is 1 if the license(s) of the included static libs require source distribution alongside binaries, otherwise 0"
+                               echo >&2 "- \$PAT is an egrep pattern matching the \"\$pkg \$ver\" combinations that satisfy \$s"
+                               echo >&2 "  for example '$pkg .*' matches the currently-relevant package, $pkg $ver"
+                               exit 1
+                       fi
+                       echo "$pkg $ver $srcleft"
+               fi
+       done
+}
+
+output() {
+       local binpkg="$1"
+       if [ -z "$binpkg" ]; then
+               cat
+       else
+               local built_using=""
+               local built_using_x=""
+               while read pkg ver srcleft; do
+                       case "$srcleft" in
+                       2)      exit 1;;
+                       1)      built_using="${built_using}$pkg (= $ver), ";;
+                       esac
+                       built_using_x="${built_using_x}$pkg (= $ver), "
+               done
+               echo "cargo:Built-Using=${built_using%, }" >> "debian/$binpkg.substvars"
+               echo "cargo:X-Cargo-Built-Using=${built_using_x%, }" >> "debian/$binpkg.substvars"
+       fi
+}
+
+native_libs="$(native_libs)" # capture output outside of pipe so set -e works
+{
+rust_libs
+test -z "$native_libs" || echo "$native_libs"
+} | output "$@"