Proyek Zig mendeklarasikan identitas dan dependensinya pada satu berkas manifest bernama build.zig.zon. Berkas ini ditulis dengan sintaks Zig biasa, memuat nama paket, versi, fingerprint, daftar dependensi, dan daftar berkas yang menyertai paket. Topik ini membangun dua paket, yaitu satu pustaka kecil dan satu program yang memakainya sebagai dependensi jalur lokal, lalu menjelaskan peran setiap field pada manifestnya.
Konsep#
Field wajib pertama adalah .name, ditulis sebagai .{ .nama_paket }, dan field kedua adalah .version berformat semver. Field .fingerprint adalah bilangan yang mengidentifikasi paket secara global, dihasilkan toolchain saat paket pertama kali dibuat, dan tidak boleh diubah di kemudian hari karena paket lain memakainya untuk mengenali paket yang sama. Field .paths menetapkan berkas dan direktori mana yang menyertai paket, dan hanya berkas-berkas itu yang ikut dalam perhitungan hash saat paket didistribusikan.
Dependensi dinyatakan pada field .dependencies, dengan dua bentuk sumber. Bentuk .path menunjuk direktori lokal dan cocok untuk pengembangan paket sendiri, sedangkan bentuk .url beserta .hash dipakai untuk paket daring yang diambil dan dicocokkan isinya secara otomatis. Kedua bentuk itu saling meniadakan pada satu entri dependensi, karena .path mengambil isi langsung dari disk tanpa menghitung hash, sedangkan .url mengunduh arsip lalu memverifikasinya terhadap .hash yang tertulis. Pada kedua bentuk, kunci dependensi, misalnya waktu, adalah nama yang dipakai build.zig untuk mengambil modulnya.
Manifest juga menyediakan field .lazy pada entri dependensi. Dependensi yang ditandai lazily hanya diambil bila benar-benar dirujuk oleh build.zig, sehingga proyek dengan banyak pilihan fitur tidak membayar biaya pengambilan untuk dependensi yang tidak dipakai. Field .minimum_zig_version melengkapi manifestnya dengan menandai batas bawah versi toolchain, dan informasi itu dibaca pustaka pengelola dependensi sebelum mencoba mengompilasi.
Diagram berikut merangkum alur pencocokan tersebut, dari manifest proyek menuju paket dependensinya hingga cache global.
Alur pemakaian dependensi berurutan sebagai berikut.
- Pustaka menyatakan identitasnya pada
build.zig.zondan mengekspos modul lewataddModule. - Program menyatakan dependensinya pada field
.dependenciesmanifestnya. build.zigprogram mengambil dependensi denganb.dependencylalu menyambungkan modulnya.- Kode program melakukan
@importatas nama modul tersebut.
Contoh Lengkap#
Paket pustaka bernama waktu memuat satu fungsi penggolong durasi. Manifestnya hanya memuat identitas dan daftar berkas.
// tidak-dijalankan: manifest bukan program, dibaca oleh zig build
.{
.name = .waktu,
.version = "0.1.0",
.fingerprint = 0x21f44624797ecd28,
.paths = .{ "build.zig", "build.zig.zon", "waktu.zig" },
}// tidak-dijalankan: pustaka dipakai melalui graf build paket pemakainya
pub fn durasi(menit: u32) []const u8 {
if (menit < 60) return "singkat";
if (menit < 480) return "sedang";
return "panjang";
}Pustaka mengekspos modulnya pada build.zig dengan b.addModule("waktu", .{ .root_source_file = b.path("waktu.zig") }).
// tidak-dijalankan: berkas build pustaka dieksekusi melalui graf build pemakainya
const std = @import("std");
pub fn build(b: *std.Build) void {
_ = b.addModule("waktu", .{
.root_source_file = b.path("waktu.zig"),
});
}Program pemakainya bernama catat, dan manifestnya menyatakan dependensi jalur lokal. Pada contoh ini paket pustaka ditempatkan pada subdirektori paket-waktu di dalam proyek, sehingga nilai .path menunjuk direktori itu dan seluruh contoh berdiri dalam satu direktori proyek.
// tidak-dijalankan: manifest bukan program, dibaca oleh zig build
.{
.name = .catat,
.version = "0.1.0",
.fingerprint = 0xe35c45a939766c3e,
.dependencies = .{
.waktu = .{ .path = "paket-waktu" },
},
.paths = .{ "build.zig", "build.zig.zon", "utama.zig", "paket-waktu" },
}build.zig program mengambil dependensi dan menyambungkannya sebagai import pada modul akar program.
// tidak-dijalankan: berkas build dieksekusi lewat perintah zig build
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const dep_waktu = b.dependency("waktu", .{});
const mod_waktu = dep_waktu.module("waktu");
const exe = b.addExecutable(.{
.name = "catat",
.root_module = b.createModule(.{
.root_source_file = b.path("utama.zig"),
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "waktu", .module = mod_waktu },
},
}),
});
b.installArtifact(exe);
const run_cmd = b.addRunArtifact(exe);
run_cmd.step.dependOn(b.getInstallStep());
const run_step = b.step("run", "Jalankan catat");
run_step.dependOn(&run_cmd.step);
}Kode program memakai dependensi melalui @import("waktu"), sesuai nama yang terdaftar pada manifest dan build.zig.
// tidak-dijalankan: berkas program dieksekusi lewat perintah zig build run
const std = @import("std");
const waktu = @import("waktu");
pub fn main() void {
std.debug.print("rapat 45 menit: {s}\n", .{waktu.durasi(45)});
std.debug.print("workshop 180 menit: {s}\n", .{waktu.durasi(180)});
}zig build runrapat 45 menit: singkat
workshop 180 menit: sedangAngka 45 berada di bawah enam puluh sehingga digolongkan singkat, sedangkan 180 berada di antara enam puluh dan empat ratus delapan puluh sehingga digolongkan sedang. Fungsi penggolong milik paket lain, dan seluruh penyambungannya dinyatakan pada dua berkas manifest serta satu build.zig. Field .paths pada kedua manifest berperan ketika paket hendak didistribusikan, yaitu menentukan berkas mana yang ikut terhitung pada hash paketnya, dan berkas yang tidak terdaftar di sana tidak ikut berpindah saat paket diambil orang lain. Untuk dependensi .path seperti contoh ini, isi direktori yang dirujuk ikut tunduk pada manifest paket dependensinya, sehingga daftar paths pustaka harus sudah memuat waktu.zig sejak awal.
Perubahan isi paket dependensi langsung terasa pada proyek pemakainya, karena tidak ada versi yang disematkan pada dependensi .path. Pola ini memang disengaja untuk pengembangan bersama, sedangkan dependensi yang stabil memakai bentuk .url beserta .hash sehingga isi yang tertaut tetap sama meskipun sumbernya maju.
Kesalahan umum#
Kesalahan kedua berupa fingerprint yang tidak cocok dengan direktori paket. Pesannya berbunyi error: invalid fingerprint: 0x...; if this is a new or forked package, use this value: 0x..., dan perbaikannya berupa memakai nilai kedua tersebut. Nilai pertama adalah identitas paket lama, sedangkan nilai kedua adalah identitas paket baru pada direktori sekarang, dan memaksakan nilai lama pada fork adalah keputusan yang memengaruhi kepercayaan dependen.
Kesalahan ketiga berupa lupa mendaftarkan dependensi pada build.zig. Manifest yang menyatakan waktu belum cukup, karena @import("waktu") hanya dikenali bila build.zig menyambungkan modulnya melalui b.dependency dan field .imports. Gejalanya berupa pesan error: root module of a Compile step must be created with a known 'target' field ketika modul akar dibuat tanpa target, atau import yang tidak ditemukan saat kompilasi.
Ringkasan#
build.zig.zonmemuat nama, versi, fingerprint, dependensi, dan daftar berkas paket.- Dependensi berbentuk
.pathuntuk direktori lokal dan.urlbeserta.hashuntuk paket daring. - Penyambungan modul berlangsung di
build.zigmelaluib.dependencydan field.importspada modul akar. - Fingerprint dihasilkan sekali oleh toolchain dan divalidasi terhadap nama serta direktori paket.
Referensi#
- Zig 0.17.0 Release Notes, bagian Package Management — ziglang.org — Perilaku manifest, fingerprint, dan dependensi pada 0.17.0.