diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..e472df5 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,186 @@ +name: Release + +# 触发条件:推送形如 vX.Y.Z 的 tag。手动触发也可(用于验证打包流程)。 +on: + push: + tags: [ 'v*' ] + workflow_dispatch: + inputs: + version: + description: '发布版本号(不含 v 前缀,如 2.1.8);仅 workflow_dispatch 时生效' + required: true + default: '0.0.0-test' + +env: + DEBIAN_FRONTEND: noninteractive + TZ: Asia/Shanghai + +jobs: + # 从 tag 或手动输入解析版本号,供后续 job 复用 + meta: + name: Resolve version + runs-on: ubuntu-latest + outputs: + version: ${{ steps.ver.outputs.version }} + steps: + - id: ver + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + VER="${{ github.event.inputs.version }}" + else + VER="${GITHUB_REF_NAME#v}" + fi + echo "version=$VER" >> "$GITHUB_OUTPUT" + echo "解析出的发布版本:$VER" + + # Linux x86_64:runner 原生构建,产物是 build.sh 期望布局的 staging 目录 + package-linux-x86_64: + name: Package linux-x86_64 + needs: meta + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + + - name: 安装构建依赖 + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends build-essential cmake + + - name: CMake 配置 & 安装到 staging + run: | + mkdir -p build + cd build + cmake .. \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_EXAMPLES=OFF \ + -DLINKERHAND_SDK_VERSION=${{ needs.meta.outputs.version }} + cmake --install . --prefix "${GITHUB_WORKSPACE}/stage/linkerhand-cpp-sdk-${{ needs.meta.outputs.version }}-linux-x86_64" + + - name: 打包 tar.gz + run: | + cd stage + PKG="linkerhand-cpp-sdk-${{ needs.meta.outputs.version }}-linux-x86_64" + tar -czf "${PKG}.tar.gz" "$PKG" + sha256sum "${PKG}.tar.gz" | tee "${PKG}.tar.gz.sha256" + + - uses: actions/upload-artifact@v4 + with: + name: linux-x86_64 + path: stage/*.tar.gz* + if-no-files-found: error + + # Linux aarch64:交叉编译。SDK 内部产物已是预编译库,此处只做 install 阶段的拷贝, + # 不需要真正在 aarch64 上运行任何代码,因此不需要 QEMU。 + package-linux-aarch64: + name: Package linux-aarch64 + needs: meta + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + + - name: 安装交叉工具链 + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + build-essential cmake \ + gcc-aarch64-linux-gnu g++-aarch64-linux-gnu + + - name: CMake 配置 & 安装到 staging + run: | + mkdir -p build + cd build + cmake .. \ + -DCMAKE_BUILD_TYPE=Release \ + -DBUILD_EXAMPLES=OFF \ + -DLINKERHAND_SDK_VERSION=${{ needs.meta.outputs.version }} \ + -DCMAKE_SYSTEM_NAME=Linux \ + -DCMAKE_SYSTEM_PROCESSOR=aarch64 \ + -DCMAKE_C_COMPILER=aarch64-linux-gnu-gcc \ + -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ + cmake --install . --prefix "${GITHUB_WORKSPACE}/stage/linkerhand-cpp-sdk-${{ needs.meta.outputs.version }}-linux-aarch64" + + - name: 打包 tar.gz + run: | + cd stage + PKG="linkerhand-cpp-sdk-${{ needs.meta.outputs.version }}-linux-aarch64" + tar -czf "${PKG}.tar.gz" "$PKG" + sha256sum "${PKG}.tar.gz" | tee "${PKG}.tar.gz.sha256" + + - uses: actions/upload-artifact@v4 + with: + name: linux-aarch64 + path: stage/*.tar.gz* + if-no-files-found: error + + # Windows x64:使用 MSVC 布局 + package-windows-x64: + name: Package windows-x64 + needs: meta + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + + - name: CMake 配置 & 安装到 staging + shell: pwsh + run: | + mkdir build | Out-Null + cd build + cmake .. ` + -A x64 ` + -DBUILD_EXAMPLES=OFF ` + -DLINKERHAND_SDK_VERSION=${{ needs.meta.outputs.version }} + $stage = "$env:GITHUB_WORKSPACE\stage\linkerhand-cpp-sdk-${{ needs.meta.outputs.version }}-windows-x64" + cmake --install . --config Release --prefix "$stage" + + - name: 打包 zip + shell: pwsh + run: | + $pkg = "linkerhand-cpp-sdk-${{ needs.meta.outputs.version }}-windows-x64" + Compress-Archive -Path "stage\$pkg" -DestinationPath "stage\$pkg.zip" + (Get-FileHash "stage\$pkg.zip" -Algorithm SHA256).Hash.ToLower() + " $pkg.zip" | Out-File -Encoding ascii "stage\$pkg.zip.sha256" + + - uses: actions/upload-artifact@v4 + with: + name: windows-x64 + path: stage/*.zip* + if-no-files-found: error + + # 汇总产物 → 汇总 SHA256SUMS → 发布 GitHub Release + release: + name: Publish Release + needs: [meta, package-linux-x86_64, package-linux-aarch64, package-windows-x64] + runs-on: ubuntu-22.04 + # workflow_dispatch 只做打包烟测,不真的发 Release + if: github.event_name == 'push' + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + path: dist + merge-multiple: true + + - name: 生成汇总 SHA256SUMS + working-directory: dist + run: | + # 单文件的 .sha256 只是给用户单独校验用的,Release 页仍以 SHA256SUMS 为准 + rm -f SHA256SUMS + for f in *.tar.gz *.zip; do + [ -f "$f" ] || continue + sha256sum "$f" >> SHA256SUMS + done + echo "=== SHA256SUMS ===" + cat SHA256SUMS + + - name: 创建 GitHub Release 并上传产物 + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ github.ref_name }} + name: LinkerHand C++ SDK ${{ needs.meta.outputs.version }} + generate_release_notes: true + files: | + dist/*.tar.gz + dist/*.zip + dist/SHA256SUMS diff --git a/CMakeLists.txt b/CMakeLists.txt index d4b3969..c33a344 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,10 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) +# 发布版本号。默认与 SOVERSION 主版本对齐(2.x);发布 CI 通过 +# -DLINKERHAND_SDK_VERSION= 覆盖,保证 tag / tarball / config 三者一致。 +set(LINKERHAND_SDK_VERSION "2.0.0" CACHE STRING "LinkerHand C++ SDK release version") + option(BUILD_EXAMPLES "Build example applications" ON) option(BUILD_HAND_TEACH_PENDANT "Build hand teach pendant application" OFF) @@ -17,7 +21,7 @@ if(BUILD_HAND_TEACH_PENDANT) endif() message(STATUS "=== LinkerHand C++ SDK Examples ===") -message(STATUS "Version: 2.0.0") +message(STATUS "Version: ${LINKERHAND_SDK_VERSION}") message(STATUS "Build Examples: ${BUILD_EXAMPLES}") message(STATUS "Build Hand Teach Pendant: ${BUILD_HAND_TEACH_PENDANT}") message(STATUS "=====================================") @@ -66,10 +70,15 @@ endif() # CMake config 包:让下游用 find_package(linkerhand-cpp-sdk CONFIG REQUIRED) # 配置文件相对路径自定位(见 cmake/linkerhand-cpp-sdk-config.cmake), -# prefix 改了无需重新生成。 +# prefix 改了无需重新生成。版本文件由模板注入 LINKERHAND_SDK_VERSION。 +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/linkerhand-cpp-sdk-config-version.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/linkerhand-cpp-sdk-config-version.cmake" + @ONLY +) install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/cmake/linkerhand-cpp-sdk-config.cmake" - "${CMAKE_CURRENT_SOURCE_DIR}/cmake/linkerhand-cpp-sdk-config-version.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/linkerhand-cpp-sdk-config-version.cmake" DESTINATION "lib/cmake/linkerhand-cpp-sdk" ) diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..66f92f4 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,156 @@ +# INSTALL — LinkerHand C++ SDK 安装指南 + +本文档面向"只想集成 SDK 到自有工程"的下游用户。若你在参与 SDK 本身的开发或需要从源码构建,请回到 [`README.md`](README.md)。 + +--- + +## 目录 + +- [一条命令安装](#一条命令安装) +- [版本锁定](#版本锁定) +- [离线 / 手动安装](#离线--手动安装) +- [下游 CMake 集成](#下游-cmake-集成) +- [卸载](#卸载) +- [常见问题](#常见问题) + +--- + +## 一条命令安装 + +### Linux(x86_64 / aarch64) + +```bash +# 默认:装最新 Release 到 /usr/local,自动使用 sudo +curl -fsSL https://raw.githubusercontent.com/linker-bot/linkerhand-cpp-sdk/main/scripts/install.sh | bash +``` + +支持的参数(通过 `-s --` 传给脚本): + +| 参数 | 说明 | +|------|------| +| `--version ` | 指定版本(`v2.1.8` 或 `2.1.8` 均可),默认 latest | +| `--prefix ` | 安装前缀,默认 `/usr/local` | +| `--no-sudo` | 不使用 sudo(在 root 容器或已具备写权限时) | +| `--keep-tmp` | 保留临时目录,排查用 | +| `-h`, `--help` | 帮助 | + +```bash +# 举例:装指定版本到用户目录,无需 sudo +curl -fsSL https://raw.githubusercontent.com/linker-bot/linkerhand-cpp-sdk/main/scripts/install.sh \ + | bash -s -- --version v2.1.8 --prefix $HOME/.local --no-sudo +``` + +### Windows x64 + +以 **管理员** 打开 PowerShell: + +```powershell +iwr https://raw.githubusercontent.com/linker-bot/linkerhand-cpp-sdk/main/scripts/install.ps1 -UseBasicParsing | iex +``` + +带参调用需要显式实例化脚本块: + +```powershell +& ([scriptblock]::Create( + (iwr https://raw.githubusercontent.com/linker-bot/linkerhand-cpp-sdk/main/scripts/install.ps1 -UseBasicParsing).Content + )) -Version v2.1.8 -Prefix "C:\SDKs\LinkerHand" -AddToPath +``` + +参数:`-Version`、`-Prefix`、`-AddToPath`(把 `\bin` 加入用户 PATH)。 + +安装脚本会将 `` 追加到用户环境变量 `CMAKE_PREFIX_PATH`,新终端生效。 + +--- + +## 版本锁定 + +生产环境建议**锁定版本**,避免上游发新版后无感知升级: + +```bash +# CI / Dockerfile 中固化版本 +curl -fsSL https://raw.githubusercontent.com/linker-bot/linkerhand-cpp-sdk/main/scripts/install.sh \ + | bash -s -- --version v2.1.8 +``` + +各 Release 的 SHA256 汇总由 `SHA256SUMS` 附件承载,安装脚本会**自动校验**,任何篡改或下载损坏都会终止安装。 + +--- + +## 离线 / 手动安装 + +无法访问 GitHub 的环境(内网、离线机、气隙网络): + +1. 到 [Releases 页面](https://github.com/linker-bot/linkerhand-cpp-sdk/releases) 手动下载对应平台的产物: + - `linkerhand-cpp-sdk--linux-x86_64.tar.gz` + - `linkerhand-cpp-sdk--linux-aarch64.tar.gz` + - `linkerhand-cpp-sdk--windows-x64.zip` + - `SHA256SUMS`(校验用) +2. 校验:`sha256sum -c SHA256SUMS`(Linux)或 `Get-FileHash`(PowerShell) +3. Linux:`tar -xzf ...tar.gz && sudo rsync -a linkerhand-cpp-sdk-*/ /usr/local/ && sudo ldconfig` +4. Windows:解压 zip 后整个目录移动到目标位置,将其加入 `CMAKE_PREFIX_PATH` + +--- + +## 下游 CMake 集成 + +推荐使用 CMake config 包: + +```cmake +cmake_minimum_required(VERSION 3.15) +project(my_app LANGUAGES CXX) + +find_package(linkerhand-cpp-sdk CONFIG REQUIRED) + +add_executable(my_app main.cpp) +target_link_libraries(my_app PRIVATE LinkerHand::linkerhand_cpp_sdk) +``` + +- 装到 `/usr/local` 或 `C:\Program Files\LinkerHand\cpp-sdk`:`find_package` 自动发现 +- 装到自定义前缀:`cmake -DCMAKE_PREFIX_PATH=<前缀> ...` +- Windows 上,安装脚本已把前缀写入用户 `CMAKE_PREFIX_PATH` + +--- + +## 卸载 + +### Linux + +安装到 `/usr/local`(或指定前缀)后,可用以下命令清理: + +```bash +sudo rm -rf /usr/local/include/linkerhand-cpp-sdk \ + /usr/local/lib/linkerhand-cpp-sdk \ + /usr/local/lib/cmake/linkerhand-cpp-sdk \ + /usr/local/lib/liblinkerhand_cpp_sdk.* +sudo ldconfig +``` + +如仍保留了 SDK 源码目录,也可直接用 `sudo ./build.sh -u --prefix /usr/local`。 + +### Windows + +删除 `%ProgramFiles%\LinkerHand\cpp-sdk`(或自定义前缀)目录,并从用户 `CMAKE_PREFIX_PATH` / `Path` 中移除对应条目: + +```powershell +Remove-Item -Recurse -Force "$env:ProgramFiles\LinkerHand\cpp-sdk" +``` + +--- + +## 常见问题 + +**Q: 一键脚本安全吗?我把陌生脚本 pipe 到 bash 心里发怵。** +A: 脚本源码位于本仓库 [`scripts/install.sh`](scripts/install.sh) 与 [`scripts/install.ps1`](scripts/install.ps1),可在执行前先看一遍: +```bash +curl -fsSL https://raw.githubusercontent.com/linker-bot/linkerhand-cpp-sdk/main/scripts/install.sh | less +``` +脚本只做:查询 Release → 下载 tarball 与 `SHA256SUMS` → 校验 → 解压到指定前缀。不下载任何仓库以外的资源。 + +**Q: 我的架构不在支持列表怎么办?** +A: 当前仅提供 Linux x86_64/aarch64 与 Windows x64 预编译产物。其他架构(如 ARMv7、RISC-V)请提 issue,或克隆仓库自行构建。 + +**Q: 安装后 `find_package` 找不到?** +A: 若装到非标准前缀,配置下游时加 `-DCMAKE_PREFIX_PATH=<前缀>`;Windows 需重开终端让环境变量生效。 + +**Q: 想用 apt / conan / vcpkg 装?** +A: 暂未支持。如有需求请提 issue,会评估纳入后续发布通道。 diff --git a/README.md b/README.md index 744bbfd..48227ab 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,37 @@ LinkerHand-CPP-SDK 由灵心巧手(北京)科技有限公司开发,提供 ## 🚀 快速开始 +### 0. 一条命令安装(推荐) + +从 [GitHub Releases](https://github.com/linker-bot/linkerhand-cpp-sdk/releases) 拉取匹配平台的预编译包并自动安装。适合只需要"集成 SDK"的下游用户,不必克隆整个仓库。 + +```bash +# Linux(x86_64 / aarch64,默认装到 /usr/local) +curl -fsSL https://raw.githubusercontent.com/linker-bot/linkerhand-cpp-sdk/main/scripts/install.sh | bash + +# 指定版本 / 自定义前缀 +curl -fsSL https://raw.githubusercontent.com/linker-bot/linkerhand-cpp-sdk/main/scripts/install.sh \ + | bash -s -- --version v2.1.8 --prefix $HOME/.local +``` + +```powershell +# Windows x64(PowerShell 以管理员运行;默认装到 %ProgramFiles%\LinkerHand\cpp-sdk) +iwr https://raw.githubusercontent.com/linker-bot/linkerhand-cpp-sdk/main/scripts/install.ps1 -UseBasicParsing | iex +``` + +安装完成即可在下游工程中: + +```cmake +find_package(linkerhand-cpp-sdk CONFIG REQUIRED) +target_link_libraries(your_app PRIVATE LinkerHand::linkerhand_cpp_sdk) +``` + +详细的版本锁定、离线安装、卸载方式见 [`INSTALL.md`](INSTALL.md)。 + +--- + +如果你需要**从源码构建示例**或参与开发,继续下面的步骤: + ### 1. 克隆仓库 ```bash diff --git a/cmake/linkerhand-cpp-sdk-config-version.cmake b/cmake/linkerhand-cpp-sdk-config-version.cmake.in similarity index 94% rename from cmake/linkerhand-cpp-sdk-config-version.cmake rename to cmake/linkerhand-cpp-sdk-config-version.cmake.in index f8e0817..50d8457 100644 --- a/cmake/linkerhand-cpp-sdk-config-version.cmake +++ b/cmake/linkerhand-cpp-sdk-config-version.cmake.in @@ -1,7 +1,7 @@ # linkerhand-cpp-sdk-config-version.cmake # CMake find_package 版本兼容性检查。语义:同主版本号兼容(SOVERSION=2)。 -set(PACKAGE_VERSION "2.0.0") +set(PACKAGE_VERSION "@LINKERHAND_SDK_VERSION@") if(PACKAGE_FIND_VERSION_RANGE) # 区间形式 find_package(... 2.0...3.0):交给 CMake 自己判断 diff --git a/scripts/install.ps1 b/scripts/install.ps1 new file mode 100644 index 0000000..38e42db --- /dev/null +++ b/scripts/install.ps1 @@ -0,0 +1,109 @@ +<# +.SYNOPSIS + LinkerHand C++ SDK 一条命令安装脚本 (Windows x64) + +.DESCRIPTION + 从 GitHub Release 下载对应版本的 zip,校验 SHA256,解压到 $env:ProgramFiles\LinkerHand\cpp-sdk, + 并把安装前缀加入用户 CMAKE_PREFIX_PATH 环境变量。 + +.EXAMPLE + iwr https://raw.githubusercontent.com/linker-bot/linkerhand-cpp-sdk/main/scripts/install.ps1 -UseBasicParsing | iex + +.EXAMPLE + # 指定版本和路径 + & ([scriptblock]::Create((iwr https://raw.githubusercontent.com/linker-bot/linkerhand-cpp-sdk/main/scripts/install.ps1 -UseBasicParsing).Content)) -Version v2.1.8 -Prefix "C:\SDKs\LinkerHand" +#> + +[CmdletBinding()] +param( + [string]$Version = "", + [string]$Prefix = "$env:ProgramFiles\LinkerHand\cpp-sdk", + [switch]$AddToPath +) + +$ErrorActionPreference = 'Stop' +$Repo = 'linker-bot/linkerhand-cpp-sdk' + +function Info($msg){ Write-Host "[INFO] $msg" -ForegroundColor Green } +function Warn($msg){ Write-Host "[WARN] $msg" -ForegroundColor Yellow } + +# 解析版本 → tag +if ([string]::IsNullOrWhiteSpace($Version)) { + Info "查询最新 Release..." + $latest = Invoke-RestMethod "https://api.github.com/repos/$Repo/releases/latest" + $Tag = $latest.tag_name +} else { + $Tag = if ($Version.StartsWith('v')) { $Version } else { "v$Version" } +} +$Ver = $Tag.TrimStart('v') +Info "目标版本: $Tag" + +$Pkg = "linkerhand-cpp-sdk-$Ver-windows-x64" +$Zip = "$Pkg.zip" +$Base = "https://github.com/$Repo/releases/download/$Tag" + +$Tmp = Join-Path $env:TEMP ("linkerhand-sdk-install-" + [Guid]::NewGuid().ToString('N').Substring(0,8)) +New-Item -ItemType Directory -Path $Tmp -Force | Out-Null +try { + $zipPath = Join-Path $Tmp $Zip + $sumsPath = Join-Path $Tmp 'SHA256SUMS' + + Info "下载: $Base/$Zip" + Invoke-WebRequest -Uri "$Base/$Zip" -OutFile $zipPath -UseBasicParsing + Info "下载: $Base/SHA256SUMS" + Invoke-WebRequest -Uri "$Base/SHA256SUMS" -OutFile $sumsPath -UseBasicParsing + + # 校验 SHA256(SHA256SUMS 格式:" ") + Info "校验 SHA256..." + $expected = (Get-Content $sumsPath | Where-Object { $_ -match "\s+$([regex]::Escape($Zip))\s*$" } | Select-Object -First 1) -split '\s+' | Select-Object -First 1 + if (-not $expected) { throw "SHA256SUMS 中未找到 $Zip 的记录" } + $actual = (Get-FileHash $zipPath -Algorithm SHA256).Hash.ToLower() + if ($actual -ne $expected.ToLower()) { + throw "SHA256 校验失败:expected=$expected actual=$actual" + } + Info "校验通过" + + # 解压 → 拷贝到 Prefix + Info "解压..." + Expand-Archive -Path $zipPath -DestinationPath $Tmp -Force + $stage = Join-Path $Tmp $Pkg + if (-not (Test-Path $stage)) { throw "解压后未找到目录:$stage" } + + Info "安装到 $Prefix ..." + if (Test-Path $Prefix) { + # 只清理 SDK 自身条目,不误伤同前缀下用户其他内容 + Remove-Item -Recurse -Force (Join-Path $Prefix 'include\linkerhand-cpp-sdk') -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force (Join-Path $Prefix 'lib\linkerhand-cpp-sdk') -ErrorAction SilentlyContinue + Remove-Item -Recurse -Force (Join-Path $Prefix 'lib\cmake\linkerhand-cpp-sdk') -ErrorAction SilentlyContinue + } + New-Item -ItemType Directory -Path $Prefix -Force | Out-Null + Copy-Item -Path (Join-Path $stage '*') -Destination $Prefix -Recurse -Force + + # 更新用户环境变量 CMAKE_PREFIX_PATH(追加而非覆盖) + $curCPP = [Environment]::GetEnvironmentVariable('CMAKE_PREFIX_PATH', 'User') + if ([string]::IsNullOrEmpty($curCPP)) { + [Environment]::SetEnvironmentVariable('CMAKE_PREFIX_PATH', $Prefix, 'User') + } elseif (($curCPP -split ';') -notcontains $Prefix) { + [Environment]::SetEnvironmentVariable('CMAKE_PREFIX_PATH', "$curCPP;$Prefix", 'User') + } + + if ($AddToPath) { + $binDir = Join-Path $Prefix 'bin' + if (Test-Path $binDir) { + $curPath = [Environment]::GetEnvironmentVariable('Path', 'User') + if (($curPath -split ';') -notcontains $binDir) { + [Environment]::SetEnvironmentVariable('Path', "$curPath;$binDir", 'User') + Info "已将 $binDir 加入用户 PATH(新终端生效)" + } + } + } + + Info "安装完成 ✓" + Write-Host "" + Write-Host "版本 : $Tag" + Write-Host "前缀 : $Prefix" + Write-Host "CMake : find_package(linkerhand-cpp-sdk CONFIG REQUIRED)" + Write-Host " (已写入用户 CMAKE_PREFIX_PATH,新终端生效)" +} finally { + Remove-Item -Recurse -Force $Tmp -ErrorAction SilentlyContinue +} diff --git a/scripts/install.sh b/scripts/install.sh new file mode 100755 index 0000000..e0ad996 --- /dev/null +++ b/scripts/install.sh @@ -0,0 +1,156 @@ +#!/usr/bin/env bash +# LinkerHand C++ SDK 一条命令安装脚本 (Linux) +# +# 用法: +# curl -fsSL https://raw.githubusercontent.com/linker-bot/linkerhand-cpp-sdk/main/scripts/install.sh | bash +# +# 带参数: +# curl -fsSL .../install.sh | bash -s -- --version v2.1.8 --prefix $HOME/.local +# +# 选项: +# --version 安装指定 Release tag(默认 latest) +# --prefix 安装前缀(默认 /usr/local) +# --no-sudo 不使用 sudo(在 root 容器或已具备写权限时使用) +# --keep-tmp 安装完成后保留临时目录,便于排查 +# -h, --help 帮助 + +set -euo pipefail + +REPO="linker-bot/linkerhand-cpp-sdk" +VERSION="" # 为空表示 latest +PREFIX="/usr/local" +USE_SUDO="auto" # auto|yes|no +KEEP_TMP="false" + +RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' +info(){ echo -e "${GREEN}[INFO]${NC} $*"; } +warn(){ echo -e "${YELLOW}[WARN]${NC} $*"; } +die(){ echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; } + +usage(){ sed -n '2,15p' "$0" | sed 's/^# \{0,1\}//'; exit 0; } + +# 解析参数 +while [[ $# -gt 0 ]]; do + case $1 in + --version) VERSION="$2"; shift 2 ;; + --prefix) PREFIX="$2"; shift 2 ;; + --no-sudo) USE_SUDO="no"; shift ;; + --keep-tmp) KEEP_TMP="true"; shift ;; + -h|--help) usage ;; + *) die "未知参数: $1" ;; + esac +done + +# 依赖检查 +for cmd in curl tar sha256sum uname; do + command -v "$cmd" >/dev/null 2>&1 || die "缺少依赖命令: $cmd" +done + +# 架构映射 +UNAME_M=$(uname -m) +case "$UNAME_M" in + x86_64|amd64) ARCH="linux-x86_64" ;; + aarch64|arm64) ARCH="linux-aarch64" ;; + *) die "不支持的架构: $UNAME_M(当前仅支持 x86_64 / aarch64)" ;; +esac +info "目标架构: $ARCH" + +# sudo 策略 +if [[ "$USE_SUDO" == "auto" ]]; then + if [[ $EUID -eq 0 ]] || [[ -w "$PREFIX" ]]; then + SUDO="" + else + command -v sudo >/dev/null 2>&1 || die "需要写入 $PREFIX 但当前非 root 且未安装 sudo;请指定 --prefix 到可写目录或使用 --no-sudo" + SUDO="sudo" + fi +elif [[ "$USE_SUDO" == "no" ]]; then + SUDO="" +fi + +# 解析版本 → tag +if [[ -z "$VERSION" ]]; then + info "查询最新 Release..." + TAG=$(curl -fsSL "https://api.github.com/repos/${REPO}/releases/latest" \ + | grep -oE '"tag_name":\s*"[^"]+"' | head -1 | sed -E 's/.*"([^"]+)".*/\1/') + [[ -n "$TAG" ]] || die "无法解析最新 Release tag" +else + # 允许用户传 v2.1.8 或 2.1.8 + TAG="$VERSION" + [[ "$TAG" == v* ]] || TAG="v$TAG" +fi +VER="${TAG#v}" +info "目标版本: $TAG" + +PKG="linkerhand-cpp-sdk-${VER}-${ARCH}" +TARBALL="${PKG}.tar.gz" +BASE_URL="https://github.com/${REPO}/releases/download/${TAG}" + +# 临时目录 +TMP=$(mktemp -d -t linkerhand-sdk-install.XXXXXX) +cleanup(){ + if [[ "$KEEP_TMP" == "true" ]]; then + warn "保留临时目录:$TMP" + else + rm -rf "$TMP" + fi +} +trap cleanup EXIT + +cd "$TMP" + +# 下载 tarball 与 SHA256SUMS +info "下载: $BASE_URL/$TARBALL" +curl -fL --retry 3 -o "$TARBALL" "$BASE_URL/$TARBALL" + +info "下载: $BASE_URL/SHA256SUMS" +curl -fL --retry 3 -o SHA256SUMS "$BASE_URL/SHA256SUMS" + +# 校验 +info "校验 SHA256..." +if ! grep -E " ${TARBALL}\$" SHA256SUMS | sha256sum -c - >/dev/null 2>&1; then + die "SHA256 校验失败,请重试或提交 issue" +fi +info "校验通过" + +# 解压 + 交给 build.sh 完成安装(复用符号链接 + ldconfig) +info "解压..." +tar -xzf "$TARBALL" + +# tarball 内的顶层目录名与包名一致 +STAGE_DIR="$TMP/$PKG" +[[ -d "$STAGE_DIR" ]] || die "解压后未找到目录:$STAGE_DIR" + +info "安装到 $PREFIX ..." +# 这里的 tarball 已是"已 install 好的目录树",直接 rsync/cp 到 PREFIX 即可, +# 然后调用 ldconfig 与建立 /usr/local/lib 下的库软链,逻辑与 build.sh 保持一致。 +if command -v rsync >/dev/null 2>&1; then + $SUDO rsync -a "$STAGE_DIR/" "$PREFIX/" +else + $SUDO cp -a "$STAGE_DIR/." "$PREFIX/" +fi + +# 在 $PREFIX/lib 下建库软链,让 -llinkerhand_cpp_sdk 直接可用 +SDK_LIB_DIR="$PREFIX/lib/linkerhand-cpp-sdk/lib" +if [[ -d "$SDK_LIB_DIR" ]]; then + for lib in "$SDK_LIB_DIR"/*.so*; do + [[ -f "$lib" ]] || continue + $SUDO ln -sf "$lib" "$PREFIX/lib/$(basename "$lib")" + done + if command -v ldconfig >/dev/null 2>&1 && [[ "$PREFIX" == "/usr" || "$PREFIX" == "/usr/local" ]]; then + $SUDO ldconfig + fi +fi + +info "安装完成 ✓" +echo +echo "版本 : $TAG" +echo "前缀 : $PREFIX" +echo "头文件 : $PREFIX/include/linkerhand-cpp-sdk/" +echo "CMake : find_package(linkerhand-cpp-sdk CONFIG REQUIRED)" +if [[ "$PREFIX" != "/usr" && "$PREFIX" != "/usr/local" ]]; then + echo + warn "非标准前缀,需在下游 CMake 配置时加:" + echo " cmake -DCMAKE_PREFIX_PATH=$PREFIX ..." + echo "或运行时:" + echo " export LD_LIBRARY_PATH=$PREFIX/lib:\$LD_LIBRARY_PATH" +fi