From 478b0622f72eca99f76f5985b00738a4e4abb027 Mon Sep 17 00:00:00 2001 From: slz Date: Thu, 3 Sep 2026 09:59:53 +0800 Subject: [PATCH] feat: add script to update bundled Orbbec SDK for ARM64 and x86-64 architectures --- orbbec_camera/scripts/update_bundled_sdk.sh | 322 ++++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100755 orbbec_camera/scripts/update_bundled_sdk.sh diff --git a/orbbec_camera/scripts/update_bundled_sdk.sh b/orbbec_camera/scripts/update_bundled_sdk.sh new file mode 100755 index 00000000..67a1586e --- /dev/null +++ b/orbbec_camera/scripts/update_bundled_sdk.sh @@ -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 < + +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."