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

问题描述 投票:0回答:2

我正在使用

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"]

main.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/[email protected]/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 1292.60.1)
    /usr/lib/libresolv.9.dylib (compatibility version 1.0.0, current version 1.0.0)

未解决的问题

  1. 如何自动导出此环境变量(通过
    toml
    配置 /
    build.rs
    - 仍在研究中)
  2. 开发人员人体工程学 - 如何确保
    sqlcipher
    安装在开发机器上(通过
    build.rs
    /
    toml dev
    等配置)
  3. 确保 CI 将在 SQLCIPHER_STATIC=1 的情况下运行(并安装它)
rust ld static-linking rust-cargo
2个回答
0
投票

目前在 crates.io 上发布的版本似乎

不可能

但是有一个开放的 Pull Request 您可能可以使用它。

首先在本地克隆工作分支,然后将其用作Cargo.toml中的

补丁
,如下所示:

[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
的供应商)是否可以接受,因此在使用它时应谨慎(尤其是在商业产品中)。

编辑

这个问题/评论也相关。


0
投票

自从 @frankenapps 发布了他们的答案后,

rusqlite
在 master 分支中添加了对
sqlcipher
的支持。

在你的

Cargo.toml

[dependencies]
rusqlite = { version = "0.32", features = ["bundled-sqlcipher"] }
use rusqlite::Connection;

const ENCRYPTION_KEY: &str = "your-encryption-key";

fn main() -> Result<(), Box<dyn Error>> {
    let conn = Connection::open(path)?;
    conn.pragma_update(None, "KEY", ENCRYPTION_KEY)?;
    Ok(())
}
© www.soinside.com 2019 - 2024. All rights reserved.