You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
191 lines
4.7 KiB
191 lines
4.7 KiB
#!/bin/bash
|
|
#
|
|
# Copyright (C) 2020 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
# This program fixes prebuilt ELF check errors by updating the "shared_libs"
|
|
# fields in Android.bp.
|
|
#
|
|
# Example:
|
|
# $ source build/envsetup.sh
|
|
# $ m fix_android_bp_prebuilt bpflatten bpmodify
|
|
# $ fix_android_bp_prebuilt --in-place path_to_problematic_android_bp
|
|
|
|
set -e
|
|
|
|
function usage() {
|
|
cat <<EOF
|
|
Usage:
|
|
$0 [OPTION]... FILE
|
|
|
|
Options:
|
|
--in-place
|
|
Edit file in place (overwrites source file)
|
|
--diff
|
|
Show diffs
|
|
-h, --help, --usage
|
|
Display this message and exit
|
|
EOF
|
|
}
|
|
|
|
function exit_handler() {
|
|
readonly EXIT_CODE="$?"
|
|
# Cleanup any temporary files
|
|
rm -rf "$TEMP_DIR"
|
|
exit "$EXIT_CODE"
|
|
}
|
|
|
|
trap exit_handler EXIT
|
|
|
|
function trim_space() {
|
|
echo "$1" | sed -E 's/^[[:space:]]+//;s/[[:space:]]+$//'
|
|
}
|
|
|
|
function get_prop() {
|
|
echo "${MODULE_PROP_VALUES_DICT[${1}:${2}]}"
|
|
}
|
|
|
|
function rewrite_prop() {
|
|
local ORIGINAL_VALUE=$(trim_space "$(get_prop "$1" "$2")")
|
|
if [[ -n "$ORIGINAL_VALUE" ]]; then
|
|
bpmodify -m "$1" -property "$2" -r "$ORIGINAL_VALUE" -w "$TEMP_ANDROID_BP"
|
|
fi
|
|
if [[ -n "$3" ]]; then
|
|
bpmodify -m "$1" -property "$2" -a "$3" -w "$TEMP_ANDROID_BP"
|
|
fi
|
|
}
|
|
|
|
function get_dt_needed() {
|
|
local DYNAMIC_TABLE=$($READELF -d "${ANDROID_BP_DIR}/$1")
|
|
if [[ "$?" -ne 0 ]]; then
|
|
return 1
|
|
fi
|
|
echo "$DYNAMIC_TABLE" |
|
|
sed -n -E 's/^[[:space:]]*0x[[:xdigit:]]+[[:space:]]+\(NEEDED\).*\[(.+)\.so\].*$/\1/p' |
|
|
xargs
|
|
}
|
|
|
|
function unique() {
|
|
echo "$1" | xargs -n1 | sort | uniq | xargs
|
|
}
|
|
|
|
|
|
while [[ "$1" =~ ^- ]]; do
|
|
case "$1" in
|
|
-h | --help | --usage)
|
|
usage
|
|
exit 0
|
|
;;
|
|
--in-place)
|
|
EDIT_IN_PLACE=1
|
|
;;
|
|
--diff)
|
|
SHOW_DIFF=1
|
|
;;
|
|
-x)
|
|
set -x
|
|
;;
|
|
--)
|
|
shift
|
|
break
|
|
;;
|
|
*)
|
|
echo >&2 "Unexpected flag: $1"
|
|
usage >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if ! [[ -f "$1" ]]; then
|
|
echo >&2 "No such file: '$1'"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ -e "$(command -v llvm-readelf)" ]]; then
|
|
READELF="llvm-readelf"
|
|
elif [[ -e "$(command -v readelf)" ]]; then
|
|
READELF="readelf -W"
|
|
else
|
|
echo >&2 'Cannot find readelf in $PATH, please run:'
|
|
echo >&2 '$ source build/envsetup.sh'
|
|
exit 1
|
|
fi
|
|
|
|
if ! [[ -e "$(command -v bpflatten)" && -e "$(command -v bpmodify)" ]]; then
|
|
echo >&2 'Cannot find bpflatten and bpmodify in $PATH, please run:'
|
|
echo >&2 '$ source build/envsetup.sh'
|
|
echo >&2 '$ m blueprint_tools'
|
|
exit 1
|
|
fi
|
|
|
|
readonly EDIT_IN_PLACE
|
|
readonly SHOW_DIFF
|
|
readonly READELF
|
|
readonly ANDROID_BP="$1"
|
|
readonly ANDROID_BP_DIR=$(dirname "$ANDROID_BP")
|
|
readonly TEMP_DIR=$(mktemp -d)
|
|
readonly TEMP_ANDROID_BP="${TEMP_DIR}/Android.bp"
|
|
|
|
cp -L "$ANDROID_BP" "$TEMP_ANDROID_BP"
|
|
|
|
# This subshell and `eval` must be on separate lines, so that eval would not
|
|
# shadow the subshell's exit code.
|
|
# In other words, if `bpflatten` fails, we mustn't eval its output.
|
|
FLATTEN_COMMAND=$(bpflatten --bash "$ANDROID_BP")
|
|
eval "$FLATTEN_COMMAND"
|
|
|
|
for MODULE_NAME in "${MODULE_NAMES[@]}" ; do
|
|
MODULE_TYPE="${MODULE_TYPE_DICT[${MODULE_NAME}]}"
|
|
if ! [[ "$MODULE_TYPE" =~ ^(.+_)?prebuilt(_.+)?$ ]]; then
|
|
continue
|
|
fi
|
|
|
|
SRCS=$(get_prop "$MODULE_NAME" "srcs")
|
|
SHARED_LIBS=$(get_prop "$MODULE_NAME" "shared_libs")
|
|
if [[ -n "${SRCS}" ]]; then
|
|
DT_NEEDED=$(get_dt_needed "$SRCS")
|
|
if [[ $(unique "$DT_NEEDED") != $(unique "$SHARED_LIBS") ]]; then
|
|
rewrite_prop "$MODULE_NAME" "shared_libs" "$DT_NEEDED"
|
|
fi
|
|
fi
|
|
|
|
# Handle different arch / target variants...
|
|
for PROP in ${MODULE_PROP_KEYS_DICT[${MODULE_NAME}]} ; do
|
|
if ! [[ "$PROP" =~ \.srcs$ ]]; then
|
|
continue
|
|
fi
|
|
SRCS=$(get_prop "$MODULE_NAME" "$PROP")
|
|
DT_NEEDED=$(get_dt_needed "$SRCS")
|
|
SHARED_LIBS_PROP="${PROP%.srcs}.shared_libs"
|
|
VARIANT_SHARED_LIBS="${SHARED_LIBS} $(get_prop "$MODULE_NAME" "$SHARED_LIBS_PROP")"
|
|
if [[ $(unique "$DT_NEEDED") != $(unique "$VARIANT_SHARED_LIBS") ]]; then
|
|
rewrite_prop "$MODULE_NAME" "$SHARED_LIBS_PROP" "$DT_NEEDED"
|
|
fi
|
|
done
|
|
done
|
|
|
|
if [[ -n "$SHOW_DIFF" ]]; then
|
|
diff -u "$ANDROID_BP" "$TEMP_ANDROID_BP" || true
|
|
fi
|
|
|
|
if [[ -n "$EDIT_IN_PLACE" ]]; then
|
|
cp "$TEMP_ANDROID_BP" "$ANDROID_BP"
|
|
fi
|
|
|
|
if [[ -z "${SHOW_DIFF}${EDIT_IN_PLACE}" ]]; then
|
|
cat "$TEMP_ANDROID_BP"
|
|
fi
|