如何指定仅二进制依赖项?

87

我有一个包含二进制文件和库的货箱。库非常轻依赖,而二进制文件则需要更多依赖,比如加载文件或进行范围并行处理。

目前,我的Cargo.toml文件的设置如下:

[dependencies.kdtree]
path = "../kdtree"

[dependencies]
rand="0.3.0"
rustc-serialize = "0.3"
csv = {git = "https://github.com/BurntSushi/rust-csv.git"}
crossbeam = "0.2"
num_cpus = "0.2"

[lib]
name = "conformal"
path = "src/lib.rs"

[[bin]]
name = "ucitest"
path = "src/bin/main.rs"

这个库只需要kdtreerand这两个依赖项。然而,即使你只构建该库,它似乎仍会构建二进制依赖项。我尝试过使用features以及其他技巧,比如[[bin].dependencies][ucitest-dependencies](或在[[bin]]下添加dependencies = []),以此来让它们仅为二进制文件构建,但我找不到方法。

这些依赖项不足以成为问题,但这让我感到困扰。有没有办法缩小依赖范围,使它们仅适用于特定的二进制文件?


6
如果你的库和二进制文件差别很大,也许它们应该有两个独立的 Cargo.toml 文件?你可以把二进制文件放在一个子目录中,在父目录(或已发布的版本)中使用库。 - Shepmaster
从名称上看,您的二进制文件似乎只是一个测试,因此您可以将其放在“tests”下并使用“dev-dependencies”。 - starblue
1
@starblue 这个名字有误导性,因为程序员通常考虑的测试方式并不适用于它,它是用来在UCI测试数据集上运行库的试验并生成学习曲线之类的东西。 - Linear
3个回答

101

有几种方法可以模拟您想要的内容:


1)将二进制文件转换为示例

示例和测试是由dev-dependencies构建的,因此您可以将这些依赖项移入此部分。该库不会依赖它们。

# File structure
conformal/
    Cargo.toml
    src/
        lib.rs
    examples/        # <-- the `ucitest` is
        ucitest.rs   # <-- moved to here
# Cargo.toml

[dependencies]
kdtree = { path = "../kdtree" }
rand = "0.3"

[dev-dependencies]  # <-- move the examples-only dependencies here
serde = "1"
csv = "0.15"
crossbeam = "0.3"
num_cpus = "1"

[lib]
name = "conformal"

[[example]]         # <--- declare the executable
name = "ucitest"    # <--- as an example

运行二进制文件,使用以下命令:

cargo run --example ucitest

2) 带有必需特性的可选依赖项

依赖项可以被标记为可选的,这样依赖于您的conformal库的其他crate就不需要下载它们。

从 Rust 1.17 开始,二进制文件可以声明它们需要打开某些可选功能,从而使那些库“仅对二进制文件需要”必需

# Cargo.toml

[dependencies]
kdtree = { path = "../kdtree" }
rand = "0.3"

serde = { version = "1", optional = true }          # <-- make 
csv = { version = "0.15", optional = true }         # <-- all of
crossbeam = { version = "0.3", optional = true }    # <-- them
num_cpus = { version = "1", optional = true }       # <-- optional

[lib]
name = "conformal"

[features]
build-binary = ["serde", "csv", "crossbeam", "num_cpus"]

[[bin]]         
name = "ucitest"    
required-features = ["build-binary"]     # <--

请注意,在构建二进制文件时需要手动添加--features build-binary

cargo run --features build-binary --bin ucitest

3) 将可执行文件制作为独立的包

当库和可执行文件分别作为独立的包时,您可以自由进行依赖管理。


# File structure
conformal/
    Cargo.toml
    src/
        lib.rs
    ucitest/          # <-- move ucitest
        Cargo.toml    # <-- into its own
        src/          # <-- package.
            main.rs 
# ucitest/Cargo.toml 

[dependencies]
conformal = { version = "0.1", path = "../" }   # <-- explicitly depend on the library
serde = "1"
csv = "0.15"
crossbeam = "0.3"
num_cpus = "1"

3
第二种方法似乎是最佳实践。我们可以轻松地添加一些草稿二进制文件,而不会污染其他内容,并且不会得到冗余的 pkg 清单。 - Fifnmar

31

现今最好的解决方案可能是使用工作区[1, 2]。

目录结构如下:

project-root
├── Cargo.lock
├── Cargo.toml
├── yourlibary
│   ├── Cargo.toml
│   └── src
│       └── lib.rs
├── src
│   └── main.rs
└── target

顶层Cargo.toml文件:

[package]
name = "yourprogram"
version = "0.1.0"
authors = ["You <you@example.com>"]

[workspace]

[dependencies]
yourlibrary = { path = "yourlibrary" }

您的库 Cargo.toml 文件:

[package]
name = "yourlibrary"
version = "0.1.0"
authors = ["You <you@example.com>"]

[dependencies]

Cargo.lock 文件和 target 目录位于项目根目录,并被工作区中的所有组件共享。工作区组件会从具有本地路径的依赖项自动推断,但也可以手动指定。

每个带有其 Cargo.toml 文件的组件仍然可以单独发布到 crates.io。


1
在使用工作区时,yourlibraryyourbinary 可以共享代码吗? - Ian Rehwinkel

13

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接