]> git.proxmox.com Git - dh-cargo.git/blame - dh-cargo-built-using
Make some behaviour more robust
[dh-cargo.git] / dh-cargo-built-using
CommitLineData
36790ab7
XL
1#!/bin/sh
2# Generates Built-Using after a successful cargo build.
3# Run this in the package top-level directory where debian/ is.
4
5set -e
6
7DEB_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 -)}"
8CARGO_REGISTRY="${CARGO_REGISTRY:-debian/cargo_registry}"
9CARGO_CHANNEL="${CARGO_CHANNEL:-release}"
10# useful for testing:
11# CARGO_REGISTRY="$HOME/.cargo/registry/src/github.com-1ecc6299db9ec823" DEB_HOST_RUST_TYPE="." CARGO_CHANNEL=debug
12
13CARGO_TARGET_DIR="target/$DEB_HOST_RUST_TYPE/$CARGO_CHANNEL"
14CARGO_TARGET_DIR_ABS="$(readlink -f "$CARGO_TARGET_DIR")"
15
16CPRIGHT_FORMAT="https://www.debian.org/doc/packaging-manuals/copyright-format/1.0"
17SRCLEFT_LICENSES="$(echo GPL LGPL AGPL GFDL MPL CDDL CPL Artistic Perl QPL | tr ' ' '\n')"
18pkg_has_srcleft_license() {
19 local pkg="$1"
20 local ver="$2"
21 local f="/usr/share/doc/$pkg/copyright"
22 if ! sed -nre 's ^Format: (.*) \1 gp' "$f" | grep -qiw "$CPRIGHT_FORMAT"; then
23 echo >&2 "$0: abort: Not in machine-readable format: $f"
24 echo 2
25 elif sed -nre 's ^X-Binary-Requires-Source: (.*) \1 gp' "$f" | grep -qiw yes; then
26 echo 1
27 elif sed -nre 's ^License: (.*) \1 gp' "$f" | grep -qiwF "$SRCLEFT_LICENSES"; then
28 echo 1
29 else
30 echo 0
31 fi
32}
33
34rust_libs() {
35 cat "$CARGO_TARGET_DIR/deps"/*.d \
36 | sed -nre 's ^(('"$PWD/"')?'"$CARGO_REGISTRY"'/[^/]*)/.* \1 gp' \
37 | sort -u \
38 | xargs -r readlink -f \
39 | xargs -r dpkg -S \
40 | sed -nre 's (.*): .* \1 gp' \
41 | xargs -r dpkg-query --show \
42 | while read pkg ver; do echo "$pkg $ver $(pkg_has_srcleft_license "${pkg%:*}" "$ver")"; done
43 # pkg_has_srcleft_license should be accurate for all rust crates, no need to give a $containing_crate
44 # this is due to nature of crate copyright info, and the debian rust packaging policy
45}
46
47gcc_default_searchdirs() {
48 gcc -print-search-dirs \
49 | sed -nre 's ^libraries: (.*) \1 gp' \
50 | tr ':' '\n' \
51 | sed -e 's ^= '"$(gcc -print-sysroot)"' g' \
52 | xargs readlink -m 2>/dev/null # suppress errors caused by early pipe closure
53}
54
55rust_search_lib() {
56 local lib="$1"
57 {
58 cat
59 # rust does not actually search normal paths when linking static libs
60 # - see https://github.com/rust-lang/rust/issues/43118
61 # - see also `fn link_rlib` in back/link.rs which calls
62 # `pub fn find_library` in back/archive.rs which generates the error message
63 #gcc_default_searchdirs
64 } | while read searchdir; do
65 #echo >&2 "searching $searchdir for static lib $lib"
66 local f="$(readlink -m "$searchdir/lib${lib}.a")"
67 if test -f "$f"; then
68 printf "%s\n" "$f"
69 break
70 fi
71 done
72}
73
74native_libs() {
75 ls -1d "$CARGO_TARGET_DIR/build"/*/output 2>/dev/null | while read output; do
8e983617
XL
76 sed -nre 's ^cargo:rustc-link-lib=static=(.*) \1 '"$output"' gp' "$output"
77 done | while read lib output; do
36790ab7 78 local containing_crate="$(basename "$(dirname "$output")")"
36790ab7 79 test -n "$lib" || continue
8e983617 80 local libfile="$(sed -nre 's ^cargo:rustc-link-search=native=(.*) \1 gp' "$output" | rust_search_lib "$lib")"
36790ab7
XL
81 local srcleft=""
82 test -n "$libfile" || { echo >&2 "$0: abort: could not find static lib '$lib'; rustc should have failed already?"; exit 1; }
eecce01b 83 echo >&2 "$0: found static lib $lib at $libfile"
36790ab7
XL
84 if [ "${libfile#$CARGO_TARGET_DIR_ABS/}" != "$libfile" ]; then
85 # static library source code embedded in crate
86 local srcstat="$(sed -nre 's ^dh-cargo:deb-built-using='"$lib"'=([01]=.*) \1 gp' "$output")"
87 case "$srcstat" in
88 0=*|1=*)
89 srcleft="${srcstat%%=*}"
90 libfile="${srcstat#*=}"
eecce01b 91 if [ "$(readlink -f "$libfile")" = "$(readlink -f "$PWD")" ]; then
36790ab7
XL
92 echo >&2 "$0: static library derived from $libfile which is the top-level crate being built, no need to add Built-Using"
93 continue
94 fi
95 ;;
96 *)
97 echo >&2 "$0: abort: could not determine source-distribution conditions of ${libfile#$CARGO_TARGET_DIR_ABS/}."
98 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:"
99 echo >&2 "- \$s is 1 if the license(s) of the included static libs require source distribution alongside binaries, otherwise 0"
100 exit 1
101 ;;
102 esac
103 fi
104 local wpkg="$(dpkg -S "$libfile")"
105 test -n "$wpkg" || { echo >&2 "$0: abort: could not find Debian package for file $libfile"; exit 1; }
106 local pkgstat="$(echo "$wpkg" | sed -nre 's (.*): .* \1 gp' | xargs -r dpkg-query --show)"
107 local pkg="$(echo "$pkgstat" | cut -f1)"
108 local ver="$(echo "$pkgstat" | cut -f2)"
109 # static library source code embedded in crate (from earlier)
110 if [ -n "$srcleft" ]; then
111 echo "$pkg $ver $srcleft"
112 # static libraries from another Debian package
113 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
114 echo "$pkg $ver 0"
115 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
116 echo "$pkg $ver 1"
117 else
118 # guess the conditions based on the whole d/copyright file
119 # this loses granularity, e.g. gcc is mostly distributed as GPL-3 but the libbacktrace portion is BSD-3
120 # to retain granularity the crate package maintainer should patch build.rs as suggested
121 echo >&2 "$0: warning: guessing source-distribution conditions of $libfile, this may be inaccurate."
122 echo >&2 "$0: warning: patch build.rs to suppress the above warning"
123 srcleft="$(pkg_has_srcleft_license "${pkg%:*}" "$ver")"
124 if [ "$srcleft" -gt 1 ]; then
125 echo >&2 "You must patch build.rs of ${containing_crate%-*} to output 'dh-cargo:deb-built-using=$lib=\$s~=\$PAT' where:"
126 echo >&2 "- \$s is 1 if the license(s) of the included static libs require source distribution alongside binaries, otherwise 0"
127 echo >&2 "- \$PAT is an egrep pattern matching the \"\$pkg \$ver\" combinations that satisfy \$s"
128 echo >&2 " for example '$pkg .*' matches the currently-relevant package, $pkg $ver"
129 exit 1
130 fi
131 echo "$pkg $ver $srcleft"
132 fi
133 done
134}
135
136output() {
137 local binpkg="$1"
138 if [ -z "$binpkg" ]; then
139 cat
140 else
141 local built_using=""
142 local built_using_x=""
143 while read pkg ver srcleft; do
144 case "$srcleft" in
145 2) exit 1;;
146 1) built_using="${built_using}$pkg (= $ver), ";;
147 esac
148 built_using_x="${built_using_x}$pkg (= $ver), "
149 done
150 echo "cargo:Built-Using=${built_using%, }" >> "debian/$binpkg.substvars"
151 echo "cargo:X-Cargo-Built-Using=${built_using_x%, }" >> "debian/$binpkg.substvars"
152 fi
153}
154
155native_libs="$(native_libs)" # capture output outside of pipe so set -e works
156{
157rust_libs
158test -z "$native_libs" || echo "$native_libs"
159} | output "$@"