Add included_headers.sh and linking_libs.sh from dberkholz
authorfuzzyray <fuzzyray@gentoo.org>
Wed, 9 May 2007 18:20:09 +0000 (18:20 -0000)
committerfuzzyray <fuzzyray@gentoo.org>
Wed, 9 May 2007 18:20:09 +0000 (18:20 -0000)
svn path=/; revision=397

trunk/src/dev-scripts/README [new file with mode: 0644]
trunk/src/dev-scripts/included_headers.sh [new file with mode: 0755]
trunk/src/dev-scripts/linking_libs.sh [new file with mode: 0755]

diff --git a/trunk/src/dev-scripts/README b/trunk/src/dev-scripts/README
new file mode 100644 (file)
index 0000000..990a2ab
--- /dev/null
@@ -0,0 +1,2 @@
+This directory is intended to be used for small developer oriented scripts used in gentoolkit-dev.
+If a script develops into a full fledged tool, it will be moved into its own subdirectory.
diff --git a/trunk/src/dev-scripts/included_headers.sh b/trunk/src/dev-scripts/included_headers.sh
new file mode 100755 (executable)
index 0000000..915628b
--- /dev/null
@@ -0,0 +1,159 @@
+#!/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}
diff --git a/trunk/src/dev-scripts/linking_libs.sh b/trunk/src/dev-scripts/linking_libs.sh
new file mode 100755 (executable)
index 0000000..a249305
--- /dev/null
@@ -0,0 +1,204 @@
+#!/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}"