aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSven 'sleipnir' Rebhan <odinshorse@googlemail.com>2010-01-24 18:05:26 +0000
committerSven 'sleipnir' Rebhan <odinshorse@googlemail.com>2010-01-24 18:05:26 +0000
commit1d75b4396ee75e460d052705fb4f6b5458239a31 (patch)
treef81cf0a5dc62432abb84267927651d2b4dde059e
parentFixes ticket #292. (diff)
downloadembedded-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-xtools/cross-revdep-rebuild300
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