Xin chào, Cargo!
Cargo là hệ thống build và quản lý gói của Rust. Hầu hết các Rustacean (lập trình viên Rust) đều sử dụng công cụ này để quản lý các dự án Rust vì Cargo xử lý nhiều tác vụ cho bạn, chẳng hạn như xây dựng code, tải xuống các thư viện mà code của bạn phụ thuộc và build các thư viện đó. (Chúng tôi gọi các thư viện mà code của bạn cần là dependencies - các phụ thuộc.)
Các chương trình Rust đơn giản nhất, như cái chúng ta đã viết cho đến giờ, không có bất kỳ phụ thuộc nào. Nếu chúng ta xây dựng dự án "Hello, world!" với Cargo, nó sẽ chỉ sử dụng một phần của Cargo cho việc xử lý build code của bạn. Khi bạn viết các chương trình Rust phức tạp hơn, bạn sẽ thêm các phụ thuộc, và nếu bạn bắt đầu một dự án bằng Cargo, việc thêm phụ thuộc sẽ dễ dàng hơn nhiều.
Vì phần lớn các dự án Rust sử dụng Cargo, phần còn lại của cuốn sách này giả định rằng bạn cũng đang sử dụng Cargo. Cargo được cài đặt cùng với Rust nếu bạn đã sử dụng trình cài đặt chính thức được thảo luận trong phần "Cài đặt". Nếu bạn đã cài đặt Rust thông qua một số phương tiện khác, hãy kiểm tra xem Cargo đã được cài đặt chưa bằng cách nhập lệnh sau vào terminal của bạn:
$ cargo --version
Nếu bạn thấy một số phiên bản, bạn đã có nó! Nếu bạn thấy một lỗi, chẳng hạn như
command not found
, hãy xem tài liệu cho phương thức cài đặt của bạn để xác
định cách cài đặt Cargo riêng biệt.
Tạo một dự án với Cargo
Hãy tạo một dự án mới sử dụng Cargo và xem nó khác với dự án "Hello, world!" ban đầu của chúng ta như thế nào. Quay lại thư mục projects của bạn (hoặc bất cứ nơi nào bạn đã quyết định lưu trữ code). Sau đó, trên bất kỳ hệ điều hành nào, chạy lệnh sau:
$ cargo new hello_cargo
$ cd hello_cargo
Lệnh đầu tiên tạo một thư mục và dự án mới có tên hello_cargo. Chúng ta đã đặt tên dự án là hello_cargo, và Cargo tạo các tệp của nó trong một thư mục cùng tên.
Đi vào thư mục hello_cargo và liệt kê các tệp. Bạn sẽ thấy rằng Cargo đã tạo hai tệp và một thư mục cho chúng ta: một tệp Cargo.toml và một thư mục src với một tệp main.rs bên trong.
Nó cũng đã khởi tạo một repository Git mới cùng với tệp .gitignore. Các tệp
Git sẽ không được tạo nếu bạn chạy cargo new
trong một Git repository đã tồn
tại; bạn có thể ghi đè hành vi này bằng cách sử dụng cargo new --vcs=git
.
Lưu ý: Git là một hệ thống quản lý phiên bản phổ biến. Bạn có thể thay đổi
cargo new
để sử dụng một hệ thống quản lý phiên bản khác hoặc không sử dụng hệ thống quản lý phiên bản nào bằng cách sử dụng cờ--vcs
. Chạycargo new --help
để xem các tùy chọn có sẵn.
Mở Cargo.toml trong trình soạn thảo văn bản bạn chọn. Nó sẽ trông giống với mã trong Listing 1-2.
[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2024"
[dependencies]
Tệp này có định dạng TOML (Tom's Obvious, Minimal Language), đây là định dạng cấu hình của Cargo.
Dòng đầu tiên, [package]
, là một tiêu đề phần cho biết rằng các câu lệnh tiếp
theo đang cấu hình một gói. Khi chúng ta thêm thông tin vào tệp này, chúng ta sẽ
thêm các phần khác.
Ba dòng tiếp theo thiết lập thông tin cấu hình mà Cargo cần để biên dịch chương
trình của bạn: tên, phiên bản và phiên bản của Rust để sử dụng. Chúng ta sẽ nói
về khóa edition
trong Phụ lục E.
Dòng cuối cùng, [dependencies]
, là phần bắt đầu cho bạn liệt kê bất kỳ phụ
thuộc nào của dự án. Trong Rust, các gói mã được gọi là crates. Chúng ta sẽ
không cần bất kỳ crate nào khác cho dự án này, nhưng chúng ta sẽ cần trong dự án
đầu tiên ở Chương 2, vì vậy chúng ta sẽ sử dụng phần phụ thuộc này sau.
Bây giờ mở src/main.rs và xem qua:
Tên tệp: src/main.rs
fn main() { println!("Hello, world!"); }
Cargo đã tạo một chương trình "Hello, world!" cho bạn, giống như cái mà chúng ta đã viết trong Listing 1-1! Cho đến nay, sự khác biệt giữa dự án của chúng ta và dự án mà Cargo đã tạo là Cargo đặt mã trong thư mục src và chúng ta có một tệp cấu hình Cargo.toml ở thư mục cấp cao nhất.
Cargo mong muốn các tệp mã nguồn của bạn nằm trong thư mục src. Thư mục dự án cấp cao nhất chỉ dành cho các tệp README, thông tin giấy phép, các tệp cấu hình và bất kỳ thứ gì khác không liên quan đến mã của bạn. Sử dụng Cargo giúp bạn tổ chức các dự án. Có một vị trí cho mọi thứ, và mọi thứ đều ở đúng vị trí.
Nếu bạn đã bắt đầu một dự án không sử dụng Cargo, như chúng ta đã làm với dự án
"Hello, world!", bạn có thể chuyển đổi nó thành một dự án sử dụng Cargo. Di
chuyển mã dự án vào thư mục src và tạo một tệp Cargo.toml thích hợp. Một
cách dễ dàng để có được tệp Cargo.toml đó là chạy cargo init
, nó sẽ tạo tự
động cho bạn.
Xây dựng và chạy một dự án Cargo
Bây giờ hãy xem có gì khác khi chúng ta xây dựng và chạy chương trình "Hello, world!" với Cargo! Từ thư mục hello_cargo của bạn, xây dựng dự án của bạn bằng cách nhập lệnh sau:
$ cargo build
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs
Lệnh này tạo một tệp thực thi trong target/debug/hello_cargo (hoặc target\debug\hello_cargo.exe trên Windows) thay vì trong thư mục hiện tại của bạn. Vì bản dựng mặc định là bản dựng debug, Cargo đặt tệp nhị phân vào một thư mục có tên debug. Bạn có thể chạy tệp thực thi bằng lệnh này:
$ ./target/debug/hello_cargo # hoặc .\target\debug\hello_cargo.exe trên Windows
Hello, world!
Nếu mọi việc suôn sẻ, Hello, world!
sẽ được in ra terminal. Chạy cargo build
lần đầu tiên cũng khiến Cargo tạo một tệp mới ở cấp cao nhất: Cargo.lock. Tệp
này theo dõi các phiên bản chính xác của các phụ thuộc trong dự án của bạn. Dự
án này không có phụ thuộc, vì vậy tệp hơi thưa thớt. Bạn sẽ không bao giờ cần
thay đổi tệp này theo cách thủ công; Cargo quản lý nội dung của nó cho bạn.
Chúng ta vừa xây dựng một dự án với cargo build
và chạy nó với
./target/debug/hello_cargo
, nhưng chúng ta cũng có thể sử dụng cargo run
để
biên dịch mã và sau đó chạy tệp thực thi kết quả tất cả trong một lệnh:
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/hello_cargo`
Hello, world!
Sử dụng cargo run
thuận tiện hơn việc phải nhớ chạy cargo build
và sau đó sử
dụng toàn bộ đường dẫn đến tệp nhị phân, vì vậy hầu hết các nhà phát triển sử
dụng cargo run
.
Lưu ý rằng lần này chúng ta không thấy đầu ra cho biết rằng Cargo đang biên dịch
hello_cargo
. Cargo nhận ra rằng các tệp không thay đổi, vì vậy nó đã không xây
dựng lại mà chỉ chạy tệp nhị phân. Nếu bạn đã sửa đổi mã nguồn, Cargo sẽ xây
dựng lại dự án trước khi chạy nó, và bạn sẽ thấy đầu ra này:
$ cargo run
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.33 secs
Running `target/debug/hello_cargo`
Hello, world!
Cargo cũng cung cấp một lệnh có tên là cargo check
. Lệnh này nhanh chóng kiểm
tra mã của bạn để đảm bảo nó biên dịch được nhưng không tạo ra tệp thực thi:
$ cargo check
Checking hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
Tại sao bạn lại không muốn có một tệp thực thi? Thông thường, cargo check
nhanh hơn nhiều so với cargo build
vì nó bỏ qua bước tạo ra tệp thực thi. Nếu
bạn đang liên tục kiểm tra công việc của mình trong khi viết mã, việc sử dụng
cargo check
sẽ tăng tốc quá trình cho bạn biết liệu dự án của bạn vẫn đang
biên dịch hay không! Như vậy, nhiều Rustacean chạy cargo check
định kỳ khi họ
viết chương trình của họ để đảm bảo nó biên dịch. Sau đó, họ chạy cargo build
khi họ sẵn sàng sử dụng tệp thực thi.
Hãy tổng kết những gì chúng ta đã học được cho đến nay về Cargo:
- Chúng ta có thể tạo một dự án bằng
cargo new
. - Chúng ta có thể xây dựng một dự án bằng
cargo build
. - Chúng ta có thể xây dựng và chạy một dự án trong một bước bằng
cargo run
. - Chúng ta có thể xây dựng một dự án mà không tạo ra tệp nhị phân để kiểm tra
lỗi bằng
cargo check
. - Thay vì lưu kết quả của bản dựng trong cùng thư mục với mã của chúng ta, Cargo lưu trữ nó trong thư mục target/debug.
Một lợi ích bổ sung của việc sử dụng Cargo là các lệnh giống nhau bất kể bạn đang làm việc trên hệ điều hành nào. Vì vậy, tại thời điểm này, chúng tôi sẽ không cung cấp hướng dẫn cụ thể cho Linux và macOS so với Windows nữa.
Build cho release (phát hành)
Khi dự án của bạn cuối cùng đã sẵn sàng để phát hành, bạn có thể sử dụng
cargo build --release
để biên dịch nó với các tối ưu hóa. Lệnh này sẽ tạo một
tệp thực thi trong target/release thay vì target/debug. Các tối ưu hóa làm
cho mã Rust của bạn chạy nhanh hơn, nhưng việc bật chúng làm kéo dài thời gian
biên dịch chương trình. Đây là lý do tại sao có hai hồ sơ khác nhau: một cho
phát triển, khi bạn muốn xây dựng lại nhanh chóng và thường xuyên, và một khác
để xây dựng chương trình cuối cùng mà bạn sẽ giao cho người dùng, sẽ không được
xây dựng lại nhiều lần và sẽ chạy nhanh nhất có thể. Nếu bạn đang đo hiệu suất
thời gian chạy của mã, hãy chắc chắn chạy cargo build --release
và đo hiệu
suất với tệp thực thi trong target/release.
Cargo như là một quy chuẩn
Với các dự án đơn giản, Cargo không cung cấp nhiều giá trị hơn so với chỉ sử
dụng rustc
, nhưng nó sẽ chứng minh giá trị của nó khi chương trình của bạn trở
nên phức tạp hơn. Khi chương trình phát triển thành nhiều tệp hoặc cần một phụ
thuộc, thì sẽ dễ dàng hơn nhiều để Cargo phối hợp việc xây dựng.
Mặc dù dự án hello_cargo
đơn giản, nhưng bây giờ nó sử dụng nhiều công cụ thực
tế mà bạn sẽ sử dụng trong phần còn lại của sự nghiệp Rust của mình. Trên thực
tế, để làm việc trên bất kỳ dự án hiện có nào, bạn có thể sử dụng các lệnh sau
để kiểm tra mã sử dụng Git, thay đổi thành thư mục của dự án đó, và xây dựng:
$ git clone example.org/someproject
$ cd someproject
$ cargo build
Để biết thêm thông tin về Cargo, hãy xem tài liệu của nó.
Tóm tắt
Bạn đã có một khởi đầu tuyệt vời cho hành trình Rust của mình! Trong chương này, bạn đã học cách:
- Cài đặt phiên bản Rust ổn định mới nhất sử dụng
rustup
- Cập nhật lên phiên bản Rust mới hơn
- Mở tài liệu đã cài đặt cục bộ
- Viết và chạy chương trình "Hello, world!" sử dụng
rustc
trực tiếp - Tạo và chạy một dự án mới sử dụng các quy ước của Cargo
Đây là thời điểm tuyệt vời để xây dựng một chương trình đáng kể hơn để làm quen với việc đọc và viết mã Rust. Vì vậy, trong Chương 2, chúng ta sẽ xây dựng một chương trình trò chơi đoán số. Nếu bạn thích bắt đầu bằng cách học cách các khái niệm lập trình phổ biến hoạt động trong Rust, hãy xem Chương 3 và sau đó quay lại Chương 2.