ARM-10-SQLite3 库移植笔记

一、为什么要移植 SQLite3

嵌入式 Linux 开发中经常需要在开发板上存储数据,SQLite3 是首选方案:

特点 说明
轻量 库文件只有几百 KB,嵌入式友好
无需配置 不需要单独的数据库服务进程
无需网络 本地文件即数据库,断网也能用
标准 SQL 语法与 MySQL 基本一致,上手快

移植本质:在 ubuntu 上用交叉编译器把 SQLite3 编译成 ARM 平台的动态库,再拷贝到开发板上。


二、移植前提条件

2.1 检查交叉编译工具链

bash 复制代码
arm-linux-gnueabihf-gcc --version

如果没有安装:

bash 复制代码
sudo apt install gcc-arm-linux-gnueabi

2.2 下载 SQLite3 源码

官网下载地址:https://www.sqlite.org/download.html

下载 sqlite-autoconf-xxxxx.tar.gz(autoconf 版本,带 configure 脚本)


三、完整移植步骤

第一步:解压源码

bash 复制代码
tar -xvf sqlite-autoconf-3530000.tar.gz
cd sqlite-autoconf-3530000

第二步:创建编译目录并配置

bash 复制代码
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= 后面的值即可。

第三步:编译并安装

bash 复制代码
make
make install

编译完成后,目录结构如下:

复制代码
build_arm/install/
├── include/
│   └── sqlite3.h        ← 头文件(编译应用程序时用)
└── lib/
    ├── libsqlite3.so.0.8.6   ← 动态库(拷贝到开发板)
    ├── libsqlite3.so.0       → 软链接
    └── libsqlite3.so         → 软链接

第四步:将动态库拷贝到开发板

前提:开发板与虚拟机网络正常,NFS 已挂载。

bash 复制代码
# 如果开发板 /lib 下已有旧版本,先删除
rm /lib/libsqlite3.so*

# 拷贝新库到开发板(/lib 或 /usr/lib 都可以)
cp libsqlite3.so.0.8.6 /lib/

关键经验:开发板库目录 /lib 和 /usr/lib 都会被动态链接器找到,任选其一即可。

第五步:交叉编译测试程序

bash 复制代码
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 库

第六步:拷贝到开发板运行

bash 复制代码
cp sqlite_test /home/linux/nfs/imx6/rootfs/home/root/

在开发板上运行:

bash 复制代码
./sqlite_test

四、测试代码

c 复制代码
#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 函数参数说明:

c 复制代码
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 均可放置动态库
相关推荐
Li_RuiQi1 天前
DAgger方法演进_独立学习笔记
笔记·学习·计算机视觉
Li_RuiQi1 天前
DAgger与交互式模仿学习_ACT学习笔记
笔记·学习
He BianGu1 天前
【笔记】C# 中BindingFlags的详细作用
笔记·c#
AI视觉网奇1 天前
turtle 入门教程笔记
笔记
跨知易知识产权1 天前
美国专利确权是什么,和专利诉讼有什么不一样?
笔记
杨逢昌工厂6S管理1 天前
126-杨逢昌6S三环体系:越做越乱的现场熵增机理与基准化治理——一线现场诊断笔记
经验分享·笔记·职场和发展·学习方法
悟道书生1 天前
若依 RBAC 权限控制学习笔记
java·网络·笔记·sql·学习·vue
陈哈哈11111 天前
折腾了半天,总算把 Vim 9.2 装明白了
笔记
陈哈哈11111 天前
折腾了半天,总算把 OpenGL 的开发环境给装明白了
笔记
深圳老胡1 天前
STM32F103 硬件 SPI 与软件 IO 模拟 SPI 最高速度差异详解
笔记·stm32·单片机·代码规范·1024程序员节