Skip to content

Commit

Permalink
ltprune.eclass: Split prune_libtool_files out of eutils
Browse files Browse the repository at this point in the history
Move the prune_libtool_files into a dedicated ltprune.eclass.
The function is quite complex and depends on toolchain-funcs. It has
a separate maintainer, is not useful to non-autotools ebuilds, and even
there it is frequently replaced by the simpler 'find ... -delete' call.

The new eclass is implicitly inherited by eutils in EAPI 6 and older
in order to preserve compatibility with existing ebuilds. However, all
ebuilds should switch to inheriting it directly.

The split has been suggested by Ulrich Müller.
  • Loading branch information
mgorny committed Mar 18, 2017
1 parent 8400f95 commit e625e0a
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 149 deletions.
150 changes: 1 addition & 149 deletions eclass/eutils.eclass
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@
if [[ -z ${_EUTILS_ECLASS} ]]; then
_EUTILS_ECLASS=1

inherit toolchain-funcs

# implicitly inherited (now split) eclasses
case ${EAPI:-0} in
0|1|2|3|4|5|6)
inherit epatch estack multilib
inherit epatch estack ltprune multilib toolchain-funcs
;;
esac

Expand Down Expand Up @@ -869,152 +867,6 @@ use_if_iuse() {
use $1
}

# @FUNCTION: prune_libtool_files
# @USAGE: [--all|--modules]
# @DESCRIPTION:
# Locate unnecessary libtool files (.la) and libtool static archives
# (.a) and remove them from installation image.
#
# By default, .la files are removed whenever the static linkage can
# either be performed using pkg-config or doesn't introduce additional
# flags.
#
# If '--modules' argument is passed, .la files for modules (plugins) are
# removed as well. This is usually useful when the package installs
# plugins and the plugin loader does not use .la files.
#
# If '--all' argument is passed, all .la files are removed without
# performing any heuristic on them. You shouldn't ever use that,
# and instead report a bug in the algorithm instead.
#
# The .a files are only removed whenever corresponding .la files state
# that they should not be linked to, i.e. whenever these files
# correspond to plugins.
#
# Note: if your package installs both static libraries and .pc files
# which use variable substitution for -l flags, you need to add
# pkg-config to your DEPEND.
prune_libtool_files() {
debug-print-function ${FUNCNAME} "$@"

local removing_all removing_modules opt
for opt; do
case "${opt}" in
--all)
removing_all=1
removing_modules=1
;;
--modules)
removing_modules=1
;;
*)
die "Invalid argument to ${FUNCNAME}(): ${opt}"
esac
done

local f
local queue=()
while IFS= read -r -d '' f; do # for all .la files
local archivefile=${f/%.la/.a}

# The following check is done by libtool itself.
# It helps us avoid removing random files which match '*.la',
# see bug #468380.
if ! sed -n -e '/^# Generated by .*libtool/q0;4q1' "${f}"; then
continue
fi

[[ ${f} != ${archivefile} ]] || die 'regex sanity check failed'
local reason= pkgconfig_scanned=
local snotlink=$(sed -n -e 's:^shouldnotlink=::p' "${f}")

if [[ ${snotlink} == yes ]]; then

# Remove static libs we're not supposed to link against.
if [[ -f ${archivefile} ]]; then
einfo "Removing unnecessary ${archivefile#${D%/}} (static plugin)"
queue+=( "${archivefile}" )
fi

# The .la file may be used by a module loader, so avoid removing it
# unless explicitly requested.
if [[ ${removing_modules} ]]; then
reason='module'
fi

else

# Remove .la files when:
# - user explicitly wants us to remove all .la files,
# - respective static archive doesn't exist,
# - they are covered by a .pc file already,
# - they don't provide any new information (no libs & no flags).

if [[ ${removing_all} ]]; then
reason='requested'
elif [[ ! -f ${archivefile} ]]; then
reason='no static archive'
elif [[ ! $(sed -nre \
"s/^(dependency_libs|inherited_linker_flags)='(.*)'$/\2/p" \
"${f}") ]]; then
reason='no libs & flags'
else
if [[ ! ${pkgconfig_scanned} ]]; then
# Create a list of all .pc-covered libs.
local pc_libs=()
if [[ ! ${removing_all} ]]; then
local pc
local tf=${T}/prune-lt-files.pc
local pkgconf=$(tc-getPKG_CONFIG)

while IFS= read -r -d '' pc; do # for all .pc files
local arg libs

# Use pkg-config if available (and works),
# fallback to sed.
if ${pkgconf} --exists "${pc}" &>/dev/null; then
sed -e '/^Requires:/d' "${pc}" > "${tf}"
libs=$(${pkgconf} --libs "${tf}")
else
libs=$(sed -ne 's/^Libs://p' "${pc}")
fi

for arg in ${libs}; do
if [[ ${arg} == -l* ]]; then
if [[ ${arg} == '*$*' ]]; then
eerror "${FUNCNAME}: variable substitution likely failed in ${pc}"
eerror "(arg: ${arg})"
eerror "Most likely, you need to add virtual/pkgconfig to DEPEND."
die "${FUNCNAME}: unsubstituted variable found in .pc"
fi

pc_libs+=( lib${arg#-l}.la )
fi
done
done < <(find "${D}" -type f -name '*.pc' -print0)

rm -f "${tf}"
fi

pkgconfig_scanned=1
fi # pkgconfig_scanned

has "${f##*/}" "${pc_libs[@]}" && reason='covered by .pc'
fi # removal due to .pc

fi # shouldnotlink==no

if [[ ${reason} ]]; then
einfo "Removing unnecessary ${f#${D%/}} (${reason})"
queue+=( "${f}" )
fi
done < <(find "${D}" -xtype f -name '*.la' -print0)

if [[ ${queue[@]} ]]; then
rm -f "${queue[@]}"
fi
}

# @FUNCTION: optfeature
# @USAGE: <short description> <package atom to match> [other atoms]
# @DESCRIPTION:
Expand Down
167 changes: 167 additions & 0 deletions eclass/ltprune.eclass
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# Copyright 1999-2017 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2

# @ECLASS: ltprune.eclass
# @MAINTAINER:
# Michał Górny <[email protected]>
# @BLURB: Smart .la file pruning
# @DESCRIPTION:
# A function to locate and remove unnecessary .la files.
#
# Discouraged. Whenever possible, please use much simpler:
# @CODE
# find "${D}" -name '*.la' -delete || die
# @CODE

if [[ -z ${_LTPRUNE_ECLASS} ]]; then

inherit toolchain-funcs

# @FUNCTION: prune_libtool_files
# @USAGE: [--all|--modules]
# @DESCRIPTION:
# Locate unnecessary libtool files (.la) and libtool static archives
# (.a) and remove them from installation image.
#
# By default, .la files are removed whenever the static linkage can
# either be performed using pkg-config or doesn't introduce additional
# flags.
#
# If '--modules' argument is passed, .la files for modules (plugins) are
# removed as well. This is usually useful when the package installs
# plugins and the plugin loader does not use .la files.
#
# If '--all' argument is passed, all .la files are removed without
# performing any heuristic on them. You shouldn't ever use that,
# and instead report a bug in the algorithm instead.
#
# The .a files are only removed whenever corresponding .la files state
# that they should not be linked to, i.e. whenever these files
# correspond to plugins.
#
# Note: if your package installs both static libraries and .pc files
# which use variable substitution for -l flags, you need to add
# pkg-config to your DEPEND.
prune_libtool_files() {
debug-print-function ${FUNCNAME} "$@"

local removing_all removing_modules opt
for opt; do
case "${opt}" in
--all)
removing_all=1
removing_modules=1
;;
--modules)
removing_modules=1
;;
*)
die "Invalid argument to ${FUNCNAME}(): ${opt}"
esac
done

local f
local queue=()
while IFS= read -r -d '' f; do # for all .la files
local archivefile=${f/%.la/.a}

# The following check is done by libtool itself.
# It helps us avoid removing random files which match '*.la',
# see bug #468380.
if ! sed -n -e '/^# Generated by .*libtool/q0;4q1' "${f}"; then
continue
fi

[[ ${f} != ${archivefile} ]] || die 'regex sanity check failed'
local reason= pkgconfig_scanned=
local snotlink=$(sed -n -e 's:^shouldnotlink=::p' "${f}")

if [[ ${snotlink} == yes ]]; then

# Remove static libs we're not supposed to link against.
if [[ -f ${archivefile} ]]; then
einfo "Removing unnecessary ${archivefile#${D%/}} (static plugin)"
queue+=( "${archivefile}" )
fi

# The .la file may be used by a module loader, so avoid removing it
# unless explicitly requested.
if [[ ${removing_modules} ]]; then
reason='module'
fi

else

# Remove .la files when:
# - user explicitly wants us to remove all .la files,
# - respective static archive doesn't exist,
# - they are covered by a .pc file already,
# - they don't provide any new information (no libs & no flags).

if [[ ${removing_all} ]]; then
reason='requested'
elif [[ ! -f ${archivefile} ]]; then
reason='no static archive'
elif [[ ! $(sed -nre \
"s/^(dependency_libs|inherited_linker_flags)='(.*)'$/\2/p" \
"${f}") ]]; then
reason='no libs & flags'
else
if [[ ! ${pkgconfig_scanned} ]]; then
# Create a list of all .pc-covered libs.
local pc_libs=()
if [[ ! ${removing_all} ]]; then
local pc
local tf=${T}/prune-lt-files.pc
local pkgconf=$(tc-getPKG_CONFIG)

while IFS= read -r -d '' pc; do # for all .pc files
local arg libs

# Use pkg-config if available (and works),
# fallback to sed.
if ${pkgconf} --exists "${pc}" &>/dev/null; then
sed -e '/^Requires:/d' "${pc}" > "${tf}"
libs=$(${pkgconf} --libs "${tf}")
else
libs=$(sed -ne 's/^Libs://p' "${pc}")
fi

for arg in ${libs}; do
if [[ ${arg} == -l* ]]; then
if [[ ${arg} == '*$*' ]]; then
eerror "${FUNCNAME}: variable substitution likely failed in ${pc}"
eerror "(arg: ${arg})"
eerror "Most likely, you need to add virtual/pkgconfig to DEPEND."
die "${FUNCNAME}: unsubstituted variable found in .pc"
fi

pc_libs+=( lib${arg#-l}.la )
fi
done
done < <(find "${D}" -type f -name '*.pc' -print0)

rm -f "${tf}"
fi

pkgconfig_scanned=1
fi # pkgconfig_scanned

has "${f##*/}" "${pc_libs[@]}" && reason='covered by .pc'
fi # removal due to .pc

fi # shouldnotlink==no

if [[ ${reason} ]]; then
einfo "Removing unnecessary ${f#${D%/}} (${reason})"
queue+=( "${f}" )
fi
done < <(find "${D}" -xtype f -name '*.la' -print0)

if [[ ${queue[@]} ]]; then
rm -f "${queue[@]}"
fi
}

_LTPRUNE_ECLASS=1
fi #_LTPRUNE_ECLASS

0 comments on commit e625e0a

Please sign in to comment.