feat: add script to update bundled Orbbec SDK for ARM64 and x86-64 architectures

This commit is contained in:
slz
2026-09-03 15:06:22 +08:00
parent 74abd4c194
commit 478b0622f7
+322
View File
@@ -0,0 +1,322 @@
#!/usr/bin/env bash
set -Eeuo pipefail
readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
readonly PACKAGE_DIR="$(cd -- "${SCRIPT_DIR}/.." && pwd -P)"
readonly SDK_ROOT="${PACKAGE_DIR}/SDK"
readonly ROS_CONFIG_FILE="${PACKAGE_DIR}/config/OrbbecSDKConfig_v2.0.xml"
dry_run=false
work_dir=""
arm64_backup_dir=""
x64_backup_dir=""
config_backup_file=""
usage() {
cat <<EOF
Usage:
$(basename "$0") [--dry-run] <arm64-or-x86_64-sdk-directory>
Replace the bundled Orbbec SDK for both supported ROS package architectures.
The other SDK directory is inferred by swapping the input path suffix between
"_arm64" and "_x86_64".
Only the files used or distributed by orbbec_camera are copied:
- include/libobsensor/
- lib/libOrbbecSDK.so*
- lib/OrbbecSDKConfig-release.cmake
- lib/OrbbecSDKConfig.cmake
- lib/OrbbecSDKVersion.cmake
- lib/extensions/
- lib/OrbbecSDKConfig.xml -> config/OrbbecSDKConfig_v2.0.xml
SDK/licenses/ is left unchanged.
Example:
$(basename "$0") \\
/home/user/Downloads/SDK/OrbbecSDK_v2.10.2_linux_arm64
EOF
}
die() {
echo "Error: $*" >&2
exit 1
}
cleanup_work_dir() {
if [[ -n "${work_dir}" && "${work_dir}" == "${PACKAGE_DIR}"/.sdk-update.* ]]; then
rm -rf -- "${work_dir}"
fi
}
backup_exists() {
[[ -n "${arm64_backup_dir}" && -d "${arm64_backup_dir}" ]] ||
[[ -n "${x64_backup_dir}" && -d "${x64_backup_dir}" ]] ||
[[ -n "${config_backup_file}" && -e "${config_backup_file}" ]]
}
restore_backup() {
backup_exists || return 0
echo "Update failed; restoring the original SDK libraries and runtime configuration..." >&2
if [[ -n "${config_backup_file}" && -e "${config_backup_file}" ]]; then
if [[ -e "${ROS_CONFIG_FILE}" ]]; then
mv -- "${ROS_CONFIG_FILE}" "${work_dir}/OrbbecSDKConfig.failed.xml" || return 1
fi
mv -- "${config_backup_file}" "${ROS_CONFIG_FILE}" || return 1
fi
if [[ -n "${x64_backup_dir}" && -d "${x64_backup_dir}" ]]; then
if [[ -e "${SDK_ROOT}/x64" ]]; then
mv -- "${SDK_ROOT}/x64" "${work_dir}/x64.failed" || return 1
fi
mv -- "${x64_backup_dir}" "${SDK_ROOT}/x64" || return 1
fi
if [[ -n "${arm64_backup_dir}" && -d "${arm64_backup_dir}" ]]; then
if [[ -e "${SDK_ROOT}/arm64" ]]; then
mv -- "${SDK_ROOT}/arm64" "${work_dir}/arm64.failed" || return 1
fi
mv -- "${arm64_backup_dir}" "${SDK_ROOT}/arm64" || return 1
fi
}
on_exit() {
local status=$?
trap - EXIT
if ((status != 0)) && backup_exists; then
if ! restore_backup; then
echo "Error: automatic rollback failed; recovery files remain in ${work_dir}" >&2
exit "${status}"
fi
fi
if ! backup_exists; then
cleanup_work_dir
fi
exit "${status}"
}
trap on_exit EXIT
trap 'exit 130' INT TERM HUP
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
usage
exit 0
fi
if [[ "${1:-}" == "--dry-run" ]]; then
dry_run=true
shift
fi
[[ $# -eq 1 ]] || {
usage >&2
exit 2
}
for command_name in basename cat cmp cp dirname file find mkdir mktemp mv readlink rm wc; do
command -v "${command_name}" >/dev/null 2>&1 || die "required command not found: ${command_name}"
done
[[ -d "${SDK_ROOT}" && ! -L "${SDK_ROOT}" ]] ||
die "bundled SDK must be a real directory: ${SDK_ROOT}"
[[ -d "${SDK_ROOT}/arm64" && ! -L "${SDK_ROOT}/arm64" ]] ||
die "bundled ARM64 SDK must be a real directory: ${SDK_ROOT}/arm64"
[[ -d "${SDK_ROOT}/x64" && ! -L "${SDK_ROOT}/x64" ]] ||
die "bundled x86-64 SDK must be a real directory: ${SDK_ROOT}/x64"
[[ -d "${SDK_ROOT}/licenses" && ! -L "${SDK_ROOT}/licenses" ]] ||
die "bundled SDK licenses must be a real directory: ${SDK_ROOT}/licenses"
[[ -f "${ROS_CONFIG_FILE}" && ! -L "${ROS_CONFIG_FILE}" ]] ||
die "ROS SDK configuration must be a real file: ${ROS_CONFIG_FILE}"
[[ -d "$1" ]] || die "SDK directory not found: $1"
input_source="$(readlink -f -- "$1")"
case "${input_source}" in
*_arm64)
arm64_source="${input_source}"
x64_source="${input_source%_arm64}_x86_64"
;;
*_x86_64)
x64_source="${input_source}"
arm64_source="${input_source%_x86_64}_arm64"
;;
*)
die "SDK directory name must end with _arm64 or _x86_64: ${input_source}"
;;
esac
[[ -d "${arm64_source}" ]] || die "paired ARM64 SDK directory not found: ${arm64_source}"
[[ -d "${x64_source}" ]] || die "paired x86-64 SDK directory not found: ${x64_source}"
case "${arm64_source}" in
"${SDK_ROOT}" | "${SDK_ROOT}"/*) die "the ARM64 source cannot be inside ${SDK_ROOT}" ;;
esac
case "${x64_source}" in
"${SDK_ROOT}" | "${SDK_ROOT}"/*) die "the x86-64 source cannot be inside ${SDK_ROOT}" ;;
esac
core_library_path() {
local source_dir=$1
local core_link="${source_dir}/lib/libOrbbecSDK.so"
[[ -e "${core_link}" ]] || die "missing core SDK library: ${core_link}"
readlink -f -- "${core_link}"
}
sdk_version() {
local core_library
core_library="$(core_library_path "$1")"
local filename=${core_library##*/}
[[ "${filename}" == libOrbbecSDK.so.* ]] ||
die "cannot determine SDK version from core library: ${core_library}"
echo "${filename#libOrbbecSDK.so.}"
}
verify_architecture() {
local source_dir=$1
local expected_arch=$2
local core_library
local description
core_library="$(core_library_path "${source_dir}")"
description="$(file -Lb -- "${core_library}")"
case "${expected_arch}" in
arm64)
[[ "${description}" == *"ARM aarch64"* || "${description}" == *"AArch64"* ]] ||
die "${source_dir} is not an ARM64 SDK (${description})"
;;
x64)
[[ "${description}" == *"x86-64"* ]] ||
die "${source_dir} is not an x86-64 SDK (${description})"
;;
*)
die "internal error: unsupported architecture ${expected_arch}"
;;
esac
}
verify_symlinks_within() {
local root_dir
local link_path
local resolved_path
root_dir="$(readlink -f -- "$1")"
while IFS= read -r -d '' link_path; do
if ! resolved_path="$(readlink -f -- "${link_path}")"; then
die "broken symbolic link: ${link_path}"
fi
case "${resolved_path}" in
"${root_dir}"/*) ;;
*) die "symbolic link points outside ${root_dir}: ${link_path} -> ${resolved_path}" ;;
esac
done < <(find "${root_dir}" -type l -print0)
}
verify_source_layout() {
local source_dir=$1
local expected_arch=$2
local required_path
for required_path in \
include/libobsensor/ObSensor.h \
include/libobsensor/ObSensor.hpp \
lib/OrbbecSDKConfig-release.cmake \
lib/OrbbecSDKConfig.cmake \
lib/OrbbecSDKVersion.cmake \
lib/OrbbecSDKConfig.xml; do
[[ -f "${source_dir}/${required_path}" ]] ||
die "missing required ${expected_arch} SDK file: ${source_dir}/${required_path}"
done
[[ -d "${source_dir}/lib/extensions" ]] ||
die "missing ${expected_arch} SDK extensions directory: ${source_dir}/lib/extensions"
verify_architecture "${source_dir}" "${expected_arch}"
verify_symlinks_within "${source_dir}/lib"
}
copy_architecture() {
local source_dir=$1
local target_arch=$2
local destination_dir=$3
local cmake_file
local copied_core_library=false
mkdir -p -- "${destination_dir}/include" "${destination_dir}/lib"
cp -a -- "${source_dir}/include/libobsensor" "${destination_dir}/include/"
while IFS= read -r -d '' library; do
cp -a -- "${library}" "${destination_dir}/lib/"
copied_core_library=true
done < <(find "${source_dir}/lib" -maxdepth 1 \( -type f -o -type l \) \
-name 'libOrbbecSDK.so*' -print0)
[[ "${copied_core_library}" == true ]] ||
die "no core SDK libraries were copied for ${target_arch}"
for cmake_file in \
OrbbecSDKConfig-release.cmake \
OrbbecSDKConfig.cmake \
OrbbecSDKVersion.cmake; do
cp -a -- "${source_dir}/lib/${cmake_file}" "${destination_dir}/lib/"
done
cp -a -- "${source_dir}/lib/extensions" "${destination_dir}/lib/"
}
verify_source_layout "${arm64_source}" arm64
verify_source_layout "${x64_source}" x64
cmp -s -- "${arm64_source}/lib/OrbbecSDKConfig.xml" \
"${x64_source}/lib/OrbbecSDKConfig.xml" ||
die "ARM64 and x86-64 OrbbecSDKConfig.xml files do not match"
arm64_version="$(sdk_version "${arm64_source}")"
x64_version="$(sdk_version "${x64_source}")"
[[ "${arm64_version}" == "${x64_version}" ]] ||
die "SDK versions do not match: ARM64=${arm64_version}, x86-64=${x64_version}"
work_dir="$(mktemp -d -- "${PACKAGE_DIR}/.sdk-update.XXXXXX")"
staged_sdk="${work_dir}/SDK.new"
staged_config="${work_dir}/OrbbecSDKConfig_v2.0.xml.new"
mkdir -p -- "${staged_sdk}"
copy_architecture "${arm64_source}" arm64 "${staged_sdk}/arm64"
copy_architecture "${x64_source}" x64 "${staged_sdk}/x64"
cp -a -- "${x64_source}/lib/OrbbecSDKConfig.xml" "${staged_config}"
verify_architecture "${staged_sdk}/arm64" arm64
verify_architecture "${staged_sdk}/x64" x64
verify_symlinks_within "${staged_sdk}"
sdk_file_count="$(find "${staged_sdk}" \( -type f -o -type l \) | wc -l)"
file_count=$((sdk_file_count + 1))
echo "Validated Orbbec SDK ${arm64_version} for ARM64 and x86-64."
echo "Staged ${file_count} ROS package files, including ${ROS_CONFIG_FILE}."
if [[ "${dry_run}" == true ]]; then
echo "Dry run complete; SDK libraries, licenses, and runtime configuration were not changed."
exit 0
fi
arm64_backup_dir="${work_dir}/arm64.old"
x64_backup_dir="${work_dir}/x64.old"
config_backup_file="${work_dir}/OrbbecSDKConfig_v2.0.xml.old"
mv -- "${SDK_ROOT}/arm64" "${arm64_backup_dir}"
mv -- "${SDK_ROOT}/x64" "${x64_backup_dir}"
mv -- "${ROS_CONFIG_FILE}" "${config_backup_file}"
mv -- "${staged_sdk}/arm64" "${SDK_ROOT}/arm64"
mv -- "${staged_sdk}/x64" "${SDK_ROOT}/x64"
mv -- "${staged_config}" "${ROS_CONFIG_FILE}"
# The verified SDK and runtime configuration are now active. Mark the
# transaction as committed; the exit handler removes the temporary backups.
arm64_backup_dir=""
x64_backup_dir=""
config_backup_file=""
echo "Updated bundled ARM64, x86-64, and runtime configuration to Orbbec SDK ${arm64_version}."
echo "Left ${SDK_ROOT}/licenses unchanged."