--- /dev/null
+#!/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 "$@"