--- /dev/null
+#!/bin/bash
+
+# CHANGES
+#
+# 20051211: Add qfile use from portage-utils, prefer over equery. Create new
+# function track_headers() to handle package manager queries for both
+# relative and absolute headers. Split relative and absolute queries into two
+# separate places, since relative aren't quite as reliable. Prefer headers
+# found in the tarball over those in /usr/include. Also, note which headers
+# weren't considered in the calculation and the reasons why not.
+
+location=${1}
+
+usage() {
+ echo "${0##*/} [ -d ] source_location"
+ echo " Returns owners of all include files used. ${0##*/} defaults to"
+ echo " files in /usr/include, so if a file with the same name within the"
+ echo " source is the actual one used, false dependencies may be printed."
+ echo
+ echo " -d"
+ echo " Show debug output: Print files not found"
+ exit 1
+}
+
+decho() {
+ if [[ -n "${DEBUG}" ]]; then
+ echo "${1}"
+ fi
+}
+
+if [[ $# -le 0 ]] || [[ $# -ge 3 ]]; then
+ usage
+fi
+
+# Handle command-line options
+while getopts d options; do
+ case ${options} in
+ d) DEBUG=1
+ ;;
+ *) usage
+ ;;
+ esac
+done
+# Reset post-option stuff to positional parameters
+shift $((OPTIND - 1))
+
+get_absolute_includes() {
+ grep '^#[[:space:]]*include' -r ${1} | grep '.*.[ch]' | grep -e '<' -e '>' \
+ | cut -d':' -f2 | cut -d'<' -f2 | cut -d'>' -f1 | grep '.*.[ch]' \
+ | sort | uniq
+}
+
+get_relative_includes() {
+ grep '^#[[:space:]]*include' -r ${1} | grep '.*.[ch]' | grep -e '"' -e '"' \
+ | cut -d':' -f2 | cut -d'"' -f2 | cut -d'"' -f1 | grep '.*.[ch]' \
+ | sort | uniq
+}
+
+track_headers() {
+ if [[ -x $(which qfile 2> /dev/null) ]]; then
+ qfile ${@} | cut -d'(' -f1 | sort | uniq
+ elif [[ -x $(which equery 2> /dev/null) ]]; then
+ equery -q belongs ${@} | cut -d'(' -f1
+ elif [[ -x $(which rpm 2> /dev/null) ]]; then
+ rpm -qf ${@}
+ else
+ echo "Couldn't find package query tool! Printing headerpaths instead."
+ echo
+ for header in ${@}; do
+ echo ${header}
+ done
+ fi
+}
+
+echo "Analyzing source ... "
+absolute_headers="$(get_absolute_includes ${1})"
+relative_headers="$(get_relative_includes ${1})"
+
+echo "Looking for absolute headers ... "
+echo
+for header in ${absolute_headers}; do
+ absheader="/usr/include/${header}"
+ if [[ -e ${absheader} ]]; then
+ abs_headerpaths="${abs_headerpaths} ${absheader}"
+ echo " Looking for ${absheader} ... OK"
+ else
+ # Try as a relative header in case people use -I with <>
+ relative_headers="${relative_headers} ${header}"
+ decho " Looking for ${absheader} ... Not found!"
+ fi
+done
+
+echo
+echo "Looking for relative headers ... "
+echo
+for header in ${relative_headers}; do
+ fullheader=${header}
+ header=${header##*/}
+ # Prefer headers in tarball over /usr/include
+ header_options=$(find ${location} -name ${header} | grep ${fullheader})
+ if [[ -z ${header_options} ]]; then
+ header_options="$(find /usr/include -name ${header} | grep ${fullheader})"
+ header_loc="/usr/include"
+ else
+ decho " Local header ${header} ... Not considering."
+ local_headers="${local_headers} ${header}"
+ continue
+ fi
+ count="0"
+ for found in ${header_options}; do
+ (( count++ ))
+ done
+ if [[ ${count} -ge 2 ]]; then
+ echo " Looking for ${header} ... "
+ echo " More than one option found for ${header} in ${header_loc}."
+ echo " Not considering ${header}."
+ duplicate_headers="${duplicate_headers} ${header}"
+ continue
+ elif [[ ${count} -le 0 ]]; then
+ decho " Looking for ${header} ... Not found!"
+ unfound_headers="${unfound_headers} ${header}"
+ continue
+ fi
+ header=${header_options}
+ if [[ -e ${header} ]] && [[ ${header_loc} = /usr/include ]]; then
+ rel_headerpaths="${rel_headerpaths} ${header}"
+ echo " Looking for ${header} ... OK"
+ else
+ decho " Looking for ${header} ... Not found!"
+ fi
+done
+
+echo "Tracing headers back to packages ..."
+echo
+echo "Headers ignored because they exist in the tarball:"
+echo
+for header in ${local_headers}; do
+ echo "${header}"
+done
+echo
+echo "Headers ignored because of duplicates in /usr/include:"
+echo
+for header in ${duplicate_headers}; do
+ echo "${header}"
+done
+echo
+echo "Headers ignored because they weren't found:"
+echo
+for header in ${unfound_headers}; do
+ echo "${header}"
+done
+echo
+echo "Absolute headers:"
+echo
+track_headers ${abs_headerpaths}
+echo
+echo "Relative headers:"
+echo
+track_headers ${rel_headerpaths}
--- /dev/null
+#!/bin/bash
+
+# CHANGES
+#
+# 20051211: Move most of the logic to check for bad links into get_libnames()
+# seds, so we don't wrongly sed out whole link lines. Seems to catch more
+# problems, such as ' or ` or -- in a link.
+# 20051210: Prefer qfile from portage-utils over equery if it's available.
+# Check for ... in "link" lines because configure checks are not links.
+# Change get_link_generic() to handle whole lines at a time instead of single
+# words, so get_linklines() works.
+# 20051210: Rework get_libnames() to use a new style of grep, because the old
+# way was broken on some packages from the \b. Also optimize the "Looking for
+# libraries" section to only grep the log file once for links and cache it;
+# also only grep the link lines ones for a given library, then parse the
+# output for static or shared. Should speed things up considerably for large
+# packages. I get 5 seconds in Analyzing log and 15 in Looking for libs on an
+# xorg-x11-6.8.99.15 log on second run.
+# Create get_link_generic() that both sections call with different options.
+
+usage() {
+ echo "${0##*/} compilation_log"
+ echo " Checks for -lfoo link commands and finds the library owners."
+ exit 1
+}
+
+if [[ $# -lt 1 || $1 == -h || $1 == --help ]]; then
+ usage
+fi
+
+
+# Finds all lines in a file that involve linking
+# get_link_generic(char *grep_opts, char *filename)
+get_link_generic() {
+ egrep ${1} '\-l\w[^[:space:]]*' ${2} \
+ | while read linker; do
+ # -linker is passed through to ld and doesn't mean the inker lib.
+ # The new -w in grep makes sure they're separate "words", but its
+ # "word" characters only include alnum and underscore, so -- gets
+ # through.
+ # Some configure lines with ... match, so we drop them
+ # Some of the configure options match, so we get rid of = for that.
+ if \
+ [[ "${linker}" != *...* ]] \
+ && [[ "${linker}" != -lib ]] \
+ && [[ "${linker}" != -libs ]]; then
+ echo ${linker}
+ fi
+ done
+}
+
+# Note the lack of -o, as compared to get_libnames() egrep
+get_linklines() {
+ get_link_generic "-w" ${1} | sort | uniq
+}
+
+get_libnames() {
+ for x; do
+ get_link_generic "-o -w" ${x} \
+ | sed \
+ -e "/^-link/d" \
+ -e "/^-lib/d" \
+ -e "s:^-l::g" \
+ -e "/=/d" \
+ -e "/'/d" \
+ -e "/^-/d" \
+ -e "s:\.*$::g" \
+ -e "s:|::g" \
+ -e "s:\"::g" \
+ -e "/^-link/d" \
+ -e "/^-lib/d"
+ done | sort | uniq
+}
+
+get_libdirs() {
+ cat /etc/ld.so.conf | sed -e "/^#/d"
+}
+
+check_exists() {
+ if [[ -n ${1// } ]]; then
+ return 0
+ fi
+
+ return 1
+}
+
+trace_to_packages() {
+ local paths=$1
+
+ check_exists "${paths}"
+ local ret=$?
+ if [[ $ret -ne 0 ]]; then
+ return 1
+ fi
+
+ if [[ -x $(which qfile 2> /dev/null) ]]; then
+ qfile -q ${paths} | sort | uniq
+ elif [[ -x $(which equery 2> /dev/null) ]]; then
+ equery -q belongs ${paths} | cut -d'(' -f1
+ elif [[ -x $(which rpm 2> /dev/null) ]]; then
+ rpm -qf ${paths}
+ else
+ echo "Couldn't find package query tool! Printing paths instead."
+ echo
+ for path in ${paths}; do
+ echo ${path}
+ done
+ fi
+}
+
+# *64 needs to be first, as *lib is a symlink to it so equery screws up
+libdirs="/lib64 /usr/lib64 /lib /usr/lib $(get_libdirs)"
+
+echo "Analyzing log ..."
+libnames=$(get_libnames "$@")
+
+#echo libnames=$libnames
+
+echo "Looking for libraries ..."
+linker_lines=$(get_linklines ${1})
+
+#echo linker_lines=$linker_lines
+
+for libname in ${libnames}; do
+ static=0
+ shared=0
+ line=$(echo ${linker_lines} | grep "\b-l${libname}\b")
+ if echo ${line} | grep -q '\b-static\b'; then
+ static=1
+ fi
+ if ! echo ${line} | grep -q '\b-static\b'; then
+ shared=1
+ fi
+ staticlibname="lib${libname}.a"
+ sharedlibname="lib${libname}.so"
+ if [[ ${static} -eq 1 ]]; then
+ echo -n " Looking for ${staticlibname} ... "
+ for libdir in ${libdirs}; do
+ found=0
+ if [[ -e ${libdir}/${staticlibname} ]]; then
+ libpaths="${libpaths} ${libdir}/${staticlibname}"
+ found=1
+ echo "OK"
+ break
+ fi
+ done
+ if [[ ${found} -ne 1 ]]; then
+ echo "Not found!"
+ fi
+ fi
+ if [[ ${shared} -eq 1 ]]; then
+ echo -n " Looking for ${sharedlibname} ... "
+ for libdir in ${libdirs}; do
+ found=0
+ if [[ -e ${libdir}/${sharedlibname} ]]; then
+ libpaths="${libpaths} ${libdir}/${sharedlibname}"
+ found=1
+ echo "OK"
+ break
+ fi
+ done
+ if [[ ${found} -ne 1 ]]; then
+ echo "Not found!"
+ fi
+ fi
+done
+
+# Add backslashes in front of any + symbols
+libpaths=${libpaths//+/\\+}
+
+echo "Looking for build tools (imake, etc) ..."
+BUILD_PKGS=$(egrep -h "$@" \
+ -e '^(/usr/(X11R6/)?bin/)?rman' \
+ -e '^(/usr/(X11R6/)?bin/)?gccmakedep' \
+ -e '^(/usr/(X11R6/)?bin/)?makedepend' \
+ -e '^(/usr/(X11R6/)?bin/)?imake' \
+ -e '^(/usr/(X11R6/)?bin/)?rman' \
+ -e '^(/usr/(X11R6/)?bin/)?lndir' \
+ -e '^(/usr/(X11R6/)?bin/)?xmkmf' \
+ | awk '{ print $1 }' \
+ | sort \
+ | uniq)
+
+for PKG in ${BUILD_PKGS}; do
+ PKG=$(basename ${PKG})
+ echo -n " Looking for ${PKG} ... "
+ if [[ -e /usr/bin/${PKG} ]]; then
+ echo "OK"
+ buildpaths="${buildpaths} ${PKG}"
+ else
+ echo "Not found!"
+ fi
+done
+
+echo
+echo "Tracing libraries back to packages ..."
+echo
+trace_to_packages "${libpaths}"
+
+echo
+echo "Tracing build tools back to packages ..."
+echo
+
+trace_to_packages "${buildpaths}"