Home > Software engineering >  What version of rusqlite should I use?
What version of rusqlite should I use?

Time:10-08

I'm learning the rust language. So, I try to build a simple web app using sqlite3. But it gets multiple packages link error.
I saw some solution for this error(ex. this), but they didn't work.
The cause seems to be that the version specification of rusqlite is wrong, but I don't know the correct version specification.
How should I configure the cargo.toml?

Source codes are here.
cargo.toml

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

[dependencies]
actix-web = "4.0.0-beta.3"
actix-rt = "2.2.0"
thiserror = "1.0.29"
askama = "0.10.5"
rusqlite = { version = "0.23", features = ["bundled"] }
r2d2 = "0.8.9"
r2d2-sqlite3 = "0.1.1"

main.rs

use actix_web::{get, App, HttpResponse, HttpServer, ResponseError};
use thiserror::Error;
use askama::Template;
use r2d2::Pool;
use r2d2_sqlite3::SqliteConnectionManager;
use rusqlite::params;

struct TodoEntry {
    id: u32,
    text: String,
}

#[derive(Template)]
#[template(path = "index.html")]
struct IndexTemplate {
    entries: Vec<TodoEntry>,
}

#[derive(Error, Debug)]
enum MyError {
    #[error("Failed to render HTML")]
    AskamaError(#[from] askama::Error),
}

impl ResponseError for MyError {}

#[get("/")]
async fn index() -> Result<HttpResponse, MyError> {

    let mut entries = Vec::new();

    entries.push(TodoEntry {
        id: 1,
        text: "First entry".to_string(),
    });
    entries.push(TodoEntry {
        id: 2,
        text: "Second entry".to_string(),
    });

    let html = IndexTemplate { entries };
    let response_body = html.render()?;

    Ok(HttpResponse::Ok()
        .content_type("text/html")
        .body(response_body))
}

#[actix_rt::main]
async fn main() -> Result<(), actix_web::Error> {

    let manager = SqliteConnectionManager::file("todo.db");
    let pool = Pool::new(manager).expect("Failed to initialize the connection pool.");
    let conn = pool
        .get()
        .expect("Failed to get the connection from the pool.");
    conn.execute(
        "CREATE TABLE IF NOT EXISTS todo (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        text TEXT NOT NULL
        )",
        params![],
    )?
        .expect("Failed to create a table `todo`");

    HttpServer::new(move || App::new().service(index))
        .bind("127.0.0.1:8080")?
        .run()
        .await?;
    Ok(())
}

And the error messages are here.

error: multiple packages link to native library `sqlite3`, but a native library can be linked only once

package `libsqlite3-sys v0.18.0`
    ... which is depended on by `rusqlite v0.23.1`
    ... which is depended on by `todo v0.1.0 (/Users/******/Documents/IntelliJ project/Rust-project/todo)`
links to native library `sqlite3`

package `sqlite3-src v0.2.9`
    ... which is depended on by `sqlite3-sys v0.12.0`
    ... which is depended on by `sqlite3 v0.24.0`
    ... which is depended on by `r2d2-sqlite3 v0.1.1`
    ... which is depended on by `todo v0.1.0 (/Users/*****/Documents/IntelliJ project/Rust-project/todo)`
also links to native library `sqlite3`

CodePudding user response:

You're directly depending on rusqlite and using r2d2-sqlite3 which itself depends on rusqlite.

Since rusqlite binds to a native library as the message indicates you can't have two versions of rusqlite linking to different versions of sqlite3(-sys), so you need to ensure you use the same version of rusqlite as r2d2.

If you're not going to publish on Cargo, the easiest by far is to leave rusqlite's version as a wildcard ("*"), that way the dependency resolver will give you whatever works for r2d2-sqlite3. Otherwise you need to check the version of r2d2-sqlite3 you're using and match it.

Incidentally... r2d2-sqlite3 0.1.1? That seems to be over 4 years old, the current version seems to be 0.18. I'm slightly surprised r2d2 works, though I guess it changes relatively little (0.8.0 was 4 years ago, current is 0.8.9). Though I'm not sure what the utility of r2d2 is for sqlite3, especially for "a simple web app".

  • Related