diff options
author | Sven 'sleipnir' Rebhan <odinshorse@googlemail.com> | 2010-01-24 18:05:26 +0000 |
---|---|---|
committer | Sven 'sleipnir' Rebhan <odinshorse@googlemail.com> | 2010-01-24 18:05:26 +0000 |
commit | 1d75b4396ee75e460d052705fb4f6b5458239a31 (patch) | |
tree | f81cf0a5dc62432abb84267927651d2b4dde059e | |
parent | Fixes ticket #292. (diff) | |
download | embedded-cross-1d75b4396ee75e460d052705fb4f6b5458239a31.tar.gz embedded-cross-1d75b4396ee75e460d052705fb4f6b5458239a31.tar.bz2 embedded-cross-1d75b4396ee75e460d052705fb4f6b5458239a31.zip |
Provide a first version of a cross-compile aware revdep-rebuild.
-rwxr-xr-x | tools/cross-revdep-rebuild | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/tools/cross-revdep-rebuild b/tools/cross-revdep-rebuild new file mode 100755 index 0000000..e3b09af --- /dev/null +++ b/tools/cross-revdep-rebuild @@ -0,0 +1,300 @@ +#!/bin/bash + +KEEP_TEMP=1 + +# Readonly variables: +declare -r ENV_FILE=0_env.rr # Contains environment variables +declare -r FILES_FILE=1_files.rr # Contains a list of files to search +declare -r LDPATH_FILE=2_ldpath.rr # Contains the LDPATH +declare -r BROKEN_FILE=3_broken.rr # Contains the list of broken files +declare -r ERRORS_FILE=3_errors.rr # Contains the ldd error output +declare -r RAW_FILE=4_raw.rr # Contains the raw list of packages +declare -r OWNERS_FILE=4_owners.rr # Contains the file owners +declare -r PKGS_FILE=4_pkgs.rr # Contains the unsorted bare package names +declare -r EBUILDS_FILE=4_ebuilds.rr # Contains the unsorted atoms + # (Appropriately slotted or versioned) +declare -r ORDER_FILE=5_order.rr # Contains the sorted atoms +declare -r STATUS_FILE=6_status.rr # Contains the ldd error output + +# Example: env SEARCH_DIRS="/usr/bin -*" revdep-rebuild will set SEARCH_DIRS +# to contain only /usr/bin +declare TMP_DIR # Dir containing the generated files. +declare CONFIG_DIR # Dir containing config files (usually ${ROOT}/etc). + +declare SEARCH_DIRS # List of dirs to search for executables and libraries +declare SEARCH_DIRS_MASK # List of dirs not to search +declare LD_LIBRARY_SEARCH_DIRS # List of dirs to search for dependency libraries +declare LD_LIBRARY_MASK # Mask of specially evaluated libraries + +# Cleanup a variable (duplicate spaces etc. +clean_var() { + gawk 'BEGIN {RS="[[:space:]]"} + /-\*/ {exit} + /[^[:space:]]/ {gsub(/\/\/+/, "/"); print}' | sort -u +} + +# Usage: progress i n +# i: current item +# n: total number of items to process +progress() { + if [[ -t 1 ]]; then + progress() { + local curProg=$(( $1 * 100 / $2 )) + (( curProg == OLDPROG )) && return # no change, output nothing + OLDPROG="$curProg" # must be a global variable + (( $1 == $2 )) && local lb=$'\n' + echo -ne '\r \r'"[ $curProg% ] $lb" + } + progress $@ + else # STDOUT is not a tty. Disable progress meter. + progress() { :; } + fi +} + +# Have a nice die command +die() { + local status=$1 + shift + eerror "$@" + exit $status +} + +# Setup the local environment +setup_env() { + # Get all the usefull functions like die etc + source /etc/init.d/functions.sh + + # Check for a valid CHOST + [[ -n "${CHOST}" ]] || die 1 "No CHOST! variable set!" + + # Set the ROOT directory + ROOT="/usr/${CHOST}" + CONFIG_DIR="${ROOT}/etc" + + # Create a temporary directory and change to it. + TMP_DIR=$(mktemp -d --tmpdir="/tmp" "cross-revdep-XXXXXXXX") || + die $? "Creating tempdir failed!" + cd "${TMP_DIR}" || + die $? "Changing to tempdir failed!" + [[ -n "${DEBUG}" ]] && einfo "Changing to temporary dir ${TMP_DIR}" +} + +# Setup the paths to search (and filter the ones to avoid) +setup_search_paths_and_masks() { + local configfile sdir mdir skip_me filter_SEARCH_DIRS + + einfo "Configuring search environment" + + # Update the incremental variables using /etc/profile.env, /etc/ld.so.conf, + # portage, and the environment + + # Read the incremental variables from environment and portage + # Until such time as portage supports these variables as incrementals + # The value will be what is in /etc/make.conf + SEARCH_DIRS+=" "$(unset SEARCH_DIRS; portageq envvar SEARCH_DIRS) + SEARCH_DIRS_MASK+=" "$(unset SEARCH_DIRS_MASK; portageq envvar SEARCH_DIRS_MASK) + LD_LIBRARY_MASK+=" "$(unset LD_LIBRARY_MASK; portageq envvar LD_LIBRARY_MASK) + + # Add the defaults + if [[ -d "${CONFIG_DIR}/revdep-rebuild" ]]; then + for configfile in "${CONFIG_DIR}/revdep-rebuild/"*; do + SEARCH_DIRS+=" "$(. $configfile; echo $SEARCH_DIRS) + SEARCH_DIRS_MASK+=" "$(. $configfile; echo $SEARCH_DIRS_MASK) + LD_LIBRARY_MASK+=" "$(. $configfile; echo $LD_LIBRARY_MASK) + done + else + SEARCH_DIRS+=" /bin /sbin /usr/bin /usr/sbin /lib* /usr/lib*" + SEARCH_DIRS_MASK+=" /opt/OpenOffice /usr/lib/openoffice" + LD_LIBRARY_MASK+=" libodbcinst.so libodbc.so libjava.so libjvm.so" + fi + + # Get the ROOTPATH and PATH from /etc/profile.env + if [[ -r "${CONFIG_DIR}/profile.env" && -s "${CONFIG_DIR}/profile.env" ]]; then + SEARCH_DIRS+=" "$(. "${CONFIG_DIR}/profile.env"; /usr/bin/tr ':' ' ' <<< "$ROOTPATH $PATH") + fi + + # Get the directories from /etc/ld.so.conf + if [[ -r "${CONFIG_DIR}/ld.so.conf" && -s "${CONFIG_DIR}/ld.so.conf" ]]; then + SEARCH_DIRS+=" "$(sed '/^#/d;s/#.*$//' "${CONFIG_DIR}/ld.so.conf") + fi + + # Set the final variables + SEARCH_DIRS=$(clean_var <<< "$SEARCH_DIRS") + SEARCH_DIRS_MASK=$(clean_var <<< "$SEARCH_DIRS_MASK") + LD_LIBRARY_SEARCH_DIRS=$(clean_var <<< "$LD_LIBRARY_SEARCH_DIRS") + LD_LIBRARY_MASK=$(clean_var <<< "$LD_LIBRARY_MASK") + + # Filter masked paths from SEARCH_DIRS + for sdir in ${SEARCH_DIRS} ; do + skip_me= + for mdir in ${SEARCH_DIRS_MASK}; do + [[ ${sdir} == ${mdir}/* ]] && skip_me=1 && break + done + [[ -n ${skip_me} ]] || filter_SEARCH_DIRS+=" ${ROOT}/${sdir}" + done + SEARCH_DIRS=$(clean_var <<< "${filter_SEARCH_DIRS}") + + [[ $SEARCH_DIRS ]] || die 1 "No search defined -- this is a bug." + + echo "CONFIG_DIR=${CONFIG_DIR}" > "${ENV_FILE}" + echo "SEARCH_DIRS=(${SEARCH_DIRS[@]})" >> "${ENV_FILE}" + echo "LD_LIBRARY_MASK=(${LD_LIBRARY_MASK[@]})" >> "${ENV_FILE}" + einfo "Generated new ${ENV_FILE}" +} + +clean_exit() { + if [[ ! $KEEP_TEMP ]]; then + cd - > /dev/null + rm -rf "${TMP_DIR}" + fi + einfo "" + einfo "Dynamic linking on your system is consistent... All done. " + exit 0 +} + +# Finds all ELF files among the executables and libraries +# in the search directory list. +get_files() { + einfo "Collecting system binaries and libraries" + + find ${SEARCH_DIRS[@]} \ + -type f \ + \( -perm /111 -o -name '*.so' -o -name '*.so.*' -o -name '*.la' \) \ + -fprint "${FILES_FILE}" \ + > /dev/null 2>&1 + einfo "Generated new ${FILES_FILE}" +} + +get_ldpath() { + einfo 'Collecting complete LD_LIBRARY_PATH' + + # Ensure that the "trusted" lib directories are at the start of the path + LD_LIBRARY_SEARCH_DIRS+="${ROOT}/lib ${ROOT}/usr/lib" + LD_LIBRARY_SEARCH_DIRS+=" "$(sed '/^#/d;s/#.*$//' < "${CONFIG_DIR}/ld.so.conf") + LD_LIBRARY_SEARCH_DIRS=$(clean_var <<< "$LD_LIBRARY_SEARCH_DIRS") + + echo "$LD_LIBRARY_SEARCH_DIRS" > "$LDPATH_FILE" + einfo "Generated new $LDPATH_FILE" +} + +# Check if a single file is ok +check_file() { + local file="$1" + + [[ -n "${DEBUG}" ]] && einfo "Checking $file" + + # Get the required dependencies out of the ELF file and + # try to find these dependencies in the LD_LIBRARY_SEARCH_DIRS! + DEPENDENCIES=$(${CHOST}-readelf -d "${file}" | \ + grep "(NEEDED)" | \ + sed -e 's/^.*\[//' -e 's/\].*$//') + status="ok" + for dep in $DEPENDENCIES ; do + # Search the dependency and stop at first occurance + ret=$(find -L ${LD_LIBRARY_SEARCH_DIRS[@]} \ + -type f \ + -name ${dep} \ + -print \ + -quit \ + 2>/dev/null) + if [ -z "$ret" ]; then + status="broken" + break + fi + done + + # We found a broken files. Spit this file out and add it to broken. + if [ "$status" != "ok" ] ; then + eindent + ewarn "broken ${file} (requires $dep)" + eoutdent + echo "$file" >> "${BROKEN_FILE}" + fi +} + +check_linking() { + local i + local total + + einfo "Checking dynamic linking" + rm -f ${BROKEN_FILE} || die $? "Unable to remove $BROKEN_FILE" + + # Get the total number of files + total=$(wc -l "${FILES_FILE}" | cut -d' ' -f1) + + # Check all found elf files + i=0 + cat "${FILES_FILE}" | while read file; do + # Only process the file if it is an ELF file. + file "${file}" | grep -qF "${file}: ELF " + [[ "$?" == "0" ]] && check_file "${file}" + + # Increment progressbar + let "i++" + progress ${i} ${total} + done + + # If no broken file exists, everything is fine. + [[ -f "${BROKEN_FILE}" ]] || clean_exit + + einfo "Generated new $BROKEN_FILE" +} + +get_file_owners() { + export ROOT + + einfo 'Assigning files to packages' + + rm -f ${RAW_FILE} || die $? "Unable to remove $RAW_FILE" + rm -f ${OWNERS_FILE} || die $? "Unable to remove $OWNERS_FILE" + + # Get the owners of the broken files + eindent + cat "${BROKEN_FILE}" | while read file; do + pkg=$(qfile --nocolor --exact --root-prefix "${file}" | cut -d' ' -f1) + [[ "$?" != "0" ]] && pkg="" + [[ -n "${pkg}" ]] && echo "=${pkg}" >> "${RAW_FILE}" + [[ -n "${pkg}" ]] || ewarn "${file} not owned by any package" + [[ -n "${pkg}" ]] || pkg="(none)" + echo "${file} -> ${pkg}" >> "${OWNERS_FILE}" + done + eoutdent + einfo "Generated new $RAW_FILE and $OWNERS_FILE" +} + +clean_packages() { + einfo 'Cleaning list of packages to rebuild' + sort -u "$RAW_FILE" > "$EBUILDS_FILE" + einfo "Generated new $EBUILDS_FILE" +} + +rebuild() { + einfo 'All prepared. Starting rebuild' + REBUILD_LIST=$(tr '\n' ' ' < "$EBUILDS_FILE") + echo "emerge-${CHOST} --keep-going ${EMERGE_OPTIONS[@]} ${REBUILD_LIST}" + + exec emerge-${CHOST} --keep-going ${EMERGE_OPTIONS[@]} ${REBUILD_LIST} +} + +# Setup the script environment +setup_env + +# Setup the search directories +setup_search_paths_and_masks + +# Find all ELF files among the executables and libraries +# in the search directory list. +get_files + +# Get the path where we search for the dependency libraries +get_ldpath + +# Check the files +check_linking + +# Get the owners of the broken files and clean the package list +get_file_owners +clean_packages + +# Finally rebuild the packages +rebuild |