scripts/populate.in
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Thu Mar 25 22:42:00 2010 +0100 (2010-03-25)
changeset 1861 a5c020c3d31d
parent 1860 ed94d8e12b63
child 1862 7fec5db8933c
permissions -rw-r--r--
scripts/populate: properly locate the sysroot and required tools

This fixes two problems:
- the sysroot might be in a sub-directory (think SYSROOT_DIR_PREFIX)
- it is not needed to have the target tuple to properly detect the sysroot
and the required tools

As a side effect, this script is now no longer dependent on the target
tuple, and in the future, we might be able to share it across many
toolchains (when/if we can install all of them in the same place).
     1 #!@@CT_bash@@
     2 # This script will populate the root directory with libs from the sysroot.
     3 # (C) 2007 Yann E. MORIN
     4 # Licensed under the GPL v2
     5 set -e
     6 
     7 # Use the tools discovered by crosstool-NG's ./configure:
     8 install="@@CT_install@@"
     9 grep="@@CT_grep@@"
    10 sed="@@CT_sed@@"
    11 
    12 # Detect where the toolchain is:
    13 CT_PREFIX_DIR="$(cd "$(dirname "$0")/.."; pwd)"
    14 CT_GCC="${0%-populate}-gcc"
    15 CT_READELF="${0%-populate}-readelf"
    16 CT_CFG_PREFIX_DIR="$("${CT_GCC}" -v 2>&1            \
    17                      |tr ' ' '\n'                   \
    18                      |"${grep}" -E -- '--prefix='   \
    19                      |cut -d = -f 2-
    20                     )"
    21 CT_CFG_SYSROOT_DIR="$("${CT_GCC}" -v 2>&1                   \
    22                       |tr ' ' '\n'                          \
    23                       |"${grep}" -E -- '--with-sysroot='    \
    24                       |cut -d = -f 2-
    25                      )"
    26 CT_SYSROOT_DIR="$(echo "${CT_CFG_SYSROOT_DIR}"                                  \
    27                   |"${sed}" -r -e "s:^${CT_CFG_PREFIX_DIR}:${CT_PREFIX_DIR}:;"  \
    28                   |"${sed}" -r -e 's,/+,/,g;'                                   \
    29                  )"
    30 
    31 myname=$(basename "$0")
    32 
    33 doHelp() {
    34     cat <<_EOF_
    35 NAME
    36     $myname - populate the target root file system
    37 
    38 SYNOPSIS
    39     $myname OPTIONS -s source_root -d destination_root
    40 
    41 DESCRIPTION
    42     $myname will 'populate' your target root file system ('src_dir') with
    43     libraries from the toolchain (eg. libc.so...), storing the result into
    44     'dst_dir'.
    45 
    46 OPTIONS
    47     -s src_dir
    48         use 'src_dir' as the un-populated (source) root directory
    49 
    50     -d dst_dir
    51         use 'dst_dir' as the place to put the populated root directory
    52 
    53     -r sysroot_dir
    54         use 'sysroot_dir' as the sysroot instead of the toolchain default
    55 
    56     -l name1[:name2[...]]
    57         Always add the specified shared library/ies name1, name2... from the
    58         toolchain (in the sys-root). Actual library names are searched as
    59         follows (where 'name' is replaced with the given name) in the
    60         sys-root directory:
    61           - libname.so
    62           - name.so
    63           - name
    64         If the file is found, then the SONAME of the library is used, and the
    65         library is copied with that name. If the library was not found, this
    66         yields an error (unless -f was given).
    67 
    68     -L file
    69         Read 'file' for a list of shared libraries to always add from the
    70         toolchain. The file should contain one library name per line; text
    71         after a # is ignored until the end of the line; spaces are ignored;
    72         empty lines are ignored. Libraries are searched for as with -l.
    73 
    74     -f  force execution: if destination directory already exists, it will be
    75         removed first; if a specified library (above) was not found, continue.
    76         Note: if using -m and the destination directory already exists, it
    77         is *not* removed, see below.
    78 
    79     -m  Merge the source root directory with the destination root directory.
    80         If the latter does not exist, it is created, and -m is ignored.
    81         If the destination droot directory exists, then the content of the
    82         source root directory is copied in there, and the result is populated
    83         as usual.
    84         It can be usefull if constructing a rootfs incrementally from many
    85         smaller source root directories, or if your destination root directory
    86         is an NFS export that your target mounts as / (and you don't want to
    87         re-run exportfs -av everytime). USE WITH CARE!
    88 
    89     -v  Be verbose. By default, populate is absolutely silent.
    90 
    91 _EOF_
    92 }
    93 
    94 CT_ROOT_SRC_DIR=
    95 CT_ROOT_DST_DIR=
    96 CT_LIB_LIST=
    97 CT_LIB_FILE=
    98 CT_MERGE=
    99 CT_FORCE=
   100 CT_PRINTF=:
   101 OPTIND=1
   102 while getopts ":s:d:r:l:L:fmvh" CT_OPT; do
   103     case "${CT_OPT}" in
   104         s)  CT_ROOT_SRC_DIR="${OPTARG}";;
   105         d)  CT_ROOT_DST_DIR="${OPTARG}";;
   106         r)  CT_SYSROOT_DIR="${OPTARG}";;
   107         l)  CT_LIB_LIST="${CT_LIB_LIST}:${OPTARG}";;
   108         L)  CT_LIB_FILE="${OPTARG}";;
   109         f)  CT_FORCE=y;;
   110         m)  CT_MERGE=y;;
   111         v)  CT_PRINTF=printf;;
   112         h)  doHelp
   113             exit 0
   114             ;;
   115         :)  echo "$myname: '-${OPTARG}' takes exactly one argument."
   116             exit 1
   117             ;;
   118         ?)  echo "$myname: unknown option '-${OPTARG}'."
   119             exit 1
   120             ;;
   121     esac
   122 done
   123 
   124 # Sanity checks
   125 if [ -z "${CT_ROOT_SRC_DIR}" -o -z "${CT_ROOT_DST_DIR}" ]; then
   126     doHelp
   127     exit 1
   128 fi
   129 if [ ! -d "${CT_ROOT_SRC_DIR}" ]; then
   130     echo "$myname: '${CT_ROOT_SRC_DIR}': no such file or directory"
   131     exit 1
   132 fi
   133 if [ ! -d "${CT_SYSROOT_DIR}" ]; then
   134     echo "$myname: '${CT_SYSROOT_DIR}': no such file or directory"
   135     exit 1
   136 fi
   137 # If the dest dir does not exist, all is well
   138 # If merging, we accept an existing dest directory
   139 # If forcing and not merging, we remove an exiting dest directory
   140 # If not forcing and not merging, we do not accept an exiting dest directory
   141 if [ -d "${CT_ROOT_DST_DIR}" ]; then
   142     case "${CT_FORCE}:${CT_MERGE}" in
   143         *:y)    ;;
   144         y:)     rm -rf "${CT_ROOT_DST_DIR}";;
   145         :)      echo "$myname: '${CT_ROOT_DST_DIR}': already exists" && exit 1 ;;
   146     esac
   147 fi
   148 src_inode=$(stat -c '%i' "${CT_ROOT_SRC_DIR}/.")
   149 dst_inode=$(stat -c '%i' "${CT_ROOT_DST_DIR}/." 2>/dev/null || true)
   150 if [ "${src_inode}" -eq "$((dst_inode+0))" ]; then
   151     echo "$myname: source and destination are the same!"
   152     exit 1
   153 fi
   154 
   155 # Check existence of the forced libraries file
   156 if [ -n "${CT_LIB_FILE}" -a ! \( -f "${CT_LIB_FILE}" -a -r "${CT_LIB_FILE}" \) ]; then
   157     echo "$myname: forced libraries file '${CT_LIB_FILE}' not found!"
   158     exit 1
   159 fi
   160 
   161 # Create the working copy, no issue if already existing
   162 mkdir -p "${CT_ROOT_DST_DIR}"
   163 
   164 # Make all path absolute
   165 CT_ROOT_SRC_DIR=$(cd "${CT_ROOT_SRC_DIR}"; pwd)
   166 CT_ROOT_DST_DIR=$(cd "${CT_ROOT_DST_DIR}"; pwd)
   167 
   168 # Populate the destination directory with files from the source directory
   169 pushd "${CT_ROOT_SRC_DIR}" >/dev/null
   170 cp -a . "${CT_ROOT_DST_DIR}"
   171 popd >/dev/null
   172 
   173 # A function do search for a library
   174 # Usage: do_add_lib libname
   175 # returns: 0 if library was found and added, !0 otherwise
   176 do_add_lib() {
   177     local libname="$1"
   178     local true_libname
   179     local dir
   180     local mode
   181 
   182     for dir in lib usr/lib; do
   183         ${CT_PRINTF} "    trying in '%s'" "${dir}"
   184         libfile="${CT_SYSROOT_DIR}/${dir}/${libname}"
   185         ${CT_PRINTF} ": '%s'\n" "${libfile}"
   186         if [ -e "${libfile}" ]; then
   187             mkdir -p "${dir}"
   188             true_libname=$("${CT_READELF}" -d "${libfile}"          \
   189                            |"${grep}" "Library soname:"             \
   190                            |"${sed}" -r -e 's,.+\[(.+)\] *$,\1,;'   \
   191                           )
   192             case "${libfile}" in
   193                 */ld*)  mode=0755;;
   194                 *)      mode=0644;;
   195             esac
   196             ${CT_PRINTF} "      installing as '%s/%s', mode='%s'\n" "${dir}" "${true_libname}" "${mode}"
   197             "${install}" -m "${mode}" "${libfile}" "${dir}/${true_libname}"
   198             return 0
   199             break
   200         fi
   201     done
   202     return 1
   203 }
   204 
   205 # We'll work in the copied rootfs
   206 pushd "${CT_ROOT_DST_DIR}" >/dev/null
   207 
   208 # First of, copy the forced libraries into the working copy
   209 if [ -n "${CT_LIB_FILE}" ]; then
   210     lib_list=$("${sed}" -r -e ':loop; s/#.*//;'         \
   211                            -e 's/[[:space:]]+//g;'      \
   212                            -e 's/([^:])$/\1:/;'         \
   213                            -e '/$/N; s/\n//; tloop;'    \
   214                         "${CT_LIB_FILE}"
   215               )
   216     CT_LIB_LIST=$(echo "${CT_LIB_LIST}:${lib_list}"             \
   217                   |"${sed}" -r -e 's/:+/:/g; s/^:+//; s/:+$//;' \
   218                  )
   219 fi
   220 CT_LIB_LIST=$(echo "${CT_LIB_LIST}:${lib_list}"             \
   221               |"${sed}" -r -e 's/^:+//; s/:+$//; s/:+/ /g;' \
   222              )
   223 if [ -n "${CT_LIB_LIST}" ]; then
   224     ${CT_PRINTF} "Installing forced libraries...\n"
   225     for name in ${CT_LIB_LIST}; do
   226         [ -z "${name}" ] && continue
   227         found=0
   228         for libname in "lib${name}.so" "${name}.so" "${name}"; do
   229             ${CT_PRINTF} "  searching for '%s'\n" "${libname}"
   230             if do_add_lib "${libname}"; then
   231                 found=1
   232                 break
   233             fi
   234         done
   235         if [ ${found} -eq 0 ]; then
   236             echo "$myname: library '${libname}' not found!"
   237             [ "${CT_FORCE}" = y ] || exit 1
   238         fi
   239     done
   240 fi
   241 
   242 # Parse the working copy for executables and libraries
   243 still_needed=1
   244 while [ ${still_needed} -eq 1 ]; do
   245     ${CT_PRINTF} "Looping...\n"
   246     still_needed=0
   247     for f in $(find . -type f -exec file {} \;                                              \
   248                |"${grep}" -E ': ELF [[:digit:]]+-bit (L|M)SB (executable|shared object),'   \
   249                |cut -d ":" -f 1                                                             \
   250               ); do
   251         ${CT_PRINTF} "Scanning '%s'\n" "${f}"
   252         for libname in $("${CT_READELF}" -d "${f}"                              \
   253                          |"${grep}" -E '\(NEEDED\)[[:space:]]+Shared library:'  \
   254                          |"${sed}" -r -e 's,.+\[(.+)\] *$,\1,;'                 \
   255                         ); do
   256             ${CT_PRINTF} "  searching for '%s'\n" "${libname}"
   257             if [    -e "lib/${libname}"     \
   258                  -o -e "usr/lib/${libname}" ]; then
   259                 ${CT_PRINTF} "    already present\n"
   260                 continue
   261             fi
   262             if do_add_lib "${libname}"; then
   263                 still_needed=1
   264             else
   265                 echo "$myname: library '${libname}' not found!"
   266             fi
   267         done
   268     done
   269 done
   270 
   271 # OK, we're done. Back off.
   272 popd >/dev/null