]>
Commit | Line | Data |
---|---|---|
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 | ||
5 | set -e | |
6 | ||
7 | 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 -)}" | |
8 | CARGO_REGISTRY="${CARGO_REGISTRY:-debian/cargo_registry}" | |
9 | CARGO_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 | ||
13 | CARGO_TARGET_DIR="target/$DEB_HOST_RUST_TYPE/$CARGO_CHANNEL" | |
14 | CARGO_TARGET_DIR_ABS="$(readlink -f "$CARGO_TARGET_DIR")" | |
15 | ||
16 | CPRIGHT_FORMAT="https://www.debian.org/doc/packaging-manuals/copyright-format/1.0" | |
17 | SRCLEFT_LICENSES="$(echo GPL LGPL AGPL GFDL MPL CDDL CPL Artistic Perl QPL | tr ' ' '\n')" | |
18 | pkg_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 | ||
34 | rust_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 | ||
47 | gcc_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 | ||
55 | rust_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 | ||
74 | native_libs() { | |
75 | ls -1d "$CARGO_TARGET_DIR/build"/*/output 2>/dev/null | while read output; do | |
76 | local containing_crate="$(basename "$(dirname "$output")")" | |
77 | local lib=$(sed -nre 's ^cargo:rustc-link-lib=static=(.*) \1 gp' "$output") | |
78 | test -n "$lib" || continue | |
79 | local libfile=$(sed -nre 's ^cargo:rustc-link-search=native=(.*) \1 gp' "$output" | rust_search_lib "$lib") | |
80 | local srcleft="" | |
81 | test -n "$libfile" || { echo >&2 "$0: abort: could not find static lib '$lib'; rustc should have failed already?"; exit 1; } | |
82 | if [ "${libfile#$CARGO_TARGET_DIR_ABS/}" != "$libfile" ]; then | |
83 | # static library source code embedded in crate | |
84 | local srcstat="$(sed -nre 's ^dh-cargo:deb-built-using='"$lib"'=([01]=.*) \1 gp' "$output")" | |
85 | case "$srcstat" in | |
86 | 0=*|1=*) | |
87 | srcleft="${srcstat%%=*}" | |
88 | libfile="${srcstat#*=}" | |
89 | if [ "$libfile" = "$PWD" ]; then | |
90 | echo >&2 "$0: static library derived from $libfile which is the top-level crate being built, no need to add Built-Using" | |
91 | continue | |
92 | fi | |
93 | ;; | |
94 | *) | |
95 | echo >&2 "$0: abort: could not determine source-distribution conditions of ${libfile#$CARGO_TARGET_DIR_ABS/}." | |
96 | 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:" | |
97 | echo >&2 "- \$s is 1 if the license(s) of the included static libs require source distribution alongside binaries, otherwise 0" | |
98 | exit 1 | |
99 | ;; | |
100 | esac | |
101 | fi | |
102 | local wpkg="$(dpkg -S "$libfile")" | |
103 | test -n "$wpkg" || { echo >&2 "$0: abort: could not find Debian package for file $libfile"; exit 1; } | |
104 | local pkgstat="$(echo "$wpkg" | sed -nre 's (.*): .* \1 gp' | xargs -r dpkg-query --show)" | |
105 | local pkg="$(echo "$pkgstat" | cut -f1)" | |
106 | local ver="$(echo "$pkgstat" | cut -f2)" | |
107 | # static library source code embedded in crate (from earlier) | |
108 | if [ -n "$srcleft" ]; then | |
109 | echo "$pkg $ver $srcleft" | |
110 | # static libraries from another Debian package | |
111 | 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 | |
112 | echo "$pkg $ver 0" | |
113 | 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 | |
114 | echo "$pkg $ver 1" | |
115 | else | |
116 | # guess the conditions based on the whole d/copyright file | |
117 | # this loses granularity, e.g. gcc is mostly distributed as GPL-3 but the libbacktrace portion is BSD-3 | |
118 | # to retain granularity the crate package maintainer should patch build.rs as suggested | |
119 | echo >&2 "$0: warning: guessing source-distribution conditions of $libfile, this may be inaccurate." | |
120 | echo >&2 "$0: warning: patch build.rs to suppress the above warning" | |
121 | srcleft="$(pkg_has_srcleft_license "${pkg%:*}" "$ver")" | |
122 | if [ "$srcleft" -gt 1 ]; then | |
123 | echo >&2 "You must patch build.rs of ${containing_crate%-*} to output 'dh-cargo:deb-built-using=$lib=\$s~=\$PAT' where:" | |
124 | echo >&2 "- \$s is 1 if the license(s) of the included static libs require source distribution alongside binaries, otherwise 0" | |
125 | echo >&2 "- \$PAT is an egrep pattern matching the \"\$pkg \$ver\" combinations that satisfy \$s" | |
126 | echo >&2 " for example '$pkg .*' matches the currently-relevant package, $pkg $ver" | |
127 | exit 1 | |
128 | fi | |
129 | echo "$pkg $ver $srcleft" | |
130 | fi | |
131 | done | |
132 | } | |
133 | ||
134 | output() { | |
135 | local binpkg="$1" | |
136 | if [ -z "$binpkg" ]; then | |
137 | cat | |
138 | else | |
139 | local built_using="" | |
140 | local built_using_x="" | |
141 | while read pkg ver srcleft; do | |
142 | case "$srcleft" in | |
143 | 2) exit 1;; | |
144 | 1) built_using="${built_using}$pkg (= $ver), ";; | |
145 | esac | |
146 | built_using_x="${built_using_x}$pkg (= $ver), " | |
147 | done | |
148 | echo "cargo:Built-Using=${built_using%, }" >> "debian/$binpkg.substvars" | |
149 | echo "cargo:X-Cargo-Built-Using=${built_using_x%, }" >> "debian/$binpkg.substvars" | |
150 | fi | |
151 | } | |
152 | ||
153 | native_libs="$(native_libs)" # capture output outside of pipe so set -e works | |
154 | { | |
155 | rust_libs | |
156 | test -z "$native_libs" || echo "$native_libs" | |
157 | } | output "$@" |