Dependensi

Laporkan masalah Lihat sumber Per Malam · 7,3 · 7,2 · 7,1 · 7,0 · 6,5

Target A bergantung pada target B jika B diperlukan oleh A pada build atau serta waktu eksekusinya. Relasi tergantung pada memicu Directed Acyclic Graph (DAG) melebihi target, dan hal ini disebut grafik dependensi.

Dependensi langsung target adalah target lain yang dapat dijangkau oleh jalur dari panjang 1 dalam grafik dependensi. Dependensi transitif target target tersebut yang bergantung pada jalur dengan panjang berapa pun melalui grafik.

Bahkan, dalam konteks build, ada dua grafik dependensi, dependensi sebenarnya dan grafik dependensi yang dideklarasikan. Sebagian besar waktu, kedua grafik tersebut sangat mirip sehingga perbedaan ini tidak perlu dibuat, tetapi sebaiknya diskusikan di bawah ini.

Dependensi aktual dan yang dinyatakan

Target X sebenarnya bergantung pada target Y jika Y harus ada, sudah dibuat, dan terbaru agar X dapat dibuat dengan benar. Dibangun dapat berarti dihasilkan, diproses, dikompilasi, ditautkan, diarsipkan, dikompresi, dieksekusi, atau jenis tugas lain yang secara rutin terjadi selama build.

X target memiliki dependensi yang dideklarasikan pada Y target jika ada dependensi dari X ke Y dalam paket X.

Untuk build yang benar, grafik dependensi aktual A harus berupa subgrafik dari grafik dependensi yang dideklarasikan D. Artinya, setiap pasangan node yang terhubung langsung x --> y di A juga harus terhubung langsung di D Dapat dikatakan bahwa D adalah pendekatan yang berlebihan dari A.

Penulis file BUILD harus secara eksplisit mendeklarasikan semua konversi dependensi untuk setiap aturan ke sistem build, dan tidak lebih.

Kegagalan dalam mengamati prinsip ini menyebabkan perilaku yang tidak ditentukan: build mungkin gagal, tetapi lebih buruk lagi, build mungkin bergantung pada beberapa operasi sebelumnya, atau pada dependensi yang dideklarasikan yang dimiliki target. Bazel memeriksa apakah ada yang hilang dependensi dan kesalahan laporan, tetapi tidak mungkin pemeriksaan ini diselesaikan dalam semua kasus.

Anda tidak perlu (dan tidak boleh) mencoba mencantumkan semua yang diimpor secara tidak langsung, meskipun diperlukan oleh A pada waktu eksekusi.

Selama pembuatan target X, alat build akan memeriksa seluruh seluruh transitif penutupan dependensi X untuk memastikan bahwa perubahan pada target tersebut tercermin dalam hasil akhir, membangun ulang intermediate sesuai kebutuhan.

Sifat transitif dari dependensi menyebabkan kesalahan umum. Terkadang, kode dalam satu file dapat menggunakan kode yang disediakan oleh dependensi tidak langsung — transitif tetapi tidak tepi langsung dalam grafik dependensi yang dideklarasikan. Tidak Langsung dependensi tidak muncul di file BUILD. Karena aturan tersebut tidak tergantung pada penyedia, tidak ada cara untuk melacak perubahan, seperti yang ditunjukkan dalam contoh linimasa berikut:

1. Dependensi yang dideklarasikan cocok dengan dependensi sebenarnya

Pada awalnya, semuanya akan berfungsi. Kode dalam paket a menggunakan kode dalam paket b. Kode dalam paket b menggunakan kode dalam paket c, sehingga a secara transitif bergantung pada c.

a/BUILD b/BUILD
rule(
    name = "a",
    srcs = "a.in",
    deps = "//b:b",
)
      
rule(
    name = "b",
    srcs = "b.in",
    deps = "//c:c",
)
      
a / a.in b / b.in
import b;
b.foo();
    
import c;
function foo() {
  c.bar();
}
      
Mendeklarasikan grafik dependensi dengan panah yang menghubungkan a, b, dan c
Grafik dependensi yang dideklarasikan
Grafik dependensi aktual yang cocok dengan dependensi yang dideklarasikan
                  grafik dengan panah yang menghubungkan a, b, dan c
Grafik dependensi Aktual

Dependensi yang dideklarasikan melebihi perkiraan dependensi yang sebenarnya. Semuanya baik-baik saja.

2. Menambahkan dependensi yang tidak dideklarasikan

Bahaya laten diperkenalkan saat seseorang menambahkan kode ke a yang membuat dependensi aktual langsung pada c, tetapi lupa mendeklarasikannya dalam file build a/BUILD.

a / a.in  
        import b;
        import c;
        b.foo();
        c.garply();
      
 
Mendeklarasikan grafik dependensi dengan panah yang menghubungkan a, b, dan c
Grafik dependensi yang dideklarasikan
Grafik dependensi aktual dengan panah yang menghubungkan a, b, dan c. Channel
                  panah sekarang menghubungkan A ke C. Hal ini tidak sesuai dengan
                  grafik dependensi yang dideklarasikan
Grafik dependensi Aktual

Dependensi yang dideklarasikan tidak lagi melebihi perkiraan dependensi sebenarnya. Hal ini dapat berjalan dengan baik, karena penutupan transitif kedua grafik tersebut sama, tetapi menyamarkan masalah: a memiliki dependensi yang sebenarnya, tetapi tidak dideklarasikan pada c.

3. Perbedaan antara grafik dependensi yang dideklarasikan dan aktual

Bahaya ini terungkap saat seseorang memfaktorkan ulang b sehingga tidak lagi bergantung pada c, secara tidak sengaja melanggar a melalui kesalahan mereka sendiri.

  b/BUILD
 
rule(
    name = "b",
    srcs = "b.in",
    deps = "//d:d",
)
      
  b / b.in
 
      import d;
      function foo() {
        d.baz();
      }
      
Mendeklarasikan grafik dependensi dengan panah yang menghubungkan a dan b.
                  b tidak lagi terhubung ke c, yang 
memutuskan koneksi ke c
Grafik dependensi yang dideklarasikan
Grafik dependensi aktual yang 
menunjukkan koneksi ke b dan c,
                  tapi b tidak lagi terhubung ke c
Grafik dependensi Aktual

Grafik dependensi yang dideklarasikan kini merupakan perkiraan yang lebih rendah dari dependensi, bahkan saat tertutup secara transitif; kemungkinan build tersebut akan gagal.

Masalahnya dapat dihindari dengan memastikan bahwa dependensi aktual dari a ke c yang diperkenalkan di Langkah 2 dideklarasikan dengan benar di file BUILD.

Jenis-jenis dependensi

Sebagian besar aturan build memiliki tiga atribut untuk menentukan dependensi umum: srcs, deps, dan data. Hal ini dijelaskan di bawah. Sebagai detail selengkapnya, lihat Atribut yang umum untuk semua aturan.

Banyak aturan juga memiliki atribut tambahan untuk dependensi, misalnya, compiler atau resources. Hal tersebut diuraikan dalam Buat Ensiklopedia.

srcs dependensi

File yang digunakan secara langsung oleh aturan atau aturan yang menghasilkan file sumber.

deps dependensi

Aturan yang mengarah ke modul yang dikompilasi secara terpisah yang menyediakan file {i>header<i}, simbol, {i>library<i}, data, dll.

data dependensi

Target build mungkin memerlukan beberapa file data agar dapat berjalan dengan benar. File-file data ini bukanlah kode sumber: mereka tidak mempengaruhi cara target dibangun. Sebagai contoh, {i>unit test<i} mungkin membandingkan {i> output<i} fungsi dengan isi file. Jika Anda membuat pengujian unit yang tidak memerlukan file, tetapi Anda memerlukannya saat menjalankan melakukan pengujian. Hal yang sama berlaku untuk alat yang diluncurkan selama eksekusi.

Sistem build menjalankan pengujian di direktori terisolasi tempat hanya file yang dicantumkan sebagai data tersedia. Jadi, jika biner/{i>library<i}/pengujian membutuhkan beberapa file untuk dijalankan, menentukannya (atau aturan build yang berisi keduanya) di data. Contoh:

# I need a config file from a directory named env:
java_binary(
    name = "setenv",
    ...
    data = [":env/default_env.txt"],
)

# I need test data from another directory
sh_test(
    name = "regtest",
    srcs = ["regtest.sh"],
    data = [
        "//data:file1.txt",
        "//data:file2.txt",
        ...
    ],
)

File ini tersedia menggunakan jalur relatif path/to/data/file. Dalam pengujian, Anda dapat merujuk ke file ini dengan menggabungkan jalur dan jalur relatif ruang kerja, misalnya, ${TEST_SRCDIR}/workspace/path/to/data/file.

Menggunakan label untuk mereferensikan direktori

Saat memeriksa file BUILD, Anda mungkin melihat bahwa beberapa label data merujuk ke direktori. Label ini diakhiri dengan /. atau / seperti contoh ini, yang tidak boleh Anda gunakan:

Tidak direkomendasikandata = ["//data/regression:unittest/."]

Tidak direkomendasikandata = ["testdata/."]

Tidak direkomendasikandata = ["testdata/"]

Ini tampak nyaman, terutama untuk pengujian karena memungkinkan pengujian untuk menggunakan semua file data pada direktori tersebut.

Namun, cobalah untuk tidak melakukan hal ini. Untuk memastikan build ulang inkremental yang benar (dan pelaksanaan ulang pengujian) setelah perubahan, sistem build harus mengetahui kumpulan file lengkap yang merupakan input untuk build (atau pengujian). Saat Anda menentukan direktori, sistem pembangunan akan melakukan pembangunan ulang hanya jika direktorinya perubahan (karena penambahan atau penghapusan file), tetapi tidak dapat mendeteksi edit pada setiap file karena perubahan tersebut tidak memengaruhi direktori yang terlampir. Daripada menetapkan direktori sebagai input untuk sistem build, Anda harus menghitung kumpulan file yang ada di dalamnya, baik secara eksplisit maupun menggunakan Fungsi glob(). (Gunakan ** untuk memaksa glob() untuk menjadi rekursif.)

Direkomendasikandata = glob(["testdata/**"])

Sayangnya, ada beberapa skenario di mana label direktori harus digunakan. Misalnya, jika direktori testdata berisi file yang namanya tidak sesuai dengan sintaksis label, kemudian enumerasi file secara eksplisit, atau penggunaan Fungsi glob() menghasilkan label yang tidak valid {i>error<i}. Anda harus menggunakan label direktori dalam kasus ini, tetapi berhati-hatilah terhadap risiko terkait perbaikan yang salah seperti yang dijelaskan di atas.

Jika Anda harus menggunakan label direktori, perhatikan bahwa Anda tidak dapat merujuk ke paket induk dengan jalur ../ relatif; sebagai gantinya, gunakan jalur absolut seperti //data/regression:unittest/..

Aturan eksternal apa pun, seperti tes, yang perlu menggunakan beberapa file harus secara eksplisit mendeklarasikan dependensinya pada semuanya. Anda dapat menggunakan filegroup() untuk mengelompokkan file dalam file BUILD:

filegroup(
        name = 'my_data',
        srcs = glob(['my_unittest_data/*'])
)

Anda kemudian dapat mereferensikan label my_data sebagai dependensi data dalam pengujian.

BANGUN file Visibilitas