1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
|
#!/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
}
dep_files_to_pkgs() {
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
}
rust_dep_files() {
cat "$CARGO_TARGET_DIR/deps"/*.d \
| sed -nre 's ^\S*/('"$CARGO_REGISTRY"'/[^/]*)/.* '"$(readlink -f "$PWD")/"'\1 gp' \
| sort -u \
| xargs -r readlink -f
}
rust_libs() {
{ which rustc; rust_dep_files; } | dep_files_to_pkgs
}
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
sed -nre 's ^cargo:rustc-link-lib=static=(.*) \1 '"$output"' gp' "$output"
done | while read lib output; do
local containing_crate="$(basename "$(dirname "$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; }
echo >&2 "$0: found static lib $lib at $libfile"
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 [ "$(readlink -f "$libfile")" = "$(readlink -f "$PWD")" ]; then
# Note that this exception only applies in the case that where you are building
# the Debian package for $containing_crate itself. In the case where you are
# building a Debian package for crate X depending on $containing_crate, the
# latter still has to output the dh-cargo:deb-built-using in their build.rs so
# that the Debian package for crate X can correctly set Built-Using themselves.
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 "$(readlink -f "$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
local src="$(dpkg-query -f '${source:Package}' --show "$pkg")"
local srcver="$(dpkg-query -f '${source:Version}' --show "$pkg")"
case "$srcleft" in
2) exit 1;;
1) built_using="${built_using}$src (= $srcver), ";;
esac
built_using_x="${built_using_x}$src (= $srcver), "
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"
} | LC_ALL=C.utf-8 sort -u | output "$@"
|