交叉编译 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.6、libc.so.6。
注意点 / 避坑
-
一定要显式加
-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无效。
- SONAME 取值规范:
-
去掉写死的主机 RPATH。
sqlite 的 configure 会自动往链接命令塞
-Wl,-rpath,<prefix>/lib,它存在生成的Makefile的变量LDFLAGS.rpath里。用命令行覆盖为空即可:make "LDFLAGS.rpath=" install。主机 RPATH 烧进库后,部署到板子上指向一个不存在的主机路径,容易引起加载混乱。
-
--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(不是绝对路径)。
注意点 / 避坑
-
必须设
-DSQLITECPP_INTERNAL_SQLITE=OFF。SQLiteCpp 默认
ON,会编译它自带的 sqlite3 源码 ,完全不用你单独编的外部 sqlite3。要用外部 sqlite3 共享库,必须关掉它,并保持-DSQLITECPP_FIND_SQLITE=ON(走find_package(SQLite3))。 -
前提:被链接的 sqlite3 必须已经有 SONAME。
这是最容易踩的坑。如果 sqlite3 没有 SONAME,链接器会把"链接时用到的那条路径"烧进 SQLiteCpp 的
NEEDED。由于这里用绝对路径-DSQLite3_LIBRARY=.../libsqlite3.so指定,就会变成主机绝对路径 ,部署到板子上必然找不到库而报cannot open shared object file。→ 所以一定要先按第一部分把 sqlite3 的 SONAME 编对。
-
用
-DSQLite3_LIBRARY/-DSQLite3_INCLUDE_DIR显式指定 sqlite3。这两个变量优先级高于
CMAKE_PREFIX_PATH,能确保链到你想要的那份 sqlite3,避免被 toolchain 里的旧路径或系统库干扰。配置完看 CMake 输出的Found SQLite3: ...确认路径对不对。 -
关闭 CMake 写 RPATH:
-DCMAKE_SKIP_BUILD_RPATH=ON -DCMAKE_SKIP_INSTALL_RPATH=ON。否则 CMake 会把构建/安装路径写进 RPATH,同样是主机路径污染。
三、通用避坑总结(两库共通)
- SONAME 一定要有,且只到主版本号 (
libxxx.so.<major>)------它是运行时依赖解析的依据,不是文件名软链。 - 不要让主机绝对路径进入库 :既不能出现在 RPATH,也不能出现在
NEEDED。 - 依赖库要先编好 SONAME,再编上层库,顺序不能反。
- 验证三件套 (用交叉
readelf -d+ 完整路径):有正确 SONAME、无主机 RPATH、NEEDED全是纯名字。 - 部署到板子时,把真实
.so和版本软链一起拷到板子库目录(或设LD_LIBRARY_PATH)。