Gentoo Archives: gentoo-portage-dev

From: Zac Medico <zmedico@g.o>
To: gentoo-portage-dev@l.g.o
Cc: Zac Medico <zmedico@g.o>
Subject: [gentoo-portage-dev] [PATCH] Add dostrip for EAPI 7
Date: Mon, 26 Mar 2018 20:02:51
Message-Id: 20180326200157.30381-1-zmedico@gentoo.org
1 This patch includes the essential parts of the dostrip implementation
2 from portage-mgorny. It also bans the non-standard prepstrip and
3 prepallstrip helpers in EAPI 7, with a die message suggesting to
4 use 'dostrip' instead. All of the prepstrip code has moved to
5 bin/estrip, without any changes except the addition of argument
6 parsing for estrip --ignore, --queue, and --deque modes which are
7 equivalent to the corresponding ecompressdir modes.
8
9 Bug: https://bugs.gentoo.org/203891
10 ---
11 bin/eapi.sh | 4 +
12 bin/ebuild-helpers/prepall | 2 +-
13 bin/ebuild-helpers/prepallstrip | 4 +
14 bin/ebuild-helpers/prepstrip | 400 +----------------------------------
15 bin/ebuild.sh | 2 +-
16 bin/estrip | 458 ++++++++++++++++++++++++++++++++++++++++
17 bin/misc-functions.sh | 6 +
18 bin/phase-helpers.sh | 29 +++
19 bin/save-ebuild-env.sh | 4 +-
20 9 files changed, 509 insertions(+), 400 deletions(-)
21 create mode 100755 bin/estrip
22
23 diff --git a/bin/eapi.sh b/bin/eapi.sh
24 index 326eb387e..f9a4744e9 100644
25 --- a/bin/eapi.sh
26 +++ b/bin/eapi.sh
27 @@ -76,6 +76,10 @@ ___eapi_has_docompress() {
28 [[ ! ${1-${EAPI-0}} =~ ^(0|1|2|3)$ ]]
29 }
30
31 +___eapi_has_dostrip() {
32 + [[ ${1-${EAPI-0}} =~ ^(0|1|2|3|4|4-python|4-slot-abi|5|5-hdepend|5-progress|6)$ ]]
33 +}
34 +
35 ___eapi_has_nonfatal() {
36 [[ ! ${1-${EAPI-0}} =~ ^(0|1|2|3)$ ]]
37 }
38 diff --git a/bin/ebuild-helpers/prepall b/bin/ebuild-helpers/prepall
39 index 44643bb58..bc77af4a1 100755
40 --- a/bin/ebuild-helpers/prepall
41 +++ b/bin/ebuild-helpers/prepall
42 @@ -19,7 +19,7 @@ fi
43 prepallman
44 prepallinfo
45
46 -prepallstrip
47 +___eapi_has_dostrip || prepallstrip
48
49 if has chflags $FEATURES ; then
50 # Restore all the file flags that were saved at the beginning of prepall.
51 diff --git a/bin/ebuild-helpers/prepallstrip b/bin/ebuild-helpers/prepallstrip
52 index 59fa7cc61..4bde1f4b2 100755
53 --- a/bin/ebuild-helpers/prepallstrip
54 +++ b/bin/ebuild-helpers/prepallstrip
55 @@ -4,6 +4,10 @@
56
57 source "${PORTAGE_BIN_PATH}"/isolated-functions.sh || exit 1
58
59 +if ___eapi_has_dostrip; then
60 + die "${0##*/}: ${0##*/} has been banned for EAPI '$EAPI'; use 'dostrip' instead"
61 +fi
62 +
63 if ! ___eapi_has_prefix_variables; then
64 ED=${D}
65 fi
66 diff --git a/bin/ebuild-helpers/prepstrip b/bin/ebuild-helpers/prepstrip
67 index 2136e0d4d..9db06284d 100755
68 --- a/bin/ebuild-helpers/prepstrip
69 +++ b/bin/ebuild-helpers/prepstrip
70 @@ -2,402 +2,10 @@
71 # Copyright 1999-2018 Gentoo Foundation
72 # Distributed under the terms of the GNU General Public License v2
73
74 -source "${PORTAGE_BIN_PATH}"/helper-functions.sh || exit 1
75 +source "${PORTAGE_BIN_PATH}"/isolated-functions.sh || exit 1
76
77 -# avoid multiple calls to `has`. this creates things like:
78 -# FEATURES_foo=false
79 -# if "foo" is not in $FEATURES
80 -tf() { "$@" && echo true || echo false ; }
81 -exp_tf() {
82 - local flag var=$1
83 - shift
84 - for flag in "$@" ; do
85 - eval ${var}_${flag}=$(tf has ${flag} ${!var})
86 - done
87 -}
88 -exp_tf FEATURES compressdebug installsources nostrip splitdebug xattr
89 -exp_tf RESTRICT binchecks installsources splitdebug strip
90 -
91 -if ! ___eapi_has_prefix_variables; then
92 - EPREFIX= ED=${D}
93 -fi
94 -
95 -banner=false
96 -SKIP_STRIP=false
97 -if ${RESTRICT_strip} || ${FEATURES_nostrip} ; then
98 - SKIP_STRIP=true
99 - banner=true
100 - ${FEATURES_installsources} || exit 0
101 -fi
102 -
103 -PRESERVE_XATTR=false
104 -if [[ ${KERNEL} == linux ]] && ${FEATURES_xattr} ; then
105 - PRESERVE_XATTR=true
106 - if type -P getfattr >/dev/null && type -P setfattr >/dev/null ; then
107 - dump_xattrs() {
108 - getfattr -d -m - --absolute-names "$1"
109 - }
110 - restore_xattrs() {
111 - setfattr --restore=-
112 - }
113 - else
114 - dump_xattrs() {
115 - PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \
116 - "${PORTAGE_PYTHON:-/usr/bin/python}" \
117 - "${PORTAGE_BIN_PATH}/xattr-helper.py" --dump < <(echo -n "$1")
118 - }
119 - restore_xattrs() {
120 - PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \
121 - "${PORTAGE_PYTHON:-/usr/bin/python}" \
122 - "${PORTAGE_BIN_PATH}/xattr-helper.py" --restore
123 - }
124 - fi
125 -fi
126 -
127 -# look up the tools we might be using
128 -for t in STRIP:strip OBJCOPY:objcopy READELF:readelf ; do
129 - v=${t%:*} # STRIP
130 - t=${t#*:} # strip
131 - eval ${v}=\"${!v:-${CHOST}-${t}}\"
132 - type -P -- ${!v} >/dev/null || eval ${v}=${t}
133 -done
134 -
135 -# Figure out what tool set we're using to strip stuff
136 -unset SAFE_STRIP_FLAGS DEF_STRIP_FLAGS SPLIT_STRIP_FLAGS
137 -case $(${STRIP} --version 2>/dev/null) in
138 -*elfutils*) # dev-libs/elfutils
139 - # elfutils default behavior is always safe, so don't need to specify
140 - # any flags at all
141 - SAFE_STRIP_FLAGS=""
142 - DEF_STRIP_FLAGS="--remove-comment"
143 - SPLIT_STRIP_FLAGS="-f"
144 - ;;
145 -*GNU*) # sys-devel/binutils
146 - # We'll leave out -R .note for now until we can check out the relevance
147 - # of the section when it has the ALLOC flag set on it ...
148 - SAFE_STRIP_FLAGS="--strip-unneeded"
149 - DEF_STRIP_FLAGS="-R .comment -R .GCC.command.line -R .note.gnu.gold-version"
150 - SPLIT_STRIP_FLAGS=
151 - ;;
152 -esac
153 -: ${PORTAGE_STRIP_FLAGS=${SAFE_STRIP_FLAGS} ${DEF_STRIP_FLAGS}}
154 -
155 -prepstrip_sources_dir=${EPREFIX}/usr/src/debug/${CATEGORY}/${PF}
156 -
157 -debugedit=$(type -P debugedit)
158 -if [[ -z ${debugedit} ]]; then
159 - debugedit_paths=(
160 - "${EPREFIX}/usr/libexec/rpm/debugedit"
161 - )
162 - for x in "${debugedit_paths[@]}"; do
163 - if [[ -x ${x} ]]; then
164 - debugedit=${x}
165 - break
166 - fi
167 - done
168 -fi
169 -[[ ${debugedit} ]] && debugedit_found=true || debugedit_found=false
170 -debugedit_warned=false
171 -
172 -__multijob_init
173 -
174 -# Setup $T filesystem layout that we care about.
175 -tmpdir="${T}/prepstrip"
176 -rm -rf "${tmpdir}"
177 -mkdir -p "${tmpdir}"/{inodes,splitdebug,sources}
178 -
179 -# Usage: save_elf_sources <elf>
180 -save_elf_sources() {
181 - ${FEATURES_installsources} || return 0
182 - ${RESTRICT_installsources} && return 0
183 - if ! ${debugedit_found} ; then
184 - if ! ${debugedit_warned} ; then
185 - debugedit_warned=true
186 - ewarn "FEATURES=installsources is enabled but the debugedit binary could not be"
187 - ewarn "found. This feature will not work unless debugedit or rpm is installed!"
188 - fi
189 - return 0
190 - fi
191 -
192 - local x=$1
193 -
194 - # since we're editing the ELF here, we should recompute the build-id
195 - # (the -i flag below). save that output so we don't need to recompute
196 - # it later on in the save_elf_debug step.
197 - buildid=$("${debugedit}" -i \
198 - -b "${WORKDIR}" \
199 - -d "${prepstrip_sources_dir}" \
200 - -l "${tmpdir}/sources/${x##*/}.${BASHPID:-$(__bashpid)}" \
201 - "${x}")
202 -}
203 -
204 -# Usage: save_elf_debug <elf> [splitdebug file]
205 -save_elf_debug() {
206 - ${FEATURES_splitdebug} || return 0
207 - ${RESTRICT_splitdebug} && return 0
208 -
209 - # NOTE: Debug files must be installed in
210 - # ${EPREFIX}/usr/lib/debug/${EPREFIX} (note that ${EPREFIX} occurs
211 - # twice in this path) in order for gdb's debug-file-directory
212 - # lookup to work correctly.
213 - local x=$1
214 - local inode_debug=$2
215 - local splitdebug=$3
216 - local d_noslash=${D%/}
217 - local y=${ED%/}/usr/lib/debug/${x:${#d_noslash}}.debug
218 -
219 - # dont save debug info twice
220 - [[ ${x} == *".debug" ]] && return 0
221 -
222 - mkdir -p "${y%/*}"
223 -
224 - if [ -f "${inode_debug}" ] ; then
225 - ln "${inode_debug}" "${y}" || die "ln failed unexpectedly"
226 - else
227 - if [[ -n ${splitdebug} ]] ; then
228 - mv "${splitdebug}" "${y}"
229 - else
230 - local objcopy_flags="--only-keep-debug"
231 - ${FEATURES_compressdebug} && objcopy_flags+=" --compress-debug-sections"
232 - ${OBJCOPY} ${objcopy_flags} "${x}" "${y}"
233 - ${OBJCOPY} --add-gnu-debuglink="${y}" "${x}"
234 - fi
235 - # Only do the following if the debug file was
236 - # successfully created (see bug #446774).
237 - if [ $? -eq 0 ] ; then
238 - local args="a-x,o-w"
239 - [[ -g ${x} || -u ${x} ]] && args+=",go-r"
240 - chmod ${args} "${y}"
241 - ln "${y}" "${inode_debug}" || die "ln failed unexpectedly"
242 - fi
243 - fi
244 -
245 - # if we don't already have build-id from debugedit, look it up
246 - if [[ -z ${buildid} ]] ; then
247 - # convert the readelf output to something useful
248 - buildid=$(${READELF} -n "${x}" 2>/dev/null | awk '/Build ID:/{ print $NF; exit }')
249 - fi
250 - if [[ -n ${buildid} ]] ; then
251 - local buildid_dir="${ED%/}/usr/lib/debug/.build-id/${buildid:0:2}"
252 - local buildid_file="${buildid_dir}/${buildid:2}"
253 - mkdir -p "${buildid_dir}"
254 - [ -L "${buildid_file}".debug ] || ln -s "../../${x:${#D}}.debug" "${buildid_file}.debug"
255 - [ -L "${buildid_file}" ] || ln -s "/${x:${#D}}" "${buildid_file}"
256 - fi
257 -}
258 -
259 -# Usage: process_elf <elf>
260 -process_elf() {
261 - local x=$1 inode_link=$2 strip_flags=${*:3}
262 - local already_stripped lockfile xt_data
263 -
264 - __vecho " ${x:${#ED}}"
265 -
266 - # If two processes try to debugedit or strip the same hardlink at the
267 - # same time, it may corrupt files or cause loss of splitdebug info.
268 - # So, use a lockfile to prevent interference (easily observed with
269 - # dev-vcs/git which creates ~111 hardlinks to one file in
270 - # /usr/libexec/git-core).
271 - lockfile=${inode_link}_lockfile
272 - if ! ln "${inode_link}" "${lockfile}" 2>/dev/null ; then
273 - while [[ -f ${lockfile} ]] ; do
274 - sleep 1
275 - done
276 - unset lockfile
277 - fi
278 -
279 - [ -f "${inode_link}_stripped" ] && already_stripped=true || already_stripped=false
280 -
281 - if ! ${already_stripped} ; then
282 - if ${PRESERVE_XATTR} ; then
283 - xt_data=$(dump_xattrs "${x}")
284 - fi
285 - save_elf_sources "${x}"
286 - fi
287 -
288 - if ${strip_this} ; then
289 -
290 - # see if we can split & strip at the same time
291 - if [[ -n ${SPLIT_STRIP_FLAGS} ]] ; then
292 - local shortname="${x##*/}.debug"
293 - local splitdebug="${tmpdir}/splitdebug/${shortname}.${BASHPID:-$(__bashpid)}"
294 - ${already_stripped} || \
295 - ${STRIP} ${strip_flags} \
296 - -f "${splitdebug}" \
297 - -F "${shortname}" \
298 - "${x}"
299 - save_elf_debug "${x}" "${inode_link}_debug" "${splitdebug}"
300 - else
301 - save_elf_debug "${x}" "${inode_link}_debug"
302 - ${already_stripped} || \
303 - ${STRIP} ${strip_flags} "${x}"
304 - fi
305 - fi
306 -
307 - if ${already_stripped} ; then
308 - rm -f "${x}" || die "rm failed unexpectedly"
309 - ln "${inode_link}_stripped" "${x}" || die "ln failed unexpectedly"
310 - else
311 - ln "${x}" "${inode_link}_stripped" || die "ln failed unexpectedly"
312 - if [[ ${xt_data} ]] ; then
313 - restore_xattrs <<< "${xt_data}"
314 - fi
315 - fi
316 -
317 - [[ -n ${lockfile} ]] && rm -f "${lockfile}"
318 -}
319 -
320 -# The existance of the section .symtab tells us that a binary is stripped.
321 -# We want to log already stripped binaries, as this may be a QA violation.
322 -# They prevent us from getting the splitdebug data.
323 -if ! ${RESTRICT_binchecks} && ! ${RESTRICT_strip} ; then
324 - # We need to do the non-stripped scan serially first before we turn around
325 - # and start stripping the files ourselves. The log parsing can be done in
326 - # parallel though.
327 - log=${tmpdir}/scanelf-already-stripped.log
328 - scanelf -yqRBF '#k%F' -k '!.symtab' "$@" | sed -e "s#^${ED%/}/##" > "${log}"
329 - (
330 - __multijob_child_init
331 - qa_var="QA_PRESTRIPPED_${ARCH/-/_}"
332 - [[ -n ${!qa_var} ]] && QA_PRESTRIPPED="${!qa_var}"
333 - if [[ -n ${QA_PRESTRIPPED} && -s ${log} && \
334 - ${QA_STRICT_PRESTRIPPED-unset} = unset ]] ; then
335 - shopts=$-
336 - set -o noglob
337 - for x in ${QA_PRESTRIPPED} ; do
338 - sed -e "s#^${x#/}\$##" -i "${log}"
339 - done
340 - set +o noglob
341 - set -${shopts}
342 - fi
343 - sed -e "/^\$/d" -e "s#^#/#" -i "${log}"
344 - if [[ -s ${log} ]] ; then
345 - __vecho -e "\n"
346 - eqawarn "QA Notice: Pre-stripped files found:"
347 - eqawarn "$(<"${log}")"
348 - else
349 - rm -f "${log}"
350 - fi
351 - ) &
352 - __multijob_post_fork
353 -fi
354 -
355 -# Since strip creates a new inode, we need to know the initial set of
356 -# inodes in advance, so that we can avoid interference due to trying
357 -# to strip the same (hardlinked) file multiple times in parallel.
358 -# See bug #421099.
359 -if [[ ${USERLAND} == BSD ]] ; then
360 - get_inode_number() { stat -f '%i' "$1"; }
361 -else
362 - get_inode_number() { stat -c '%i' "$1"; }
363 -fi
364 -cd "${tmpdir}/inodes" || die "cd failed unexpectedly"
365 -while read -r x ; do
366 - inode_link=$(get_inode_number "${x}") || die "stat failed unexpectedly"
367 - echo "${x}" >> "${inode_link}" || die "echo failed unexpectedly"
368 -done < <(
369 - # Use sort -u to eliminate duplicates for bug #445336.
370 - (
371 - scanelf -yqRBF '#k%F' -k '.symtab' "$@"
372 - find "$@" -type f ! -type l -name '*.a'
373 - ) | LC_ALL=C sort -u
374 -)
375 -
376 -# Now we look for unstripped binaries.
377 -for inode_link in $(shopt -s nullglob; echo *) ; do
378 -while read -r x
379 -do
380 -
381 - if ! ${banner} ; then
382 - __vecho "strip: ${STRIP} ${PORTAGE_STRIP_FLAGS}"
383 - banner=true
384 - fi
385 -
386 - (
387 - __multijob_child_init
388 - f=$(file "${x}") || exit 0
389 - [[ -z ${f} ]] && exit 0
390 -
391 - if ! ${SKIP_STRIP} ; then
392 - # The noglob funk is to support STRIP_MASK="/*/booga" and to keep
393 - # the for loop from expanding the globs.
394 - # The eval echo is to support STRIP_MASK="/*/{booga,bar}" sex.
395 - set -o noglob
396 - strip_this=true
397 - for m in $(eval echo ${STRIP_MASK}) ; do
398 - [[ /${x#${ED%/}} == ${m} ]] && strip_this=false && break
399 - done
400 - set +o noglob
401 - else
402 - strip_this=false
403 - fi
404 -
405 - # In Prefix we are usually an unprivileged user, so we can't strip
406 - # unwritable objects. Make them temporarily writable for the
407 - # stripping.
408 - was_not_writable=false
409 - if [[ ! -w ${x} ]] ; then
410 - was_not_writable=true
411 - chmod u+w "${x}"
412 - fi
413 -
414 - # only split debug info for final linked objects
415 - # or kernel modules as debuginfo for intermediatary
416 - # files (think crt*.o from gcc/glibc) is useless and
417 - # actually causes problems. install sources for all
418 - # elf types though cause that stuff is good.
419 -
420 - buildid=
421 - if [[ ${f} == *"current ar archive"* ]] ; then
422 - __vecho " ${x:${#ED}}"
423 - if ${strip_this} ; then
424 - # If we have split debug enabled, then do not strip this.
425 - # There is no concept of splitdebug for objects not yet
426 - # linked in (only for finally linked ELFs), so we have to
427 - # retain the debug info in the archive itself.
428 - if ! ${FEATURES_splitdebug} || ${RESTRICT_splitdebug} ; then
429 - ${STRIP} -g "${x}"
430 - fi
431 - fi
432 - elif [[ ${f} == *"SB executable"* || ${f} == *"SB shared object"* ]] ; then
433 - process_elf "${x}" "${inode_link}" ${PORTAGE_STRIP_FLAGS}
434 - elif [[ ${f} == *"SB relocatable"* ]] ; then
435 - process_elf "${x}" "${inode_link}" ${SAFE_STRIP_FLAGS}
436 - fi
437 -
438 - if ${was_not_writable} ; then
439 - chmod u-w "${x}"
440 - fi
441 - ) &
442 - __multijob_post_fork
443 -
444 -done < "${inode_link}"
445 -done
446 -
447 -# With a bit more work, we could run the rsync processes below in
448 -# parallel, but not sure that'd be an overall improvement.
449 -__multijob_finish
450 -
451 -cd "${tmpdir}"/sources/ && cat * > "${tmpdir}/debug.sources" 2>/dev/null
452 -if [[ -s ${tmpdir}/debug.sources ]] && \
453 - ${FEATURES_installsources} && \
454 - ! ${RESTRICT_installsources} && \
455 - ${debugedit_found}
456 -then
457 - __vecho "installsources: rsyncing source files"
458 - [[ -d ${D%/}/${prepstrip_sources_dir#/} ]] || mkdir -p "${D%/}/${prepstrip_sources_dir#/}"
459 - grep -zv '/<[^/>]*>$' "${tmpdir}"/debug.sources | \
460 - (cd "${WORKDIR}"; LANG=C sort -z -u | \
461 - rsync -tL0 --chmod=ugo-st,a+r,go-w,Da+x,Fa-x --files-from=- "${WORKDIR}/" "${D%/}/${prepstrip_sources_dir#/}/" )
462 -
463 - # Preserve directory structure.
464 - # Needed after running save_elf_sources.
465 - # https://bugzilla.redhat.com/show_bug.cgi?id=444310
466 - while read -r -d $'\0' emptydir
467 - do
468 - >> "${emptydir}"/.keepdir
469 - done < <(find "${D%/}/${prepstrip_sources_dir#/}/" -type d -empty -print0)
470 +if ___eapi_has_dostrip; then
471 + die "${0##*/}: ${0##*/} has been banned for EAPI '$EAPI'; use 'dostrip' instead"
472 fi
473
474 -cd "${T}"
475 -rm -rf "${tmpdir}"
476 +exec -a "${0}" "${PORTAGE_BIN_PATH}"/estrip "${@}"
477 diff --git a/bin/ebuild.sh b/bin/ebuild.sh
478 index 061b1aff4..11441bfb2 100755
479 --- a/bin/ebuild.sh
480 +++ b/bin/ebuild.sh
481 @@ -59,7 +59,7 @@ else
482 # These dummy functions are for things that are likely to be called
483 # in global scope, even though they are completely useless during
484 # the "depend" phase.
485 - funcs="diropts docompress exeopts get_KV insopts
486 + funcs="diropts docompress dostrip exeopts get_KV insopts
487 KV_major KV_micro KV_minor KV_to_int
488 libopts register_die_hook register_success_hook
489 __strip_duplicate_slashes
490 diff --git a/bin/estrip b/bin/estrip
491 new file mode 100755
492 index 000000000..cc3450b78
493 --- /dev/null
494 +++ b/bin/estrip
495 @@ -0,0 +1,458 @@
496 +#!/bin/bash
497 +# Copyright 1999-2018 Gentoo Foundation
498 +# Distributed under the terms of the GNU General Public License v2
499 +
500 +source "${PORTAGE_BIN_PATH}"/helper-functions.sh || exit 1
501 +
502 +# avoid multiple calls to `has`. this creates things like:
503 +# FEATURES_foo=false
504 +# if "foo" is not in $FEATURES
505 +tf() { "$@" && echo true || echo false ; }
506 +exp_tf() {
507 + local flag var=$1
508 + shift
509 + for flag in "$@" ; do
510 + eval ${var}_${flag}=$(tf has ${flag} ${!var})
511 + done
512 +}
513 +exp_tf FEATURES compressdebug installsources nostrip splitdebug xattr
514 +exp_tf RESTRICT binchecks installsources splitdebug strip
515 +
516 +if ! ___eapi_has_prefix_variables; then
517 + EPREFIX= ED=${D}
518 +fi
519 +
520 +banner=false
521 +SKIP_STRIP=false
522 +if ${RESTRICT_strip} || ${FEATURES_nostrip} ; then
523 + SKIP_STRIP=true
524 + banner=true
525 + ${FEATURES_installsources} || exit 0
526 +fi
527 +
528 +if [[ ${0##*/} != prepstrip ]]; then
529 +while [[ $# -gt 0 ]] ; do
530 + case $1 in
531 + --ignore)
532 + shift
533 +
534 + skip_dirs=()
535 + for skip; do
536 + if [[ -d ${ED%/}/${skip#/} ]]; then
537 + skip_dirs+=( "${ED%/}/${skip#/}" )
538 + else
539 + rm -f "${ED%/}/${skip#/}.estrip" || die
540 + fi
541 + done
542 +
543 + if [[ ${skip_dirs[@]} ]]; then
544 + find "${skip_dirs[@]}" -name '*.estrip' -delete || die
545 + fi
546 +
547 + exit 0
548 + ;;
549 + --queue)
550 + shift
551 +
552 + find_paths=()
553 + for path; do
554 + if [[ -e ${ED%/}/${path#/} ]]; then
555 + find_paths+=( "${ED%/}/${path#/}" )
556 + fi
557 + done
558 +
559 + if [[ ${find_paths[@]} ]]; then
560 + while IFS= read -r path; do
561 + >> "${path}.estrip" || die
562 + done < <(
563 + scanelf -yqRBF '#k%F' -k '.symtab' "${find_paths[@]}"
564 + find "${find_paths[@]}" -type f ! -type l -name '*.a'
565 + )
566 + fi
567 +
568 + exit 0
569 + ;;
570 + --dequeue)
571 + [[ -n ${2} ]] && die "${0##*/}: --dequeue takes no additional arguments"
572 + break
573 + ;;
574 + *)
575 + die "${0##*/}: unknown arguments '$*'"
576 + exit 1
577 + ;;
578 + esac
579 + shift
580 +done
581 +fi
582 +
583 +PRESERVE_XATTR=false
584 +if [[ ${KERNEL} == linux ]] && ${FEATURES_xattr} ; then
585 + PRESERVE_XATTR=true
586 + if type -P getfattr >/dev/null && type -P setfattr >/dev/null ; then
587 + dump_xattrs() {
588 + getfattr -d -m - --absolute-names "$1"
589 + }
590 + restore_xattrs() {
591 + setfattr --restore=-
592 + }
593 + else
594 + dump_xattrs() {
595 + PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \
596 + "${PORTAGE_PYTHON:-/usr/bin/python}" \
597 + "${PORTAGE_BIN_PATH}/xattr-helper.py" --dump < <(echo -n "$1")
598 + }
599 + restore_xattrs() {
600 + PYTHONPATH=${PORTAGE_PYTHONPATH:-${PORTAGE_PYM_PATH}} \
601 + "${PORTAGE_PYTHON:-/usr/bin/python}" \
602 + "${PORTAGE_BIN_PATH}/xattr-helper.py" --restore
603 + }
604 + fi
605 +fi
606 +
607 +# look up the tools we might be using
608 +for t in STRIP:strip OBJCOPY:objcopy READELF:readelf ; do
609 + v=${t%:*} # STRIP
610 + t=${t#*:} # strip
611 + eval ${v}=\"${!v:-${CHOST}-${t}}\"
612 + type -P -- ${!v} >/dev/null || eval ${v}=${t}
613 +done
614 +
615 +# Figure out what tool set we're using to strip stuff
616 +unset SAFE_STRIP_FLAGS DEF_STRIP_FLAGS SPLIT_STRIP_FLAGS
617 +case $(${STRIP} --version 2>/dev/null) in
618 +*elfutils*) # dev-libs/elfutils
619 + # elfutils default behavior is always safe, so don't need to specify
620 + # any flags at all
621 + SAFE_STRIP_FLAGS=""
622 + DEF_STRIP_FLAGS="--remove-comment"
623 + SPLIT_STRIP_FLAGS="-f"
624 + ;;
625 +*GNU*) # sys-devel/binutils
626 + # We'll leave out -R .note for now until we can check out the relevance
627 + # of the section when it has the ALLOC flag set on it ...
628 + SAFE_STRIP_FLAGS="--strip-unneeded"
629 + DEF_STRIP_FLAGS="-R .comment -R .GCC.command.line -R .note.gnu.gold-version"
630 + SPLIT_STRIP_FLAGS=
631 + ;;
632 +esac
633 +: ${PORTAGE_STRIP_FLAGS=${SAFE_STRIP_FLAGS} ${DEF_STRIP_FLAGS}}
634 +
635 +prepstrip_sources_dir=${EPREFIX}/usr/src/debug/${CATEGORY}/${PF}
636 +
637 +debugedit=$(type -P debugedit)
638 +if [[ -z ${debugedit} ]]; then
639 + debugedit_paths=(
640 + "${EPREFIX}/usr/libexec/rpm/debugedit"
641 + )
642 + for x in "${debugedit_paths[@]}"; do
643 + if [[ -x ${x} ]]; then
644 + debugedit=${x}
645 + break
646 + fi
647 + done
648 +fi
649 +[[ ${debugedit} ]] && debugedit_found=true || debugedit_found=false
650 +debugedit_warned=false
651 +
652 +__multijob_init
653 +
654 +# Setup $T filesystem layout that we care about.
655 +tmpdir="${T}/prepstrip"
656 +rm -rf "${tmpdir}"
657 +mkdir -p "${tmpdir}"/{inodes,splitdebug,sources}
658 +
659 +# Usage: save_elf_sources <elf>
660 +save_elf_sources() {
661 + ${FEATURES_installsources} || return 0
662 + ${RESTRICT_installsources} && return 0
663 + if ! ${debugedit_found} ; then
664 + if ! ${debugedit_warned} ; then
665 + debugedit_warned=true
666 + ewarn "FEATURES=installsources is enabled but the debugedit binary could not be"
667 + ewarn "found. This feature will not work unless debugedit or rpm is installed!"
668 + fi
669 + return 0
670 + fi
671 +
672 + local x=$1
673 +
674 + # since we're editing the ELF here, we should recompute the build-id
675 + # (the -i flag below). save that output so we don't need to recompute
676 + # it later on in the save_elf_debug step.
677 + buildid=$("${debugedit}" -i \
678 + -b "${WORKDIR}" \
679 + -d "${prepstrip_sources_dir}" \
680 + -l "${tmpdir}/sources/${x##*/}.${BASHPID:-$(__bashpid)}" \
681 + "${x}")
682 +}
683 +
684 +# Usage: save_elf_debug <elf> [splitdebug file]
685 +save_elf_debug() {
686 + ${FEATURES_splitdebug} || return 0
687 + ${RESTRICT_splitdebug} && return 0
688 +
689 + # NOTE: Debug files must be installed in
690 + # ${EPREFIX}/usr/lib/debug/${EPREFIX} (note that ${EPREFIX} occurs
691 + # twice in this path) in order for gdb's debug-file-directory
692 + # lookup to work correctly.
693 + local x=$1
694 + local inode_debug=$2
695 + local splitdebug=$3
696 + local d_noslash=${D%/}
697 + local y=${ED%/}/usr/lib/debug/${x:${#d_noslash}}.debug
698 +
699 + # dont save debug info twice
700 + [[ ${x} == *".debug" ]] && return 0
701 +
702 + mkdir -p "${y%/*}"
703 +
704 + if [ -f "${inode_debug}" ] ; then
705 + ln "${inode_debug}" "${y}" || die "ln failed unexpectedly"
706 + else
707 + if [[ -n ${splitdebug} ]] ; then
708 + mv "${splitdebug}" "${y}"
709 + else
710 + local objcopy_flags="--only-keep-debug"
711 + ${FEATURES_compressdebug} && objcopy_flags+=" --compress-debug-sections"
712 + ${OBJCOPY} ${objcopy_flags} "${x}" "${y}"
713 + ${OBJCOPY} --add-gnu-debuglink="${y}" "${x}"
714 + fi
715 + # Only do the following if the debug file was
716 + # successfully created (see bug #446774).
717 + if [ $? -eq 0 ] ; then
718 + local args="a-x,o-w"
719 + [[ -g ${x} || -u ${x} ]] && args+=",go-r"
720 + chmod ${args} "${y}"
721 + ln "${y}" "${inode_debug}" || die "ln failed unexpectedly"
722 + fi
723 + fi
724 +
725 + # if we don't already have build-id from debugedit, look it up
726 + if [[ -z ${buildid} ]] ; then
727 + # convert the readelf output to something useful
728 + buildid=$(${READELF} -n "${x}" 2>/dev/null | awk '/Build ID:/{ print $NF; exit }')
729 + fi
730 + if [[ -n ${buildid} ]] ; then
731 + local buildid_dir="${ED%/}/usr/lib/debug/.build-id/${buildid:0:2}"
732 + local buildid_file="${buildid_dir}/${buildid:2}"
733 + mkdir -p "${buildid_dir}"
734 + [ -L "${buildid_file}".debug ] || ln -s "../../${x:${#D}}.debug" "${buildid_file}.debug"
735 + [ -L "${buildid_file}" ] || ln -s "/${x:${#D}}" "${buildid_file}"
736 + fi
737 +}
738 +
739 +# Usage: process_elf <elf>
740 +process_elf() {
741 + local x=$1 inode_link=$2 strip_flags=${*:3}
742 + local already_stripped lockfile xt_data
743 +
744 + __vecho " ${x:${#ED}}"
745 +
746 + # If two processes try to debugedit or strip the same hardlink at the
747 + # same time, it may corrupt files or cause loss of splitdebug info.
748 + # So, use a lockfile to prevent interference (easily observed with
749 + # dev-vcs/git which creates ~111 hardlinks to one file in
750 + # /usr/libexec/git-core).
751 + lockfile=${inode_link}_lockfile
752 + if ! ln "${inode_link}" "${lockfile}" 2>/dev/null ; then
753 + while [[ -f ${lockfile} ]] ; do
754 + sleep 1
755 + done
756 + unset lockfile
757 + fi
758 +
759 + [ -f "${inode_link}_stripped" ] && already_stripped=true || already_stripped=false
760 +
761 + if ! ${already_stripped} ; then
762 + if ${PRESERVE_XATTR} ; then
763 + xt_data=$(dump_xattrs "${x}")
764 + fi
765 + save_elf_sources "${x}"
766 + fi
767 +
768 + if ${strip_this} ; then
769 +
770 + # see if we can split & strip at the same time
771 + if [[ -n ${SPLIT_STRIP_FLAGS} ]] ; then
772 + local shortname="${x##*/}.debug"
773 + local splitdebug="${tmpdir}/splitdebug/${shortname}.${BASHPID:-$(__bashpid)}"
774 + ${already_stripped} || \
775 + ${STRIP} ${strip_flags} \
776 + -f "${splitdebug}" \
777 + -F "${shortname}" \
778 + "${x}"
779 + save_elf_debug "${x}" "${inode_link}_debug" "${splitdebug}"
780 + else
781 + save_elf_debug "${x}" "${inode_link}_debug"
782 + ${already_stripped} || \
783 + ${STRIP} ${strip_flags} "${x}"
784 + fi
785 + fi
786 +
787 + if ${already_stripped} ; then
788 + rm -f "${x}" || die "rm failed unexpectedly"
789 + ln "${inode_link}_stripped" "${x}" || die "ln failed unexpectedly"
790 + else
791 + ln "${x}" "${inode_link}_stripped" || die "ln failed unexpectedly"
792 + if [[ ${xt_data} ]] ; then
793 + restore_xattrs <<< "${xt_data}"
794 + fi
795 + fi
796 +
797 + [[ -n ${lockfile} ]] && rm -f "${lockfile}"
798 +}
799 +
800 +# The existance of the section .symtab tells us that a binary is stripped.
801 +# We want to log already stripped binaries, as this may be a QA violation.
802 +# They prevent us from getting the splitdebug data.
803 +if ! ${RESTRICT_binchecks} && ! ${RESTRICT_strip} ; then
804 + # We need to do the non-stripped scan serially first before we turn around
805 + # and start stripping the files ourselves. The log parsing can be done in
806 + # parallel though.
807 + log=${tmpdir}/scanelf-already-stripped.log
808 + scanelf -yqRBF '#k%F' -k '!.symtab' "$@" | sed -e "s#^${ED%/}/##" > "${log}"
809 + (
810 + __multijob_child_init
811 + qa_var="QA_PRESTRIPPED_${ARCH/-/_}"
812 + [[ -n ${!qa_var} ]] && QA_PRESTRIPPED="${!qa_var}"
813 + if [[ -n ${QA_PRESTRIPPED} && -s ${log} && \
814 + ${QA_STRICT_PRESTRIPPED-unset} = unset ]] ; then
815 + shopts=$-
816 + set -o noglob
817 + for x in ${QA_PRESTRIPPED} ; do
818 + sed -e "s#^${x#/}\$##" -i "${log}"
819 + done
820 + set +o noglob
821 + set -${shopts}
822 + fi
823 + sed -e "/^\$/d" -e "s#^#/#" -i "${log}"
824 + if [[ -s ${log} ]] ; then
825 + __vecho -e "\n"
826 + eqawarn "QA Notice: Pre-stripped files found:"
827 + eqawarn "$(<"${log}")"
828 + else
829 + rm -f "${log}"
830 + fi
831 + ) &
832 + __multijob_post_fork
833 +fi
834 +
835 +# Since strip creates a new inode, we need to know the initial set of
836 +# inodes in advance, so that we can avoid interference due to trying
837 +# to strip the same (hardlinked) file multiple times in parallel.
838 +# See bug #421099.
839 +if [[ ${USERLAND} == BSD ]] ; then
840 + get_inode_number() { stat -f '%i' "$1"; }
841 +else
842 + get_inode_number() { stat -c '%i' "$1"; }
843 +fi
844 +cd "${tmpdir}/inodes" || die "cd failed unexpectedly"
845 +while read -r x ; do
846 + inode_link=$(get_inode_number "${x}") || die "stat failed unexpectedly"
847 + echo "${x}" >> "${inode_link}" || die "echo failed unexpectedly"
848 +done < <(
849 + # Use sort -u to eliminate duplicates for bug #445336.
850 + (
851 + scanelf -yqRBF '#k%F' -k '.symtab' "$@"
852 + find "$@" -type f ! -type l -name '*.a'
853 + ) | LC_ALL=C sort -u
854 +)
855 +
856 +# Now we look for unstripped binaries.
857 +for inode_link in $(shopt -s nullglob; echo *) ; do
858 +while read -r x
859 +do
860 +
861 + if ! ${banner} ; then
862 + __vecho "strip: ${STRIP} ${PORTAGE_STRIP_FLAGS}"
863 + banner=true
864 + fi
865 +
866 + (
867 + __multijob_child_init
868 + f=$(file "${x}") || exit 0
869 + [[ -z ${f} ]] && exit 0
870 +
871 + if ! ${SKIP_STRIP} ; then
872 + # The noglob funk is to support STRIP_MASK="/*/booga" and to keep
873 + # the for loop from expanding the globs.
874 + # The eval echo is to support STRIP_MASK="/*/{booga,bar}" sex.
875 + set -o noglob
876 + strip_this=true
877 + for m in $(eval echo ${STRIP_MASK}) ; do
878 + [[ /${x#${ED%/}} == ${m} ]] && strip_this=false && break
879 + done
880 + set +o noglob
881 + else
882 + strip_this=false
883 + fi
884 +
885 + # In Prefix we are usually an unprivileged user, so we can't strip
886 + # unwritable objects. Make them temporarily writable for the
887 + # stripping.
888 + was_not_writable=false
889 + if [[ ! -w ${x} ]] ; then
890 + was_not_writable=true
891 + chmod u+w "${x}"
892 + fi
893 +
894 + # only split debug info for final linked objects
895 + # or kernel modules as debuginfo for intermediatary
896 + # files (think crt*.o from gcc/glibc) is useless and
897 + # actually causes problems. install sources for all
898 + # elf types though cause that stuff is good.
899 +
900 + buildid=
901 + if [[ ${f} == *"current ar archive"* ]] ; then
902 + __vecho " ${x:${#ED}}"
903 + if ${strip_this} ; then
904 + # If we have split debug enabled, then do not strip this.
905 + # There is no concept of splitdebug for objects not yet
906 + # linked in (only for finally linked ELFs), so we have to
907 + # retain the debug info in the archive itself.
908 + if ! ${FEATURES_splitdebug} || ${RESTRICT_splitdebug} ; then
909 + ${STRIP} -g "${x}"
910 + fi
911 + fi
912 + elif [[ ${f} == *"SB executable"* || ${f} == *"SB shared object"* ]] ; then
913 + process_elf "${x}" "${inode_link}" ${PORTAGE_STRIP_FLAGS}
914 + elif [[ ${f} == *"SB relocatable"* ]] ; then
915 + process_elf "${x}" "${inode_link}" ${SAFE_STRIP_FLAGS}
916 + fi
917 +
918 + if ${was_not_writable} ; then
919 + chmod u-w "${x}"
920 + fi
921 + ) &
922 + __multijob_post_fork
923 +
924 +done < "${inode_link}"
925 +done
926 +
927 +# With a bit more work, we could run the rsync processes below in
928 +# parallel, but not sure that'd be an overall improvement.
929 +__multijob_finish
930 +
931 +cd "${tmpdir}"/sources/ && cat * > "${tmpdir}/debug.sources" 2>/dev/null
932 +if [[ -s ${tmpdir}/debug.sources ]] && \
933 + ${FEATURES_installsources} && \
934 + ! ${RESTRICT_installsources} && \
935 + ${debugedit_found}
936 +then
937 + __vecho "installsources: rsyncing source files"
938 + [[ -d ${D%/}/${prepstrip_sources_dir#/} ]] || mkdir -p "${D%/}/${prepstrip_sources_dir#/}"
939 + grep -zv '/<[^/>]*>$' "${tmpdir}"/debug.sources | \
940 + (cd "${WORKDIR}"; LANG=C sort -z -u | \
941 + rsync -tL0 --chmod=ugo-st,a+r,go-w,Da+x,Fa-x --files-from=- "${WORKDIR}/" "${D%/}/${prepstrip_sources_dir#/}/" )
942 +
943 + # Preserve directory structure.
944 + # Needed after running save_elf_sources.
945 + # https://bugzilla.redhat.com/show_bug.cgi?id=444310
946 + while read -r -d $'\0' emptydir
947 + do
948 + >> "${emptydir}"/.keepdir
949 + done < <(find "${D%/}/${prepstrip_sources_dir#/}/" -type d -empty -print0)
950 +fi
951 +
952 +cd "${T}"
953 +rm -rf "${tmpdir}"
954 diff --git a/bin/misc-functions.sh b/bin/misc-functions.sh
955 index 7643af7b5..df8361036 100755
956 --- a/bin/misc-functions.sh
957 +++ b/bin/misc-functions.sh
958 @@ -224,6 +224,12 @@ install_qa_check() {
959 ecompressdir --dequeue
960 ecompress --dequeue
961
962 + if ___eapi_has_dostrip; then
963 + "${PORTAGE_BIN_PATH}"/estrip --queue "${PORTAGE_DOSTRIP[@]}"
964 + "${PORTAGE_BIN_PATH}"/estrip --ignore "${PORTAGE_DOSTRIP_SKIP[@]}"
965 + "${PORTAGE_BIN_PATH}"/estrip --dequeue
966 + fi
967 +
968 # Create NEEDED.ELF.2 regardless of RESTRICT=binchecks, since this info is
969 # too useful not to have (it's required for things like preserve-libs), and
970 # it's tempting for ebuild authors to set RESTRICT=binchecks for packages
971 diff --git a/bin/phase-helpers.sh b/bin/phase-helpers.sh
972 index 5eeecfef7..556d089b5 100644
973 --- a/bin/phase-helpers.sh
974 +++ b/bin/phase-helpers.sh
975 @@ -20,6 +20,9 @@ export MOPREFIX=${PN}
976 export PORTAGE_DOCOMPRESS_SIZE_LIMIT="128"
977 declare -a PORTAGE_DOCOMPRESS=( /usr/share/{doc,info,man} )
978 declare -a PORTAGE_DOCOMPRESS_SKIP=( /usr/share/doc/${PF}/html )
979 +declare -a PORTAGE_DOSTRIP=( / )
980 +has strip ${RESTRICT} && PORTAGE_DOSTRIP=()
981 +declare -a PORTAGE_DOSTRIP_SKIP=()
982
983 into() {
984 if [ "$1" == "/" ]; then
985 @@ -160,6 +163,32 @@ docompress() {
986 fi
987 }
988
989 +dostrip() {
990 + ___eapi_has_dostrip || die "'${FUNCNAME}' not supported in this EAPI"
991 +
992 + local f g
993 + if [[ $1 = "-x" ]]; then
994 + shift
995 + for f; do
996 + f=$(__strip_duplicate_slashes "${f}"); f=${f%/}
997 + [[ ${f:0:1} = / ]] || f="/${f}"
998 + for g in "${PORTAGE_DOSTRIP_SKIP[@]}"; do
999 + [[ ${f} = "${g}" ]] && continue 2
1000 + done
1001 + PORTAGE_DOSTRIP_SKIP+=( "${f}" )
1002 + done
1003 + else
1004 + for f; do
1005 + f=$(__strip_duplicate_slashes "${f}"); f=${f%/}
1006 + [[ ${f:0:1} = / ]] || f="/${f}"
1007 + for g in "${PORTAGE_DOSTRIP[@]}"; do
1008 + [[ ${f} = "${g}" ]] && continue 2
1009 + done
1010 + PORTAGE_DOSTRIP+=( "${f}" )
1011 + done
1012 + fi
1013 +}
1014 +
1015 useq() {
1016 has $EBUILD_PHASE prerm postrm || eqawarn \
1017 "QA Notice: The 'useq' function is deprecated (replaced by 'use')"
1018 diff --git a/bin/save-ebuild-env.sh b/bin/save-ebuild-env.sh
1019 index e5ae8af88..947ac79d5 100644
1020 --- a/bin/save-ebuild-env.sh
1021 +++ b/bin/save-ebuild-env.sh
1022 @@ -15,7 +15,7 @@ __save_ebuild_env() {
1023 if has --exclude-init-phases $* ; then
1024 unset S _E_DESTTREE _E_INSDESTTREE _E_DOCDESTTREE_ _E_EXEDESTTREE_ \
1025 PORTAGE_DOCOMPRESS_SIZE_LIMIT PORTAGE_DOCOMPRESS \
1026 - PORTAGE_DOCOMPRESS_SKIP
1027 + PORTAGE_DOCOMPRESS_SKIP PORTAGE_DOSTRIP PORTAGE_DOSTRIP_SKIP
1028 if [[ -n $PYTHONPATH &&
1029 ${PYTHONPATH%%:*} -ef $PORTAGE_PYM_PATH ]] ; then
1030 if [[ $PYTHONPATH == *:* ]] ; then
1031 @@ -60,7 +60,7 @@ __save_ebuild_env() {
1032 unpack __strip_duplicate_slashes econf einstall \
1033 __dyn_setup __dyn_unpack __dyn_clean \
1034 into insinto exeinto docinto \
1035 - insopts diropts exeopts libopts docompress \
1036 + insopts diropts exeopts libopts docompress dostrip \
1037 __abort_handler __abort_prepare __abort_configure __abort_compile \
1038 __abort_test __abort_install __dyn_prepare __dyn_configure \
1039 __dyn_compile __dyn_test __dyn_install \
1040 --
1041 2.13.6