使用 sqlcipher 时,如何强制将 rustqlite 构建为静态链接?

问题描述

我正在使用 rustqlite 并尝试通过 Cargo 功能将其配置为使用 sqlcipher。通常情况下,rustqlite 具有 bundled 功能以包含 sqlite 源。更改为 sqlcipher 时,源不再捆绑。

我能够在本地安装 sqlcipher 并编译我的项目(在 Mac 上通过 brew install sqlcipher 安装)。

生成的二进制文件动态链接到本地​​ sqlcipher 安装,因此我无法再将二进制文件分发给客户

如何将库 libsqlcipher.0.dylib 嵌入到二进制文件中?不能期望客户自行安装 sqlcipher

作为参考,查看一个虚拟项目的链接库:

/tmp/try-sqlite/cipher$ otool -L target/release/cipher
target/release/cipher:
    /usr/local/opt/sqlcipher/lib/libsqlcipher.0.dylib (compatibility version 9.0.0,current version 9.6.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0,current version 1292.60.1)
    /usr/lib/libresolv.9.dylib (compatibility version 1.0.0,current version 1.0.0)

我的项目很简单:

Cargo.toml

[package]
name = "cipher"
version = "0.1.0"
edition = "2018"

# See more keys and their deFinitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]


[dependencies.rusqlite]
version = "0.24.2"
features = ["sqlcipher"]

ma​​in.rs

use rusqlite::{params,Connection,Result,NO_ParaMS};
use std::thread::sleep;

#[derive(Debug)]
struct Person {
    id: i32,name: String,data: Option<Vec<u8>>,}

fn main() -> Result<()> {
    let conn = Connection::open("/tmp/enc2.db")?;

    conn.execute("PRAGMA KEY='passphrase'",NO_ParaMS);
    conn.execute(
        "CREATE TABLE IF NOT EXISTS person (
                  id              INTEGER PRIMARY KEY,name            TEXT NOT NULL,data            BLOB
                  )",NO_ParaMS,)?;
    let me = Person {
        id: 0,name: "Steven".to_string(),data: None,};
    conn.execute(
        "INSERT INTO person (name,data) VALUES (?1,?2)",params![me.name,me.data],)?;

    let mut stmt = conn.prepare("SELECT id,name,data FROM person")?;
    let person_iter = stmt.query_map(NO_ParaMS,|row| {
        Ok(Person {
            id: row.get(0)?,name: row.get(1)?,data: row.get(2)?,})
    })?;

    for person in person_iter {
        println!("Found person {:?}",person.unwrap());
    }
    Ok(())
}

编辑

通过导出,我有一个静态链接的部分解决方案(尚未经过稳健测试) sqlCIPHER_STATIC=1

otool -L /private/tmp/try-sqlite/cypher/target/debug/cypher
/private/tmp/try-sqlite/cypher/target/debug/cypher:
    /usr/lib/libz.1.dylib (compatibility version 1.0.0,current version 1.2.11)
    /usr/local/opt/openssl@1.1/lib/libcrypto.1.1.dylib (compatibility version 1.1.0,current version 1.1.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0,current version 1.0.0)

解决的问题

  1. 如何自动导出这个环境变量(通过 toml config / build.rs - 仍在努力)
  2. 开发人员人体工程学 - 如何确保 sqlcipher 安装在开发机器上(通过 build.rs / toml dev 等配置)
  3. 确保 CI 以 sqlCIPHER_STATIC=1 运行(并安装)

解决方法

目前似乎是 not possible,版本发布于 crates.io

但是有一个开放的 Pull Request 可以用于此目的。

首先在本地克隆 working branch,然后将其用作 Cargo.toml 中的 patch,如下所示:

[dependencies]
rusqlite = { version = "0.24.2",features = ["bundled-sqlcipher"] }

[patch.crates-io]
rusqlite = { path = "../path/to/your_patch" }

请注意,我没有对此进行测试,因为该功能仅存在于补丁中,因此您可能需要像这样包含功能分支:

[dependencies]
rusqlite = { path = "../path/to/your_patch",features = ["bundled-sqlcipher"] }

警告:正如 PR 中所述,目前尚不清楚 zetetic(sqlcipher 的供应商)是否可以接受,因此您在使用它时应谨慎(尤其是在商业产品中)。

编辑

这个 Issue / Comment 也是相关的。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...