build.zig

Menyusun graf build dengan Zig itu sendiri melalui berkas build.zig dan langkah-langkahnya.

Daftar isi

Perintah zig run dan zig build-exe yang dipakai selama jalur ini cukup untuk satu berkas, tetapi proyek nyata memuat banyak berkas sumber, langkah pengujian, dan target keluaran yang beragam. Mengetik ulang seluruh flag pada setiap kompilasi tidak terkelola, dan di sinilah build system Zig mengambil peran. Topik ini membahas berkas build.zig, yaitu program Zig yang mendefinisikan graf build, beserta langkah install dan run yang paling sering dipakai.

Konsep#

Build system Zig tidak memakai bahasa deklaratif terpisah seperti Makefile atau YAML. Graf build didefinisikan oleh fungsi build pada berkas build.zig, dan fungsi itu ditulis dengan bahasa Zig biasa. Sebuah langkah (step) adalah satu pekerjaan pada graf, misalnya mengompilasi satu executable atau menjalankan hasilnya, dan langkah-langkah dihubungkan dengan dependOn untuk menyatakan urutan.

Build runner mengeksekusi graf dengan bantuan cache yang dirancang ke dalam sistemnya. Setiap langkah yang masukannya tidak berubah sejak eksekusi terakhir dianggap selesai tanpa pekerjaan ulang, sehingga perubahan satu berkas sumber hanya memicu ulang langkah yang menyentuh berkas itu. Dampaknya paling terasa pada proyek besar, karena membangun ulang seluruh proyek setelah suntingan kecil tetap berlangsung cepat. Daftar langkah tingkat atas yang tersedia pada suatu proyek juga dapat dilihat dengan zig build --help, dan setiap langkah yang dideklarasikan b.step muncul pada daftar itu bersama deskripsinya.

Tiga panggilan mendasar muncul di hampir setiap build.zig. standardTargetOptions membuka opsi -Dtarget sehingga proyek yang sama dapat dikompilasi silang tanpa menyunting apa pun, sedangkan standardOptimizeOption membuka opsi mode optimasi -Doptimize. installArtifact mendaftarkan hasil kompilasi agar tersalin ke direktori zig-out ketika langkah bawaan dijalankan. Graf build tidak dieksekusi langsung oleh fungsi build, melainkan dibangun terlebih dahulu lalu dijalankan oleh build runner, sehingga langkah-langkah yang saling bebas dapat diparalelkan.

Konsep modul yang dipakai pada contoh juga perlu diperkenalkan sejak sini. b.path mengubah jalur relatif menjadi tipe LazyPath yang dievaluasi build runner saat langkah berjalan, sedangkan createModule menyusun satu unit kompilasi yang memuat berkas akar, target, mode optimasi, dan daftar import-nya. Modul inilah yang nanti dipakai ulang pada topik ekosistem ketika dependensi eksternal disambungkan dengan cara yang sama, sehingga bentuk yang dipelajari sekarang tidak berubah di kemudian hari.

Diagram berikut memperlihatkan graf sederhana yang dibahas pada contoh, yaitu langkah run yang bergantung pada langkah instalasi, dan instalasi yang bergantung pada kompilasi.

Perintah: zig build runlangkah run (tingkat atas)dependOnlangkah installdependOncompile exe salamzig-out/bin/salam
Graf build program salam: langkah run bergantung pada install, dan install bergantung pada langkah kompilasi

Contoh Lengkap#

Contoh memakai proyek dua berkas, yaitu build.zig dan program utamanya salam.zig. Kedua berkas berada di direktori yang sama, dan seluruh perintah dijalankan dari direktori tersebut.

zig build.zig
// 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 exe = b.addExecutable(.{
        .name = "salam",
        .root_module = b.createModule(.{
            .root_source_file = b.path("salam.zig"),
            .target = target,
            .optimize = optimize,
        }),
    });
    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);
    run_cmd.addPassthruArgs();
    run_cmd.step.dependOn(b.getInstallStep());
    const run_step = b.step("run", "Jalankan program salam");
    run_step.dependOn(&run_cmd.step);
}

Fungsi build menerima penunjuk std.Build yang menyediakan seluruh perancahnya. addExecutable membuat langkah kompilasi dengan modul akar salam.zig, installArtifact menghubungkannya ke langkah instalasi, dan b.step("run", ...) mendeklarasikan langkah tingkat atas bernama run yang dapat dipanggil dari baris perintah. Panggilan addPassthruArgs meneruskan argumen setelah tanda -- kepada program yang dijalankan, sebuah cara baku pada 0.17.0 untuk memberi masukan kepada langkah run.

zig salam.zig
const std = @import("std");

pub fn main() void {
    std.debug.print("salam dari graf build\n", .{});
}

Langkah run dijalankan dengan menyebut namanya setelah zig build.

bash
zig build run
text Keluaran
salam dari graf build

Keluaran berasal dari program yang dikompilasi oleh graf, bukan dari build runner-nya. Jalankan zig build tanpa nama langkah, dan hasil instalasi dapat dipanggil langsung dari zig-out.

bash
zig build
zig-out/bin/salam
text Keluaran
salam dari graf build

Perhatikan bahwa zig build yang berhasil tidak mencetak apa pun. Ketiadaan keluaran adalah perilaku normal build system yang sehat, karena setiap langkah yang sudah sesuai cache dilewati tanpa pekerjaan ulang. Hasil biner berada di zig-out/bin/salam, sesuai nama yang diberikan pada addExecutable.

Suntingan pada salam.zig hanya memicu ulang langkah kompilasi dan dua langkah yang bergantung padanya, yaitu instalasi dan run. Definisi graf pada build.zig sendiri dievaluasi ulang setiap pemanggilan, tetapi evaluasi itu murah karena tidak melakukan pekerjaan kompilasi, melainkan hanya menyusun rencana. Pemisahan rencana dan pekerjaan inilah yang menjaga perintah zig build tetap ringan meskipun grafnya tumbuh.

Kesalahan umum#

Kesalahan kedua berupa kode lama yang membaca b.args. Pola if (b.args) |args| berasal dari versi sebelumnya dan menghasilkan error: no field named 'args' in struct 'Build' pada 0.17.0. Perbaikannya adalah run_cmd.addPassthruArgs(), yang meneruskan argumen setelah -- tanpa membaca apa pun secara manual.

Kesalahan ketiga berupa menjalankan zig build di luar direktori proyek. Build runner mencari build.zig dari direktori saat ini ke atas, dan bila tidak ditemukan pesan error: no build.zig file found, in the current directory or any parent directories muncul. Jalankan perintah dari direktori yang memuat build.zig, atau sebut jalurnya dengan opsi --build-file.

Ringkasan#

  • build.zig adalah program Zig yang mendefinisikan graf langkah, bukan berkas konfigurasi pasif.
  • standardTargetOptions dan standardOptimizeOption membuka opsi -Dtarget dan -Doptimize untuk seluruh langkah yang terhubung.
  • installArtifact menghasilkan biner pada zig-out, dan zig build yang berhasil tetap diam.
  • Langkah tingkat atas seperti run dibuat dengan b.step dan dipanggil lewat zig build run.

Kemampuan graf yang sama menjadi fondasi kompilasi silang, yaitu membangun program untuk platform lain tanpa memasang toolchain tambahan.

Referensi#