#!/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" >/dev/stderr echo " Returns owners of all include files used. ${0##*/} defaults to" >/dev/stderr echo " files in /usr/include, so if a file with the same name within the" >/dev/stderr echo " source is the actual one used, false dependencies may be printed." >/dev/stderr echo >/dev/stderr echo " -d" >/dev/stderr echo " Show debug output: Print files not found" >/dev/stderr exit 1 } decho() { if [[ -n "${DEBUG}" ]]; then echo "${1}" >/dev/stderr 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 } escape() { local TOKEN while read -n 1; do case ${REPLY} in +) TOKEN='\+' ;; *) TOKEN=$REPLY ;; esac echo -n "${TOKEN}" done < <(echo $@) echo } track_headers() { if [[ -x $(which qfile 2> /dev/null) ]]; then qlist -ICSv $(escape $(qfile -qvC ${@})) # qfile ${@} | cut -d'(' -f1 | sort | uniq else echo "Couldn't find qfile! Printing headerpaths instead." >/dev/stderr echo >/dev/stderr for header in ${@}; do echo ${header} done fi } echo "Analyzing source ... " >/dev/stderr absolute_headers="$(get_absolute_includes ${1})" relative_headers="$(get_relative_includes ${1})" echo "Looking for absolute headers ... " >/dev/stderr echo >/dev/stderr for header in ${absolute_headers}; do absheader="/usr/include/${header}" if [[ -e ${absheader} ]]; then abs_headerpaths="${abs_headerpaths} ${absheader}" echo " Looking for ${absheader} ... OK" >/dev/stderr 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 >/dev/stderr echo "Looking for relative headers ... " >/dev/stderr echo >/dev/stderr 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} ... " >/dev/stderr echo " More than one option found for ${header} in ${header_loc}." >/dev/stderr echo " Not considering ${header}." >/dev/stderr 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" >/dev/stderr else decho " Looking for ${header} ... Not found!" fi done echo "Tracing headers back to packages ..." >/dev/stderr echo >/dev/stderr echo "Headers ignored because they exist in the tarball:" >/dev/stderr echo >/dev/stderr for header in ${local_headers}; do echo "${header}" >/dev/stderr done echo >/dev/stderr echo "Headers ignored because of duplicates in /usr/include:" >/dev/stderr echo >/dev/stderr for header in ${duplicate_headers}; do echo "${header}" >/dev/stderr done echo >/dev/stderr echo "Headers ignored because they weren't found:" >/dev/stderr echo >/dev/stderr for header in ${unfound_headers}; do echo "${header}" >/dev/stderr done echo >/dev/stderr echo "Absolute headers:" >/dev/stderr echo >/dev/stderr track_headers ${abs_headerpaths} echo >/dev/stderr echo "Relative headers:" >/dev/stderr echo >/dev/stderr track_headers ${rel_headerpaths}