一、为什么要移植 SQLite3
嵌入式 Linux 开发中经常需要在开发板上存储数据,SQLite3 是首选方案:
| 特点 | 说明 |
|---|---|
| 轻量 | 库文件只有几百 KB,嵌入式友好 |
| 无需配置 | 不需要单独的数据库服务进程 |
| 无需网络 | 本地文件即数据库,断网也能用 |
| 标准 SQL | 语法与 MySQL 基本一致,上手快 |
移植本质:在 ubuntu 上用交叉编译器把 SQLite3 编译成 ARM 平台的动态库,再拷贝到开发板上。
二、移植前提条件
2.1 检查交叉编译工具链
arm-linux-gnueabihf-gcc --version
如果没有安装:
sudo apt install gcc-arm-linux-gnueabi
2.2 下载 SQLite3 源码
官网下载地址:https://www.sqlite.org/download.html
下载 sqlite-autoconf-xxxxx.tar.gz(autoconf 版本,带 configure 脚本)
三、完整移植步骤
第一步:解压源码
tar -xvf sqlite-autoconf-3530000.tar.gz
cd sqlite-autoconf-3530000
第二步:创建编译目录并配置
mkdir build_arm
cd build_arm
CC=arm-linux-gnueabihf-gcc \
../configure \
--host=arm-linux \
--prefix=$(pwd)/install
参数说明:
| 参数 | 说明 |
|---|---|
CC=arm-linux-gnueabihf-gcc | 指定交叉编译器(不同工具链名称不同,按实际修改) |
--host=arm-linux | 告诉 configure 目标平台是 ARM Linux |
--prefix=$(pwd)/install | 编译结果安装到当前目录下的 install 子目录 |
⚠️ 如果工具链名称不同(如
arm-none-linux-gnueabi-gcc),修改 CC= 后面的值即可。
第三步:编译并安装
make
make install
编译完成后,目录结构如下:
build_arm/install/
├── include/
│ └── sqlite3.h ← 头文件(编译应用程序时用)
└── lib/
├── libsqlite3.so.0.8.6 ← 动态库(拷贝到开发板)
├── libsqlite3.so.0 → 软链接
└── libsqlite3.so → 软链接
第四步:将动态库拷贝到开发板
前提:开发板与虚拟机网络正常,NFS 已挂载。
# 如果开发板 /lib 下已有旧版本,先删除
rm /lib/libsqlite3.so*
# 拷贝新库到开发板(/lib 或 /usr/lib 都可以)
cp libsqlite3.so.0.8.6 /lib/
关键经验:开发板库目录
/lib和/usr/lib都会被动态链接器找到,任选其一即可。
第五步:交叉编译测试程序
arm-linux-gnueabihf-gcc test.c -o sqlite_test \
-I ./sqlite-autoconf-3530000/build_arm/install/include \
-L ./sqlite-autoconf-3530000/build_arm/install/lib \
-lsqlite3
编译参数说明:
| 参数 | 说明 |
|---|---|
-I 路径 | 指定头文件 sqlite3.h 的位置 |
-L 路径 | 指定动态库 libsqlite3.so 的位置 |
-lsqlite3 | 链接 sqlite3 库 |
第六步:拷贝到开发板运行
cp sqlite_test /home/linux/nfs/imx6/rootfs/home/root/
在开发板上运行:
./sqlite_test
四、测试代码
#include <stdio.h>
#include <stdlib.h>
#include <sqlite3.h>
// 查询结果回调函数(每返回一行数据调用一次)
static int callback(void *NotUsed, int argc, char **argv, char **azColName)
{
int i;
for (i = 0; i < argc; i++)
{
printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
}
printf("\n");
return 0;
}
int main()
{
sqlite3 *db;
char *errMsg = 0;
int rc;
// 1. 打开数据库(文件不存在则自动创建)
rc = sqlite3_open("test.db", &db);
if (rc)
{
fprintf(stderr, "无法打开数据库: %s\n", sqlite3_errmsg(db));
sqlite3_close(db);
return 1;
}
printf("数据库打开成功\n");
// 2. 创建表
const char *sqlCreate =
"CREATE TABLE IF NOT EXISTS COMPANY("
"ID INT PRIMARY KEY NOT NULL,"
"NAME TEXT NOT NULL,"
"AGE INT NOT NULL);";
rc = sqlite3_exec(db, sqlCreate, NULL, 0, &errMsg);
if (rc != SQLITE_OK)
{
fprintf(stderr, "创建表失败: %s\n", errMsg);
sqlite3_free(errMsg);
sqlite3_close(db);
return 1;
}
printf("表创建成功\n");
// 3. 插入数据
const char *sqlInsert =
"INSERT INTO COMPANY (ID, NAME, AGE) VALUES "
"(1, 'Alice', 25), "
"(2, 'Bob', 30), "
"(3, 'Charlie', 35);";
rc = sqlite3_exec(db, sqlInsert, NULL, 0, &errMsg);
if (rc != SQLITE_OK)
{
fprintf(stderr, "插入数据失败: %s\n", errMsg);
sqlite3_free(errMsg);
}
else
{
printf("数据插入成功\n");
}
// 4. 查询数据(结果通过 callback 打印)
const char *sqlSelect = "SELECT * FROM COMPANY";
rc = sqlite3_exec(db, sqlSelect, callback, 0, &errMsg);
if (rc != SQLITE_OK)
{
fprintf(stderr, "查询失败: %s\n", errMsg);
sqlite3_free(errMsg);
}
// 5. 关闭数据库
sqlite3_close(db);
printf("数据库已关闭\n");
return 0;
}
预期输出:
数据库打开成功
表创建成功
数据插入成功
ID = 1
NAME = Alice
AGE = 25
ID = 2
NAME = Bob
AGE = 30
ID = 3
NAME = Charlie
AGE = 35
数据库已关闭
五、常用 SQLite3 API 速查
| 函数 | 说明 |
|---|---|
sqlite3_open(文件名, &db) | 打开/创建数据库文件 |
sqlite3_close(db) | 关闭数据库 |
sqlite3_exec(db, sql, callback, 0, &errMsg) | 执行 SQL 语句 |
sqlite3_free(errMsg) | 释放错误消息内存 |
sqlite3_errmsg(db) | 获取最后一次错误描述 |
callback 函数参数说明:
static int callback(void *NotUsed, int argc, char **argv, char **azColName)
// 用户数据(可不用) 列数 每列的值 每列的列名
六、完整流程总结
ubuntu 主机
│
├── 1. 下载 SQLite3 源码
├── 2. mkdir build_arm && cd build_arm
├── 3. CC=arm-linux-gnueabihf-gcc ../configure --host=arm-linux --prefix=$(pwd)/install
├── 4. make && make install
├── 5. 交叉编译测试程序
│ arm-linux-gnueabihf-gcc test.c -o sqlite_test -I .../include -L .../lib -lsqlite3
│
│ 通过 NFS
▼
ARM 开发板
├── 6. cp libsqlite3.so.0.8.6 /lib/
├── 7. cp sqlite_test /home/root/
└── 8. ./sqlite_test → 看到输出即移植成功
⚠️ 关键经验总结:
- 交叉编译必须同时指定
-I头文件路径和-L库路径- 开发板上若有旧版动态库,必须先删除再拷贝新的
- 开发板库目录
/lib和/usr/lib均可放置动态库
567

被折叠的 条评论
为什么被折叠?



