Pemformatan file BUILD
mengikuti pendekatan yang sama seperti Go, yang standarnya menangani sebagian besar masalah pemformatan.
Buildifier adalah alat yang mengurai dan
menampilkan kode sumber dalam gaya standar. Oleh karena itu, setiap file BUILD
diformat dengan cara otomatis yang sama, sehingga pemformatan menjadi bukan masalah selama peninjauan kode. Library ini juga memudahkan alat untuk memahami, mengedit, dan
membuat file BUILD
.
Format file BUILD
harus cocok dengan output buildifier
.
Contoh pemformatan
# Test code implementing the Foo controller.
package(default_testonly = True)
py_test(
name = "foo_test",
srcs = glob(["*.py"]),
data = [
"//data/production/foo:startfoo",
"//foo",
"//third_party/java/jdk:jdk-k8",
],
flaky = True,
deps = [
":check_bar_lib",
":foo_data_check",
":pick_foo_port",
"//pyglib",
"//testing/pybase",
],
)
Struktur file
Rekomendasi: Gunakan urutan berikut (setiap elemen bersifat opsional):
Deskripsi paket (komentar)
Semua pernyataan
load()
Fungsi
package()
.Panggilan ke aturan dan makro
Buildifier membuat perbedaan antara komentar mandiri dan komentar yang dilampirkan ke elemen. Jika komentar tidak dilampirkan ke elemen tertentu, gunakan baris kosong setelahnya. Perbedaannya penting saat melakukan perubahan otomatis (misalnya, untuk menyimpan atau menghapus komentar saat menghapus aturan).
# Standalone comment (such as to make a section in a file)
# Comment for the cc_library below
cc_library(name = "cc")
Referensi ke target dalam paket saat ini
File harus dirujuk oleh jalurnya yang relatif terhadap direktori paket
(tanpa pernah menggunakan referensi ke atas, seperti ..
). File yang dihasilkan harus
diawali dengan ":
" untuk menunjukkan bahwa file tersebut bukan sumber. File sumber
tidak boleh diawali dengan :
. Aturan harus diawali dengan :
. Misalnya, anggaplah x.cc
adalah file sumber:
cc_library(
name = "lib",
srcs = ["x.cc"],
hdrs = [":gen_header"],
)
genrule(
name = "gen_header",
srcs = [],
outs = ["x.h"],
cmd = "echo 'int x();' > $@",
)
Penamaan target
Nama target harus deskriptif. Jika target berisi satu file sumber,
target umumnya harus memiliki nama yang berasal dari sumber tersebut (misalnya, cc_library
untuk chat.cc
dapat diberi nama chat
, atau java_library
untuk
DirectMessage.java
dapat diberi nama direct_message
).
Target eponim untuk paket (target dengan nama yang sama dengan direktori penampung) harus menyediakan fungsi yang dijelaskan oleh nama direktori. Jika target seperti itu tidak ada, jangan buat target dengan nama yang sama.
Memilih menggunakan nama pendek saat merujuk ke target eponim (//x
,
bukan //x:x
). Jika Anda berada dalam paket yang sama, pilih referensi
lokal (:x
, bukan //x
).
Hindari penggunaan nama target "yang dicadangkan" yang memiliki arti khusus. Termasuk
all
, __pkg__
, dan __subpackages__
, nama-nama ini memiliki semantik khusus
dan dapat menyebabkan kebingungan serta perilaku yang tidak terduga saat digunakan.
Jika tidak ada konvensi tim yang berlaku, berikut adalah beberapa rekomendasi yang tidak mengikat yang digunakan secara luas di Google:
- Secara umum, gunakan "snake_case"
- Untuk
java_library
dengan satusrc
, ini berarti menggunakan nama yang tidak sama dengan nama file tanpa ekstensi - Untuk aturan
*_binary
dan*_test
Java, gunakan "Upper CamelCase". Hal ini memungkinkan nama target cocok dengan salah satusrc
. Untukjava_test
, hal ini memungkinkan atributtest_class
disimpulkan dari nama target.
- Untuk
- Jika ada beberapa varian target tertentu, tambahkan akhiran untuk memperjelas (misalnya.
:foo_dev
,:foo_prod
atau:bar_x86
,:bar_x64
) - Melengkapi target
_test
dengan_test
,_unittest
,Test
, atauTests
- Hindari akhiran yang tidak bermakna seperti
_lib
atau_library
(kecuali jika diperlukan untuk menghindari konflik antara target_library
dan_binary
terkaitnya) - Untuk target terkait proto:
proto_library
target harus memiliki nama yang berakhiran_proto
- Aturan
*_proto_library
khusus bahasa harus cocok dengan proto yang mendasarinya, tetapi ganti_proto
dengan akhiran khusus bahasa seperti:cc_proto_library
:_cc_proto
java_proto_library
:_java_proto
java_lite_proto_library
:_java_proto_lite
Visibilitas
Visibilitas harus dicakup sedekat mungkin, sambil tetap mengizinkan akses
oleh pengujian dan dependensi terbalik. Gunakan __pkg__
dan __subpackages__
sebagaimana mestinya.
Hindari menetapkan paket default_visibility
ke //visibility:public
.
//visibility:public
harus ditetapkan satu per satu hanya untuk target dalam API publik project. Library ini dapat berupa library yang didesain untuk menjadi dependensi
oleh project eksternal atau biner yang dapat digunakan oleh proses build
project eksternal.
Dependensi
Dependensi harus dibatasi untuk dependensi langsung (dependensi diperlukan oleh sumber yang tercantum dalam aturan). Jangan mencantumkan dependensi transitif.
Dependensi lokal paket harus dicantumkan terlebih dahulu dan dirujuk agar kompatibel dengan bagian Referensi ke target dalam paket saat ini di atas (bukan berdasarkan nama paket absolutnya).
Pilih untuk mencantumkan dependensi secara langsung, sebagai daftar tunggal. Memasukkan dependensi "umum" beberapa target ke dalam variabel akan mengurangi kemudahan pemeliharaan, mencegah alat mengubah dependensi target, dan dapat menyebabkan dependensi yang tidak digunakan.
Glob
Tunjukkan "tidak ada target" dengan []
. Jangan gunakan glob yang tidak cocok dengan apa pun: glob ini
lebih rentan terhadap error dan kurang jelas dibandingkan daftar kosong.
Rekursif
Jangan gunakan glob berulang untuk mencocokkan file sumber (misalnya,
glob(["**/*.java"])
).
Globo rekursif membuat file BUILD
sulit untuk dibahas karena melewati
subdirektori yang berisi file BUILD
.
glob rekursif umumnya kurang efisien dibandingkan memiliki file BUILD
per
direktori dengan grafik dependensi yang ditentukan di antaranya karena hal ini memungkinkan cache dan paralelisme
jarak jauh yang lebih baik.
Sebaiknya tulis file BUILD
di setiap direktori dan tentukan
grafik dependensi di antara keduanya.
Non-rekursif
Bola non-rekursif umumnya dapat diterima.
Konvensi lainnya
Gunakan huruf besar dan garis bawah untuk mendeklarasikan konstanta (seperti
GLOBAL_CONSTANT
), gunakan huruf kecil dan garis bawah untuk mendeklarasikan variabel (sepertimy_variable
).Label tidak boleh dipisah, meskipun lebih dari 79 karakter. Label harus berupa literal string jika memungkinkan. Rasionale: Hal ini memudahkan mencari dan mengganti. Hal ini juga meningkatkan keterbacaan.
Nilai atribut nama harus berupa string konstanta literal (kecuali dalam makro). Rasionale: Alat eksternal menggunakan atribut nama untuk merujuk aturan. Mereka perlu menemukan aturan tanpa harus menafsirkan kode.
Saat menyetel atribut jenis boolean, gunakan nilai boolean, bukan nilai bilangan bulat. Karena alasan lama, aturan tetap akan mengonversi bilangan bulat ke boolean sesuai kebutuhan, tetapi hal ini tidak disarankan. Rasionale:
flaky = 1
dapat salah dibaca sebagai pernyataan "deflake target ini dengan menjalankan kembali sekali".flaky = True
dengan jelas menyatakan "pengujian ini tidak stabil".
Perbedaan dengan panduan gaya Python
Meskipun kompatibilitas dengan panduan gaya Python adalah sebuah tujuan, ada beberapa perbedaan:
Tidak ada batas panjang baris yang ketat. Komentar panjang dan {i>string<i} panjang sering dibagi menjadi 79 kolom, tetapi hal ini tidak wajib. Hal ini tidak boleh diterapkan dalam peninjauan kode atau skrip pra-pengiriman. Rasional: Label dapat panjang dan melebihi batas ini. Biasanya file
BUILD
dibuat atau diedit oleh alat, yang tidak sesuai dengan batas panjang baris.Penyambungan string implisit tidak didukung. Gunakan operator
+
. Rasionale: FileBUILD
berisi banyak daftar string. Sangat mudah untuk melupakan koma, yang mengarah pada hasil yang sangat berbeda. Hal ini telah menciptakan banyak bug sebelumnya. Lihat juga diskusi ini.Gunakan spasi di sekitar tanda
=
untuk argumen kata kunci dalam aturan. Rasionale: Argumen bernama jauh lebih sering daripada di Python dan selalu berada di baris terpisah. Spasi meningkatkan keterbacaan. Konvensi ini sudah ada sejak lama, dan tidak ada gunanya untuk memodifikasi semua fileBUILD
yang ada.Secara default, gunakan tanda kutip ganda untuk string. Rationale: Nilai ini tidak ditentukan dalam panduan gaya Python, tetapi merekomendasikan konsistensi. Jadi kami memutuskan untuk hanya menggunakan string tanda kutip ganda. Banyak bahasa menggunakan tanda kutip ganda untuk literal {i>string<i}.
Gunakan satu baris kosong di antara dua definisi tingkat atas. Rasionale: Struktur file
BUILD
tidak seperti file Python biasa. Pernyataan ini hanya memiliki pernyataan tingkat atas. Menggunakan satu baris kosong akan membuat fileBUILD
lebih pendek.