[ad_1]
Trong JavaScript và các ngôn ngữ khác, chúng tôi gọi một hành vi đáng ngạc nhiên hoặc không nhất quán “Wat!” (tức là, một “Cái gì!?”). Ví dụ, trong JavaScript, một mảng rỗng cộng với một mảng rỗng tạo ra một chuỗi rỗng, () + () === ""
. Ồ!
Ở thái cực khác, đôi khi ngôn ngữ có hành vi nhất quán đáng ngạc nhiên. Tôi gọi đó là “Wat Not”.
Rust thường nhất quán hơn JavaScript (nhiều). Tuy nhiên, một số định dạng liên quan đến Rust lại gây ngạc nhiên. Cụ thể, bài viết này sẽ xem xét chín điều cần lưu ý và không nên lưu ý trong Cargo.toml
.
Nhớ lại rằng Cargo.toml
là tệp manifest định nghĩa cấu hình và các phụ thuộc của dự án Rust của bạn. Định dạng của nó, TOML (Tom’s Apparent, Minimal Language), biểu diễn các cặp khóa/giá trị lồng nhau và/hoặc các mảng. JSON và YAML là các định dạng tương tự. Giống như YAML, nhưng không giống JSON, Tom đã thiết kế TOML để con người có thể dễ dàng đọc và viết.
Cuộc hành trình của chín wats và wat nots này sẽ không thú vị bằng những điều kỳ quặc của JavaScript (cảm ơn Chúa). Tuy nhiên, nếu bạn đã từng tìm thấy Cargo.toml
‘ định dạng gây nhầm lẫn, tôi hy vọng bài viết này sẽ giúp bạn cảm thấy tốt hơn về bản thân mình. Ngoài ra, và quan trọng nhất, khi bạn học được chín điều nên và không nên làm, tôi hy vọng bạn sẽ có thể viết Cargo.toml
dễ dàng và hiệu quả hơn.
Bài viết này không nói về việc “sửa chữa” Cargo.toml
. Định dạng tệp này tuyệt vời ở mục đích chính của nó: chỉ định cấu hình và các phụ thuộc của dự án Rust. Thay vào đó, bài viết này nói về việc hiểu định dạng và các đặc điểm kỳ quặc của nó.
Bạn có thể biết cách thêm một (dependencies)
phần của bạn Cargo.toml
. Phần này chỉ rõ các phụ thuộc phát hành, ví dụ:
(dependencies)
serde = "1.0"
Tương tự như vậy, bạn có thể chỉ định các phụ thuộc phát triển với (dev-dependencies)
phần và xây dựng các phụ thuộc với một (build-dependencies)
phần.
Bạn cũng có thể cần thiết lập các tùy chọn biên dịch, ví dụ, mức tối ưu hóa và liệu có nên bao gồm thông tin gỡ lỗi hay không. Bạn thực hiện điều đó với hồ sơ các phần để phát hành, phát triển và xây dựng. Bạn có thể đoán tên của ba phần này không? Có phải (profile)
, (dev-profile)
Và (build-profile)
?
Không! Nó là (profile.launch)
, (profile.dev)
Và (profile.construct)
. Cái gì?
Sẽ (dev-profile)
tốt hơn (profile.dev)
? Sẽ (dependencies.dev)
tốt hơn (dev-dependencies)
?
Cá nhân tôi thích những cái tên có dấu chấm. (Trong “Wat Not 9”, chúng ta sẽ thấy sức mạnh của dấu chấm.) Tuy nhiên, tôi chỉ muốn nhớ rằng sự phụ thuộc hoạt động theo một cách và hồ sơ hoạt động theo một cách khác.
Bạn có thể cho rằng dấu chấm là tốt cho hồ sơ, nhưng dấu gạch nối tốt hơn cho các phụ thuộc vì (dev-dependencies)
kế thừa từ (dependencies)
. Nói cách khác, sự phụ thuộc trong (dependencies)
cũng có sẵn trong (dev-dependencies)
. Vậy, điều này có nghĩa là (build-dependencies)
kế thừa từ (dependencies)
?
KHÔNG! (build-dependencies)
không thừa hưởng từ (dependencies)
. Cái gì?
Tôi thấy điều này Cargo.toml
hành vi thuận tiện nhưng gây nhầm lẫn.
Có lẽ bạn biết rằng thay vì thế này:
(dependencies)
serde = { model = "1.0" }
bạn có thể viết thế này:
(dependencies)
serde = "1.0"
Nguyên tắc ở đây là gì? Nói chung, TOML chỉ định một khóa làm khóa mặc định như thế nào?
Bạn không thể! TOML chung không có khóa mặc định. Cái gì cơ?
Cargo TOML thực hiện xử lý đặc biệt trên model
chìa khóa trong (dependencies)
part. Đây là tính năng dành riêng cho Cargo, không phải tính năng TOML chung. Theo tôi biết, Cargo TOML không cung cấp bất kỳ khóa mặc định nào khác.
Với Cargo.toml
(options)
bạn có thể tạo các phiên bản của dự án khác nhau về sự phụ thuộc của chúng. Bản thân những sự phụ thuộc đó có thể khác nhau về các tính năng của chúng, mà chúng tôi sẽ gọi là các tính năng phụ.
Ở đây chúng tôi tạo ra hai phiên bản của dự án của chúng tôi. Phiên bản mặc định phụ thuộc vào getrandom
với các tính năng mặc định. wasm
phiên bản phụ thuộc vào getrandom
với js
tính năng phụ:
(options)
default = ()
wasm = ("getrandom-js")(dependencies)
rand = { model = "0.8" }
getrandom = { model = "0.2", non-compulsory = true }
(dependencies.getrandom-js)
bundle = "getrandom"
model = "0.2"
non-compulsory = true
options = ("js")
Trong ví dụ này, wasm
là một tính năng của dự án của chúng tôi phụ thuộc vào alias phụ thuộc getrandom-rs
đại diện cho phiên bản của getrandom
thùng với js
tính năng phụ.
Vậy, làm sao chúng ta có thể đưa ra cùng một thông số kỹ thuật này trong khi tránh dùng từ ngữ dài dòng? (dependencies.getrandom-js)
phần?
TRONG (options),
thay thế getrandom-js"
với "getrandom/js"
. Chúng ta chỉ có thể viết:
(options)
default = ()
wasm = ("getrandom/js")(dependencies)
rand = { model = "0.8" }
getrandom = { model = "0.2", non-compulsory = true }
Ồ!
Nói chung, trong Cargo.toml
một đặc điểm kỹ thuật như wasm = ("getrandom/js")
có thể liệt kê
- các tính năng khác
- bí danh phụ thuộc
- sự phụ thuộc
- một hoặc nhiều phụ thuộc “gạch chéo” một tính năng phụ
Đây không phải là TOML chuẩn. Thay vào đó, nó là một Cargo.toml
-viết tắt cụ thể.
Phần thưởng: Đoán xem bạn sẽ sử dụng cách viết tắt như thế nào để nói rằng wasm
tính năng nên bao gồm getrandom
với hai tính năng phụ: js
Và test-in-browser
?
Trả lời: Liệt kê sự phụ thuộc hai lần.
wasm = ("getrandom/js","getrandom/test-in-browser")
Chúng ta đã thấy cách chỉ định các phụ thuộc cho bản phát hành, gỡ lỗi và xây dựng.
(dependencies)
#...
(dev-dependencies)
#...
(build-dependencies)
#...
Chúng ta đã thấy cách chỉ định các phụ thuộc cho nhiều tính năng khác nhau:
(options)
default = ()
wasm = ("getrandom/js")
Bạn đoán chúng ta sẽ xác định sự phụ thuộc cho các mục tiêu khác nhau như thế nào (ví dụ phiên bản Linux, Home windows, v.v.)?
Chúng tôi thêm tiền tố (dependences)
với goal.TARGET_EXPRESSION
Ví dụ:
(goal.x86_64-pc-windows-msvc.dependencies)
winapi = { model = "0.3.9", options = ("winuser") }
Theo các quy tắc chung của TOML, điều này có nghĩa là chúng ta cũng có thể nói:
(goal)
x86_64-pc-windows-msvc.dependencies={winapi = { model = "0.3.9", options = ("winuser") }}
Ồ!
Tôi thấy cú pháp tiền tố này lạ, nhưng tôi không thể gợi ý giải pháp thay thế nào tốt hơn. Tuy nhiên, tôi tự hỏi tại sao các tính năng không thể được xử lý theo cùng một cách:
# not allowed
(characteristic.wasm.dependencies)
getrandom = { model = "0.2", options=("js")}
Đây là “Wat Not” đầu tiên của chúng tôi, tức là nó là thứ khiến tôi ngạc nhiên vì độ nhất quán của nó.
Thay vì một mục tiêu cụ thể như x86_64-pc-windows-msvc
thay vào đó bạn có thể sử dụng một cfg
biểu thức trong dấu ngoặc đơn. Ví dụ,
(goal.'cfg(all(home windows, target_arch = "x86_64"))'.dependencies)
Tôi không coi đây là “wat!”. Tôi nghĩ nó tuyệt vời.
Nhớ lại rằng cfg
viết tắt của “cấu hình”, là cơ chế Rust thường được sử dụng để biên dịch mã có điều kiện. Ví dụ, trong essential.rs
chúng ta có thể nói:
if cfg!(target_os = "linux") {
println!("That is Linux!");
}
TRONG Cargo.toml
trong các biểu thức mục tiêu, khá nhiều toàn bộ cfg
ngôn ngữ nhỏ được hỗ trợ.
all(), any(), not()
target_arch
target_feature
target_os
target_family
target_env
target_abi
target_endian
target_pointer_width
target_vendor
target_has_atomic
unix
home windows
Các bộ phận duy nhất của cfg
mini-language không được hỗ trợ là (tôi nghĩ) bạn không thể đặt giá trị bằng --cfg
đối số dòng lệnh. Ngoài ra, một số giá trị cfg như take a look at
không có ý nghĩa gì.
Nhớ lại từ Wat 1 rằng bạn thiết lập các tùy chọn trình biên dịch với (profile.launch)
, (profile.dev)
Và (profile.construct)
. Ví dụ:
(profile.dev)
opt-level = 0
Đoán xem bạn thiết lập tùy chọn trình biên dịch cho một mục tiêu cụ thể như Home windows như thế nào? Có phải thế này không?
(goal.'cfg(home windows)'.profile.dev)
opt-level = 0
Không. Thay vào đó, bạn tạo một tệp mới có tên .cargo/config.toml
và thêm điều này:
(goal.'cfg(home windows)')
rustflags = ("-C", "opt-level=0")
Ồ!
Nói chung, Cargo.toml
chỉ hỗ trợ goal.TARGET_EXPRESSION
như tiền tố của phần phụ thuộc. Bạn không được thêm tiền tố vào phần hồ sơ. Trong .cargo/config.toml
Tuy nhiên, bạn có thể có (goal.TARGET_EXPRESSION)
Các phần. Trong các phần đó, bạn có thể thiết lập các biến môi trường để thiết lập các tùy chọn trình biên dịch.
Cargo.toml
hỗ trợ hai cú pháp cho danh sách:
Ví dụ này sử dụng cả hai:
(bundle)
title = "cargo-wat"
model = "0.1.0"
version = "2021"(dependencies)
rand = { model = "0.8" }
# Inline array 'options'
getrandom = { model = "0.2", options = ("std", "test-in-browser") }
# Desk array 'bin'
((bin))
title = "instance"
path = "src/bin/instance.rs"
((bin))
title = "one other"
path = "src/bin/one other.rs"
Chúng ta có thể thay đổi mảng bảng thành mảng nội tuyến không? Có!
# Inline array 'bin'
bins = (
{ title = "instance", path = "src/bin/instance.rs" },
{ title = "one other", path = "src/bin/one other.rs" },
)(bundle)
title = "cargo-wat"
model = "0.1.0"
version = "2021"
(dependencies)
rand = { model = "0.8" }
# Inline array 'options'
getrandom = { model = "0.2", options = ("std", "test-in-browser") }
Chúng ta có thể thay đổi mảng tính năng nội tuyến thành mảng bảng không?
Không. Mảng nội tuyến của các giá trị đơn giản (ở đây là chuỗi) không thể được biểu diễn dưới dạng mảng bảng. Tuy nhiên, tôi coi đây là một “wat not”, không phải là “wat!” vì đây là một hạn chế của TOML nói chung, không chỉ của Cargo.toml
.
Ngoài ra: Định dạng YAML, giống như định dạng TOML, cung cấp hai cú pháp danh sách. Tuy nhiên, cả hai cú pháp YAML làm việc với các giá trị đơn giản.
Đây là một điển hình Cargo.toml
. Nó kết hợp cú pháp phần, chẳng hạn như (dependences)
với cú pháp nội tuyến như getrandom = {model = "0.2", options = ("std", "test-in-browser")}.
(bundle)
title = "cargo-wat"
model = "0.1.0"
version = "2021"(dependencies)
rand = "0.8"
getrandom = { model = "0.2", options = ("std", "test-in-browser") }
(goal.x86_64-pc-windows-msvc.dependencies)
winapi = { model = "0.3.9", options = ("winuser") }
((bin))
title = "instance"
path = "src/bin/instance.rs"
((bin))
title = "one other"
path = "src/bin/one other.rs"
Chúng ta có thể viết lại nó thành 100% nội tuyến không? Có.
bundle = { title = "cargo-wat", model = "0.1.0", version = "2021" }dependencies = { rand = "0.8", getrandom = { model = "0.2", options = (
"std",
"test-in-browser",
) } }
goal = { 'cfg(target_os = "home windows")'.dependencies = { winapi = { model = "0.3.9", options = (
"winuser",
) } } }
bins = (
{ title = "instance", path = "src/bin/instance.rs" },
{ title = "one other", path = "src/bin/one other.rs" },
)
Chúng ta cũng có thể viết lại với số phần tối đa:
(bundle)
title = "cargo-wat"
model = "0.1.0"
version = "2021"(dependencies.rand)
model = "0.8"
(dependencies.getrandom)
model = "0.2"
options = ("std", "test-in-browser")
(goal.x86_64-pc-windows-msvc.dependencies.winapi)
model = "0.3.9"
options = ("winuser")
((bin))
title = "instance"
path = "src/bin/instance.rs"
((bin))
title = "one other"
path = "src/bin/one other.rs"
Cuối cùng, chúng ta hãy nói về các dấu chấm. Trong TOML, các dấu chấm được sử dụng để phân tách các khóa trong các bảng lồng nhau. Ví dụ, a.b.c
là một chìa khóa c
trong một bảng b
trong một bảng a
. Chúng ta có thể viết lại ví dụ của mình bằng “nhiều chấm” không? Có:
bundle.title = "cargo-wat"
bundle.model = "0.1.0"
bundle.version = "2021"
dependencies.rand = "0.8"
dependencies.getrandom.model = "0.2"
dependencies.getrandom.options = ("std", "test-in-browser")
goal.x86_64-pc-windows-msvc.dependencies.winapi.model = "0.3.9"
goal.x86_64-pc-windows-msvc.dependencies.winapi.options = ("winuser")
bins = (
{ title = "instance", path = "src/bin/instance.rs" },
{ title = "one other", path = "src/bin/one other.rs" },
)
Tôi đánh giá cao tính linh hoạt của TOML đối với các phần, nội tuyến và dấu chấm. Tôi coi tính linh hoạt đó là “cái gì không”. Bạn có thể thấy tất cả các lựa chọn mà nó cung cấp đều gây nhầm lẫn. Tuy nhiên, tôi thích điều đó Cargo.toml
cho phép chúng ta sử dụng toàn bộ sức mạnh của TOML.
Cargo.toml
là một công cụ thiết yếu trong hệ sinh thái Rust, cung cấp sự cân bằng giữa tính đơn giản và tính linh hoạt, phù hợp với cả người mới bắt đầu và các nhà phát triển dày dạn kinh nghiệm. Thông qua chín điều cần lưu ý mà chúng tôi đã khám phá, chúng tôi đã thấy tệp cấu hình này đôi khi có thể gây ngạc nhiên với những đặc điểm riêng của nó nhưng vẫn gây ấn tượng với tính nhất quán và sức mạnh của nó.
Hiểu được những điều kỳ quặc này có thể giúp bạn tránh khỏi những thất vọng tiềm ẩn và cho phép bạn tận dụng Cargo.toml
đầy đủ nhất. Từ việc quản lý các phụ thuộc và hồ sơ đến xử lý các cấu hình và tính năng cụ thể của mục tiêu, những hiểu biết thu được ở đây sẽ giúp bạn viết hiệu quả và hiệu quả hơn Cargo.toml
các tập tin.
Về bản chất, trong khi Cargo.toml
có thể có những đặc điểm riêng, những đặc điểm này thường bắt nguồn từ những lựa chọn thiết kế thực tế ưu tiên chức năng và khả năng đọc. Hãy chấp nhận những đặc điểm kỳ quặc này, và bạn sẽ thấy rằng Cargo.toml
không chỉ đáp ứng nhu cầu của dự án mà còn nâng cao trải nghiệm phát triển Rust của bạn.
Vui lòng theo dõi Carl trên Medium. Tôi viết về lập trình khoa học trong Rust và Python, học máy và thống kê. Tôi có xu hướng viết khoảng một bài viết mỗi tháng.
[ad_2]
Source link