]>
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 | |
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 | ||
136 | output() { | |
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 | ||
155 | native_libs="$(native_libs)" # capture output outside of pipe so set -e works | |
156 | { | |
157 | rust_libs | |
158 | test -z "$native_libs" || echo "$native_libs" | |
159 | } | output "$@" |