交叉编译 sqlite3 与 SQLiteCpp(RV1126 / armhf)

交叉编译 sqlite3 与 SQLiteCpp(RV1126 / armhf)

工具链前缀:arm-rockchip1240-linux-gnueabihf-

验证统一使用交叉版工具:arm-rockchip1240-linux-gnueabihf-readelf(不要用主机自带的 readelf,虽然多数字段也能读,但统一用交叉版更稳妥、避免混淆)。


一、交叉编译 sqlite3

sqlite-autoconf 是 autoconf/autosetup 工程,用 configure + make

bash 复制代码
cd ~/workspace/3rdparty-keep-32/sqlite-autoconf-3530200
mkdir -p build-rv1126b && cd build-rv1126b

../configure \
  --host=arm-rockchip1240-linux-gnueabihf \
  --prefix=/home/guopf/workspace/3rdparty-keep-32/install/sqlite3_clean \
  CC=arm-rockchip1240-linux-gnueabihf-gcc \
  LDFLAGS="-Wl,-soname,libsqlite3.so.0"

make "LDFLAGS.rpath=" install

验证(完整路径,任意目录均可执行):

bash 复制代码
arm-rockchip1240-linux-gnueabihf-readelf -d \
  /home/guopf/workspace/3rdparty-keep-32/install/sqlite3_clean/lib/libsqlite3.so.0 \
  | grep -E "SONAME|RPATH|RUNPATH|NEEDED"

期望:有 SONAME libsqlite3.so.0,没有 RPATH ,NEEDED 只有 libm.so.6libc.so.6

注意点 / 避坑

  1. 一定要显式加 -Wl,-soname,libsqlite3.so.0

    交叉环境下默认可能不会把 SONAME 烧进二进制。库没有 SONAME 会引发连锁问题:依赖它的库会把"链接时的路径"当成依赖名(见 SQLiteCpp 部分)。

    • SONAME 取值规范:lib<名>.so.<主版本号>,即 libsqlite3.so.0只到主版本号 ,不要用裸 libsqlite3.so,也不要用完整的 libsqlite3.so.3.53.2(否则每次小版本升级都得重链所有使用者)。
    • -Wl,-soname 后面必须跟名字 ,单独写 -Wl,-soname 无效。
  2. 去掉写死的主机 RPATH。

    sqlite 的 configure 会自动往链接命令塞 -Wl,-rpath,<prefix>/lib,它存在生成的 Makefile 的变量 LDFLAGS.rpath 里。用命令行覆盖为空即可:make "LDFLAGS.rpath=" install

    主机 RPATH 烧进库后,部署到板子上指向一个不存在的主机路径,容易引起加载混乱。

  3. --prefix 与构建分离。 用独立的 build-rv1126b 目录构建,--prefix 指向干净的安装目录,便于管理。


二、交叉编译 SQLiteCpp

SQLiteCpp 是 CMake 工程,依赖 sqlite3。它需要一个自己写的 toolchain 文件来指定交叉工具链。

先准备 toolchain 文件:rv1126b-toolchain.cmake

这个文件不是库自带的,是自己写的,放在 SQLiteCpp 源码目录下。内容如下:

cmake 复制代码
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(TOOLCHAIN_PATH /home/guopf/workspace/tool/arm-rockchip1240-linux-gnueabihf/bin)

set(CMAKE_C_COMPILER   ${TOOLCHAIN_PATH}/arm-rockchip1240-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PATH}/arm-rockchip1240-linux-gnueabihf-g++)

# 很关键:避免找错x86库
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

# 指向 sqlite3 的安装目录,供 find_package(SQLite3) 搜索
set(CMAKE_PREFIX_PATH
    /home/guopf/workspace/3rdparty-keep-32/install/sqlite3_clean
)

说明:

  • CMAKE_SYSTEM_NAME/PROCESSOR 告诉 CMake 这是交叉编译。
  • 指定交叉 gcc/g++
  • CMAKE_FIND_ROOT_PATH_MODE_* 防止 find_package 误用主机 x86 的库/头。
  • CMAKE_PREFIX_PATH 指向 sqlite3 的安装目录,供 find_package(SQLite3) 查找。

配置 + 编译 + 安装

bash 复制代码
cd ~/workspace/3rdparty-keep-32/SQLiteCpp
mkdir -p build-rv1126b && cd build-rv1126b

cmake \
  -DCMAKE_TOOLCHAIN_FILE=/home/guopf/workspace/3rdparty-keep-32/SQLiteCpp/rv1126b-toolchain.cmake \
  -DCMAKE_BUILD_TYPE=RelWithDebInfo \
  -DBUILD_SHARED_LIBS=ON \
  -DSQLITECPP_INTERNAL_SQLITE=OFF \
  -DSQLITECPP_FIND_SQLITE=ON \
  -DSQLITECPP_BUILD_TESTS=OFF -DSQLITECPP_BUILD_EXAMPLES=OFF \
  -DSQLITECPP_RUN_CPPLINT=OFF -DSQLITECPP_USE_ASAN=OFF \
  -DSQLite3_INCLUDE_DIR=/home/guopf/workspace/3rdparty-keep-32/install/sqlite3_clean/include \
  -DSQLite3_LIBRARY=/home/guopf/workspace/3rdparty-keep-32/install/sqlite3_clean/lib/libsqlite3.so \
  -DCMAKE_SKIP_BUILD_RPATH=ON -DCMAKE_SKIP_INSTALL_RPATH=ON \
  -DCMAKE_INSTALL_PREFIX=/home/guopf/workspace/3rdparty-keep-32/install/SQLiteCpp_clean \
  ..

cmake --build . -j4
cmake --install .

验证(完整路径,任意目录均可执行):

bash 复制代码
arm-rockchip1240-linux-gnueabihf-readelf -d \
  /home/guopf/workspace/3rdparty-keep-32/install/SQLiteCpp_clean/lib/libSQLiteCpp.so.0 \
  | grep -E "SONAME|RPATH|RUNPATH|NEEDED"

期望:有 SONAME libSQLiteCpp.so.0,没有 RPATH ,且对 sqlite3 的 NEEDED 是纯名字 libsqlite3.so.0(不是绝对路径)。

注意点 / 避坑

  1. 必须设 -DSQLITECPP_INTERNAL_SQLITE=OFF

    SQLiteCpp 默认 ON,会编译它自带的 sqlite3 源码 ,完全不用你单独编的外部 sqlite3。要用外部 sqlite3 共享库,必须关掉它,并保持 -DSQLITECPP_FIND_SQLITE=ON(走 find_package(SQLite3))。

  2. 前提:被链接的 sqlite3 必须已经有 SONAME。

    这是最容易踩的坑。如果 sqlite3 没有 SONAME,链接器会把"链接时用到的那条路径"烧进 SQLiteCpp 的 NEEDED。由于这里用绝对路径 -DSQLite3_LIBRARY=.../libsqlite3.so 指定,就会变成主机绝对路径 ,部署到板子上必然找不到库而报 cannot open shared object file

    → 所以一定要先按第一部分把 sqlite3 的 SONAME 编对。

  3. -DSQLite3_LIBRARY / -DSQLite3_INCLUDE_DIR 显式指定 sqlite3。

    这两个变量优先级高于 CMAKE_PREFIX_PATH,能确保链到你想要的那份 sqlite3,避免被 toolchain 里的旧路径或系统库干扰。配置完看 CMake 输出的 Found SQLite3: ... 确认路径对不对。

  4. 关闭 CMake 写 RPATH:-DCMAKE_SKIP_BUILD_RPATH=ON -DCMAKE_SKIP_INSTALL_RPATH=ON

    否则 CMake 会把构建/安装路径写进 RPATH,同样是主机路径污染。


三、通用避坑总结(两库共通)

  1. SONAME 一定要有,且只到主版本号 (libxxx.so.<major>)------它是运行时依赖解析的依据,不是文件名软链。
  2. 不要让主机绝对路径进入库 :既不能出现在 RPATH,也不能出现在 NEEDED
  3. 依赖库要先编好 SONAME,再编上层库,顺序不能反。
  4. 验证三件套 (用交叉 readelf -d + 完整路径):有正确 SONAME、无主机 RPATH、NEEDED 全是纯名字。
  5. 部署到板子时,把真实 .so 和版本软链一起拷到板子库目录(或设 LD_LIBRARY_PATH)。