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