Vì sao cần package
Một tệp .0 đơn lẻ là đủ khi bạn đang học ngôn ngữ hay thử một đoạn code. Ngay khi dự án lớn hơn một tệp, bạn sẽ muốn có một package: một thư mục với tệp manifest và cấu trúc chuẩn mà bộ công cụ hiểu được.
Lợi ích khi chuyển từ các tệp rời rạc sang package:
- Một nơi chuẩn duy nhất cho tên, phiên bản và siêu dữ liệu của dự án.
- Nhiều điểm khởi đầu (tệp thực thi, thư viện, kiểm thử) trong cùng một cây.
- Cấu trúc dễ đoán: công cụ tìm được mã nguồn mà không cần cấu hình.
- Chạy
zero check/zero buildtrên cả cây, không phải từng tệp một.
Tạo khung một package
Cách nhanh nhất để bắt đầu là zero new:
zero new cli hello
Lệnh này tạo một thư mục hello/ có cấu trúc như sau:
hello/
├── zero.json
└── src/
└── main.0
cli là tên mẫu: nó tạo ra một chương trình dòng lệnh thực thi được. Các mẫu khác (thư viện, chương trình hệ thống) có cùng hình dạng với các giá trị mặc định khác.
cd vào thư mục mới, chạy nó, và bạn đã sẵn sàng:
cd hello
zero run
Khi bạn gọi zero run từ bên trong thư mục package mà không nêu tên tệp, lệnh sẽ lấy target mặc định từ zero.json và chạy target đó.
Tệp manifest zero.json
Manifest của một package cli vừa tạo khung trông như sau:
{
"package": { "name": "hello", "version": "0.1.0" },
"targets": { "cli": { "kind": "exe", "main": "src/main.0" } }
}
Hai khóa cấp cao nhất: package và targets. Khóa đầu xác định package; khóa sau cho trình biên dịch biết cần build gì.
package
"package": {
"name": "hello",
"version": "0.1.0"
}
name: một slug định danh package. Dùng chữ thường và dấu gạch nối.version: chuỗi phiên bản theo semver. Package trước 1.0 dùng0.x.y.
Các trường siêu dữ liệu khác (mô tả, tác giả, giấy phép, repository) có thể được hỗ trợ. Hãy dựa vào tài liệu Zero hiện tại để có schema chính xác, vì manifest vẫn đang thay đổi.
targets
"targets": {
"cli": { "kind": "exe", "main": "src/main.0" }
}
Các khóa (ở đây là cli) là tên target do bạn đặt. Các giá trị mô tả từng target:
kind: target là loại gì.execho tệp thực thi. Các loại khác (thư viện, kiểm thử) có cùng hình dạng.main: tệp mã nguồn khởi đầu, tính tương đối từ thư mục gốc của package.
Bạn có thể khai báo nhiều target trong cùng một package:
{
"package": { "name": "image-tools", "version": "0.1.0" },
"targets": {
"convert": { "kind": "exe", "main": "src/convert.0" },
"resize": { "kind": "exe", "main": "src/resize.0" },
"lib": { "kind": "lib", "main": "src/lib.0" }
}
}
Build một target cụ thể bằng CLI bằng cách nêu tên nó:
zero build convert
zero run resize
Thư mục src/
Mọi tệp mã nguồn nằm trong src/. Trình biên dịch tự động duyệt thư mục này: bạn không cần liệt kê từng tệp trong manifest. Trường main của mỗi target trỏ tới tệp khởi đầu của nó; từ đó trình biên dịch lần theo các import để tìm mọi thứ khác nó cần.
Một package có vài module hỗ trợ có thể trông như sau:
image-tools/
├── zero.json
└── src/
├── convert.0
├── resize.0
├── lib.0
└── internal/
├── decoder.0
└── encoder.0
Thư mục con internal/ chỉ là một quy ước: không có gì trong manifest nêu tên các tệp đó. Các import trong convert.0 truy cập thẳng vào internal/decoder.0.
Build và chạy
Các quy trình thường dùng khi bạn ở trong một package:
zero check # type-check the whole tree
zero run # build and run the default target
zero run convert # build and run a specific named target
zero build # build the default target
zero build --all # build every target (when supported)
zero test # run every test target
CLI đọc zero.json, tự tìm ra việc cần làm và thực hiện. Khi đã làm việc bên trong một package, bạn hiếm khi phải ghi rõ đường dẫn.
Nhiều tệp mã nguồn: một ví dụ nhanh
Giả sử src/main.0 gọi một hàm hỗ trợ từ src/math.0. Tệp hỗ trợ:
pub fun double(value: i32) -> i32 {
return value * 2
}
Tệp khởi đầu:
pub fun main(world: World) -> Void raises {
let result = double(21)
if result == 42 {
check world.out.write("forty two\n")
}
}
Chạy bằng zero run. Trong trường hợp đơn giản này, trình biên dịch tìm ra tham chiếu tới double trong phần còn lại của cây mã nguồn mà không cần khai báo import tường minh nào. Khi package lớn hơn, một hệ thống import tường minh sẽ xử lý phạm vi truy cập giữa các module. Hãy xem tài liệu Zero hiện tại để biết cú pháp import, một trong những phần có khả năng thay đổi cao nhất trước bản 1.0.
Những gì không nên commit vào git
Tệp .gitignore cho một package Zero thường cần:
# build artifacts and caches
/build/
/target/
# editor cruft
.DS_Store
*.swp
Tên chính xác của thư mục chứa kết quả build có thể khác, hãy xem tài liệu bộ công cụ hiện tại, nhưng quy tắc là: mã nguồn thì commit, sản phẩm build thì để ngoài.
Chia sẻ package
Zero đang ở giai đoạn trước 1.0 và kho package (registry) chưa thuộc phần ổn định. Hiện tại, các cách thực tế để chia sẻ một package là:
- Git: clone repository rồi chạy
zero checktrên đó. - Bản sao vendored: chép một bản mã nguồn vào dự án khác.
Khi có registry, các tham chiếu package nhiều khả năng sẽ chuyển vào một trường dependencies trong zero.json. Hãy coi đó là tính năng tương lai, chưa nên viết script dựa vào nó lúc này.
Tiếp theo: kiến thức cơ bản về ngôn ngữ
Giờ bạn đã có mọi thứ cần thiết để tổ chức một dự án Zero thực tế. Chương tiếp theo đi sâu vào chính ngôn ngữ, bắt đầu với binding let: cách đặt tên cho giá trị trong Zero.
Câu hỏi thường gặp
Package trong Zero là gì?
Một package Zero là một thư mục chứa tệp manifest zero.json và thư mục src/ với các tệp mã nguồn .0. Manifest khai báo tên, phiên bản của package và một hoặc nhiều 'target': mỗi target cho trình biên dịch biết cách build một thứ gì đó (tệp thực thi, thư viện, tệp kiểm thử) từ mã nguồn.
Tạo một package Zero mới như thế nào?
Chạy zero new <template> <name>, ví dụ zero new cli hello. CLI sẽ tạo khung một thư mục có zero.json, src/main.0 và các tệp khác mà mẫu bạn chọn cần đến. Từ đó bạn có thể chạy zero check, zero run và zero build bên trong package.
zero.json chứa những gì?
Tối thiểu là một đối tượng package có name và version, cùng một đối tượng targets mô tả từng thứ mà package build ra. Một target có kind (như exe cho tệp thực thi) và main trỏ tới tệp mã nguồn khởi đầu. Bạn có thể khai báo nhiều target trong một manifest.
Một package Zero có thể có nhiều target không?
Có. Một package có thể khai báo bao nhiêu target cũng được, ví dụ một target exe cho CLI, một target lib cho thư viện dùng lại được, và một hoặc nhiều target kiểm thử. Mỗi target có điểm khởi đầu riêng trong src/, và bạn có thể build hoặc chạy từng target riêng lẻ từ CLI.
Trình biên dịch đặt kết quả build ở đâu?
Sản phẩm build nằm trong một thư mục build bên trong package (đường dẫn chính xác do cách triển khai quyết định và có thể thay đổi khi Zero còn ở giai đoạn trước 1.0). Cây mã nguồn trong src/ không bao giờ bị sửa đổi. Hãy coi thư mục build là thứ có thể xóa bỏ: commit nó vào git là một ý tưởng tồi.