文盤Rust -- 本地庫引發的依賴衝突

京東雲開發者發表於2023-02-20

作者:京東科技 賈世聞

問題描述

clickhouse 的原生 rust 客戶端目前比較好的有兩個clickhouse-rsclickhouse.rs 。clickhouse-rs 是 tcp 連線;clickhouse.rs 是 http 連線。兩個庫在單獨使用時沒有任何問題,但是,在同一工程同時引用時會報錯。

  • Cargo.toml

    # clickhouse http
    clickhouse = {git = "https://github.com/loyd/clickhouse.rs", features =      ["test-util"]}
    
    # clickhouse tcp
    clickhouse-rs = { git = "https://github.com/suharev7/clickhouse-rs",     features = ["default"]}
    
    
  • 報錯如下

        Blocking waiting for file lock on package cache
        Updating git repository `https://github.com/suharev7/clickhouse-rs`
        Updating crates.io index
    error: failed to select a version for `clickhouse-rs-cityhash-sys`.
        ... required by package `clickhouse-rs v1.0.0-alpha.1 (https://github.  com/suharev7/clickhouse-rs#ecf28f46)`
        ... which satisfies git dependency `clickhouse-rs` of package   `conflict v0.1.0 (/Users/jiashiwen/rustproject/conflict)`
    versions that meet the requirements `^0.1.2` are: 0.1.2
    
    the package `clickhouse-rs-cityhash-sys` links to the native library   `clickhouse-rs`, but it conflicts with a previous package which links to   `clickhouse-rs` as well:
    package `clickhouse-rs-cityhash-sys v0.1.2`
        ... which satisfies dependency `clickhouse-rs-cityhash-sys = "^0.1.2"`   (locked to 0.1.2) of package `clickhouse v0.11.2 (https://github.com/  loyd/clickhouse.rs#4ba31e65)`
        ... which satisfies git dependency `clickhouse` (locked to 0.11.2) of   package `conflict v0.1.0 (/Users/jiashiwen/rustproject/conflict)`
    Only one package in the dependency graph may specify the same links value.   This helps ensure that only one copy of a native library is linked in the   final binary. Try to adjust your dependencies so that only one package   uses the links ='clickhouse-rs-cityhash-sys' value. For more information,   see https://doc.rust-lang.org/cargo/reference/resolver.html#links.
    
    failed to select a version for `clickhouse-rs-cityhash-sys` which could   resolve this conflict
    

錯誤描述還是很清楚的,clickhouse-rs-cityhash-sys 這個庫衝突了。仔細看了一下兩個庫的原始碼,引用 clickhouse-rs-cityhash-sys 庫的方式是不一樣的。clickhouse.rs 是在其Cargo.toml 檔案中使用最普遍的方式引用的

clickhouse-rs-cityhash-sys = { version = "0.1.2", optional = true }

clickhouse-rs 是透過本地方式引用的

[dependencies.clickhouse-rs-cityhash-sys]
path = "clickhouse-rs-cityhash-sys"
version = "0.1.2"

clickhouse-rs-cityhash-sys 的原始碼直接放在 clickhouse-rs 工程目錄下面。

一開始是有個直觀的想法,如果在一個工程中透過workspace 進行隔離,是不是會解決衝突問題呢? 於是,工程的目錄結構從這樣

.
├── Cargo.lock
├── Cargo.toml
└── src
    └── main.rs

改成了這樣

.
├── Cargo.lock
├── Cargo.toml
├── ck_http
│   ├── Cargo.toml
│   └── src
├── ck_tcp
│   ├── Cargo.toml
│   └── src
└── src
    └── main.rs

新建了兩個lib

cargo new ck_http --lib
cargo new ck_tcp --lib

在 workspace 中分別應用 clickhouse-rs 和 clickhouse.rs ,刪除根下 Cargo.toml 檔案中的依賴關係。 很可惜,workspace 沒有解決問題,報錯沒有一點兒差別。

又仔細看了看報錯,裡面有這樣一段

  the package `clickhouse-rs-cityhash-sys` links to the native library   `clickhouse-rs`, but it conflicts with a previous package which links to   `clickhouse-rs`

難道是 clickhouse-rs 這個名字衝突了? 直接把clickhouse-rs原始碼拉下來作為本地庫來試試呢? 於是把 clickhouse-rs clone 到本地,稍稍修改一下ck_tcp workspace 的 Cargo.toml

clickhouse-rs = { path = "../../clickhouse-rs", features = ["default"]}

編譯後衝突依舊存在。 翻翻 clickhouse-rs/clickhouse-rs-cityhash-sys/Cargo.toml,裡面的一個配置很可疑

[package]
...
...
links = "clickhouse-rs"

把 links 隨便改個名字比如:links = "ck-rs-cityhash-sys",編譯就透過了。

錯誤提示中這句話很重要

Only one package in the dependency graph may specify the same links value.

看了一下 links 欄位的含義

The links field
The links field specifies the name of a native library that is being linked to. More information can be found in the links section of the build script guide.

links 指定了本地包被連結的名字,在這裡引起了衝突,改掉本地包中的名字自然解決了衝突,在依賴圖中保證唯一性很重要。

本文涉及程式碼github倉庫,有興趣的同學可以親自試一試

下期見。

相關文章