先搞懂Rust中的项目管理——Crate、bin crate、lib crate、workspace

在Rust中想要完成一个稍微大一点的项目是不容易的,从JavaScript的角度来讲,不同js文件直接的互相导入是非常宽松且容易的,例如import、export等,甚至可以直接导出已经实例化的成员变量,但据我目前所知,在rust中暂时是不行的,rust只能导出一些类型和函数。

因此需要了解Rust中的项目管理、依赖。

1. crate、binary crate、library crate

先介绍几个概念:(粗体为原文,其余为我的理解)

  • crate:一个模块(Module)的树形结构,它形成了库或二进制项目。 我一般不喜欢对专有名词进行翻译,如果硬要翻译,我愿称之为分隔箱,我觉得这个比喻很恰当。
  • package:Cargo 的一个功能,它允许你构建、测试和分享 crate。包(package) 是提供一系列功能的一个或者多个 crate。一个包会包含有一个 Cargo.toml 文件,阐述如何去构建这些 crate。
  • Module 和 use: 模块和use关键字允许你控制作用域和路径的私有性。
  • 总体来说这三者的关系是 package > crate > module

binary crate

一个二进制crate,它的充分必要条件是会有./src/main.rs这个文件,是整个用于执行crate的入口文件。

library crate

一个library crate,在某些翻译中也称为库crate或库,明显是翻译问题,及不准确。library crate的充分必要条件是有./src/lib.rs 这个文件。

规则

对于一个package来说,要满足以下的条件:

  • 一个package最多包含一个library crate。
  • 一个package可以包含任意多的binary crate。
  • 一个package至少要包含一个crate(无论是binary或是library)。

回忆一下,如何新建一个项目,我会使用cargo new 命令,这个命令会在当前目录下自动创建一个binary application,因为会自动生成./src/main.rs

假设我们执行cargo new my-project

在此,我们有了一个只包含 src/main.rs 的包,意味着它只含有一个名为 my-project 的binary crate。如果一个包同时含有 src/main.rssrc/lib.rs,则它有两个 crate:一个binary和一个library的,且名字都与包相同。

除此之外,可以通过将文件放在 src/bin 目录下,一个包可以拥有多个binary crate:每个 src/bin 下的文件都会被编译成一个独立的binary crate。

详细信息见该链接:https://kaisery.github.io/trpl-zh-cn/ch07-01-packages-and-crates.html。

如何处理一个library crate

在我之前学习的http-server项目中,http crate的目录结构是这样的:
先搞懂Rust中的项目管理——Crate、bin crate、lib crate、workspace_第1张图片
可以看出这是一个library crate,在编写httprequest和httpresponse文件的代码时,我发现没有代码提示,后来我才知道,对于这种项目,在lib.rs中通过以下代码可以直接声明其他rs文件中的内容是一个mod:

pub mod httprequest;
pub mod httpresponse;

这也是lib.rs文件中唯一的两行代码,只要先在lib.rs中声明这两行代码,编译器就会任务这两个文件是个根目录形成树形结构的,这时就有代码提示了。

更详细的内容见该链接:https://www.tutorialspoint.com/rust/rust_modules.htm。

如何在没有package的情况下编译一个rs文件为library并为其他文件使用

假设现在目录下只有一个rary.rs文件,使用以下命令编译该文件:

// rary.rs
pub fn public_function() {
    println!("called rary's `public_function()`");
}

fn private_function() {
    println!("called rary's `private_function()`");
}

pub fn indirect_access() {
    print!("called rary's `indirect_access()`, that\n> ");

    private_function();
}
rustc --crate-type=lib rary.rs

就会生成一个library.rilb文件,然后创建一个main.rs文件

// extern crate rary; // May be required for Rust 2015 edition or earlier 在2015版本之前需要这句话

fn main() {
    rary::public_function();

    // Error! `private_function` is private
    //rary::private_function();

    rary::indirect_access();
}

然后用以下命令编译:

rustc main.rs --extern rary=library.rlib --edition=2018

就可以生成 main.exe 文件,然后通过./main 来执行main.exe这个文件。

详细内容见该链接https://doc.rust-lang.org/rust-by-example/crates/lib.html。

2. 工作空间 workspace

在之前的工作前构建了一个包含bin crate 和lib crate 的包。你可能会发现,随着项目开发的深入,lib crate 持续增大,而你希望将其进一步拆分成多个lib crate。对于这种情况,Cargo 提供了一个叫 工作空间(workspaces)的功能,它可以帮助我们管理多个相关的协同开发的pkg。

有了workspace之后,关系是这样的:

workspace > pkg > crate > mod

先创建一个文件夹作为工作空间,然后创建Cargo.toml作为配置文件:

[workspace]
members = ["tcpserver", "tcpclient", "httpserver", "http"]

这四个成员分别作为4个pkg,前两者是测试tcp连接的,后两者是构造http服务器的源文件,这4个包公用一个Cargo.lock。

运行时可以使用命令 cargo run -p 来运行指定的pkg。cargo test同理。

在同一个workspace下,如何在bin crate中引用lib crate

先搞懂Rust中的项目管理——Crate、bin crate、lib crate、workspace_第2张图片
还是刚才的例子,http是一个lib crate,现在创建了一个bin crate名为httpserver。在Cargo.toml的[dependencies]中要表明http crate,即使这个crate是自己写的。

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

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

[dependencies]
http = {path = "../http"}
serde = {version="1.0.136", features=["derive"]}
serde_json = "1.0.79"

详细内容见该链接https://kaisery.github.io/trpl-zh-cn/ch14-03-cargo-workspaces.html。

你可能感兴趣的:(rust,rust)