xref: /OK3568_Linux_fs/buildroot/support/scripts/fix-rpath (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1#!/usr/bin/env bash
2
3# Copyright (C) 2016 Samuel Martin <s.martin49@gmail.com>
4# Copyright (C) 2017 Wolfgang Grandegger <wg@grandegger.com>
5#
6# This program is free software; you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation; either version 2 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14# General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program; if not, write to the Free Software
18# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20usage() {
21  cat <<EOF >&2
22Usage:  ${0} TREE_KIND
23
24Description:
25
26    This script scans a tree and sanitize ELF files' RPATH found in there.
27
28    Sanitization behaves the same whatever the kind of the processed tree,
29    but the resulting RPATH differs. The rpath sanitization is done using
30    "patchelf --make-rpath-relative".
31
32Arguments:
33
34    TREE_KIND    Kind of tree to be processed.
35                 Allowed values: host, target, staging
36
37Environment:
38
39    PATCHELF     patchelf program to use
40                 (default: HOST_DIR/bin/patchelf)
41
42    HOST_DIR     host directory
43    STAGING_DIR  staging directory
44    TARGET_DIR   target directory
45
46    TOOLCHAIN_EXTERNAL_DOWNLOAD_INSTALL_DIR
47                 (default HOST_DIR/opt/ext-toolchain)
48
49Returns:         0 if success or 1 in case of error
50
51EOF
52}
53
54: ${PATCHELF:=${HOST_DIR}/bin/patchelf}
55
56# ELF files should not be in these sub-directories
57HOST_EXCLUDEPATHS="/share/terminfo"
58STAGING_EXCLUDEPATHS="/usr/include /usr/share/terminfo"
59TARGET_EXCLUDEPATHS="/lib/firmware"
60
61main() {
62    local rootdir
63    local tree="${1}"
64    local find_args=( )
65    local sanitize_extra_args=( )
66
67    if ! "${PATCHELF}" --version > /dev/null 2>&1; then
68	echo "Error: can't execute patchelf utility '${PATCHELF}'"
69	exit 1
70    fi
71
72    case "${tree}" in
73        host)
74            rootdir="${HOST_DIR}"
75
76            # do not process the sysroot (only contains target binaries)
77            find_args+=( "-path" "${STAGING_DIR}" "-prune" "-o" )
78
79            # do not process the external toolchain installation directory to
80            # avoid breaking it.
81            test "${TOOLCHAIN_EXTERNAL_DOWNLOAD_INSTALL_DIR}" != "" && \
82                find_args+=( "-path" "${TOOLCHAIN_EXTERNAL_DOWNLOAD_INSTALL_DIR}" "-prune" "-o" )
83
84            for excludepath in ${HOST_EXCLUDEPATHS}; do
85                find_args+=( "-path" "${HOST_DIR}""${excludepath}" "-prune" "-o" )
86            done
87
88            # do not process the patchelf binary but a copy to work-around "file in use"
89            find_args+=( "-path" "${PATCHELF}" "-prune" "-o" )
90            cp "${PATCHELF}" "${PATCHELF}.__to_be_patched"
91
92            # we always want $ORIGIN-based rpaths to make it relocatable.
93            sanitize_extra_args+=( "--relative-to-file" )
94            ;;
95
96        staging)
97            rootdir="${STAGING_DIR}"
98
99            # ELF files should not be in these sub-directories
100            for excludepath in ${STAGING_EXCLUDEPATHS}; do
101                find_args+=( "-path" "${STAGING_DIR}""${excludepath}" "-prune" "-o" )
102            done
103
104            # should be like for the target tree below
105            sanitize_extra_args+=( "--no-standard-lib-dirs" )
106            ;;
107
108        target)
109            rootdir="${TARGET_DIR}"
110
111            for excludepath in ${TARGET_EXCLUDEPATHS}; do
112                find_args+=( "-path" "${TARGET_DIR}""${excludepath}" "-prune" "-o" )
113            done
114
115            # we don't want $ORIGIN-based rpaths but absolute paths without rootdir.
116            # we also want to remove rpaths pointing to /lib or /usr/lib.
117            sanitize_extra_args+=( "--no-standard-lib-dirs" )
118            ;;
119
120        *)
121            usage
122            exit 1
123            ;;
124    esac
125
126    find_args+=( "-type" "f" "-print" )
127
128    while read file ; do
129        # check if it's an ELF file
130        rpath=$(${PATCHELF} --print-rpath "${file}" 2>&1)
131        if test $? -ne 0 ; then
132            continue
133        fi
134
135        # make files writable if necessary
136        changed=$(chmod -c u+w "${file}")
137
138        # With per-package directory support, most RPATH of host
139        # binaries will point to per-package directories. This won't
140        # work with the --make-rpath-relative ${rootdir} invocation as
141        # the per-package host directory is not within ${rootdir}. So,
142        # we rewrite all RPATHs pointing to per-package directories so
143        # that they point to the global host directry.
144        changed_rpath=$(echo ${rpath} | sed "s@${PER_PACKAGE_DIR}/[^/]\+/host@${HOST_DIR}@")
145        if test "${rpath}" != "${changed_rpath}" ; then
146            ${PATCHELF} --set-rpath ${changed_rpath} "${file}"
147        fi
148
149        # call patchelf to sanitize the rpath
150        ${PATCHELF} --make-rpath-relative "${rootdir}" ${sanitize_extra_args[@]} "${file}"
151        # restore the original permission
152        test "${changed}" != "" && chmod u-w "${file}"
153    done < <(find "${rootdir}" ${find_args[@]})
154
155    # Restore patched patchelf utility
156    test "${tree}" = "host" && mv "${PATCHELF}.__to_be_patched" "${PATCHELF}"
157
158    # ignore errors
159    return 0
160}
161
162main ${@}
163