Bekerja dengan Dependensi Eksternal

Laporkan masalah Lihat sumber

Bazel dapat bergantung pada target dari project lain. Dependensi dari project lain ini disebut dependensi eksternal.

File WORKSPACE (atau file WORKSPACE.bazel) dalam direktori ruang kerja memberi tahu Bazel cara mendapatkan sumber project lain. Project lain ini dapat berisi satu atau beberapa file BUILD dengan targetnya sendiri. File BUILD dalam project utama dapat bergantung pada target eksternal ini dengan menggunakan namanya dari file WORKSPACE.

Misalnya, ada dua project pada sebuah sistem:

/
  home/
    user/
      project1/
        WORKSPACE
        BUILD
        srcs/
          ...
      project2/
        WORKSPACE
        BUILD
        my-libs/

Jika project1 ingin bergantung pada target, :foo, yang ditentukan dalam /home/user/project2/BUILD, hal ini dapat menentukan bahwa repositori bernama project2 dapat ditemukan di /home/user/project2. Selanjutnya, target dalam /home/user/project1/BUILD dapat bergantung pada @project2//:foo.

File WORKSPACE memungkinkan pengguna bergantung pada target dari bagian lain sistem file atau didownload dari internet. Alat ini menggunakan sintaksis yang sama dengan file BUILD, tetapi memungkinkan sekumpulan aturan berbeda yang disebut aturan repositori (terkadang juga dikenal sebagai aturan ruang kerja). Bazel dilengkapi dengan beberapa aturan repositori bawaan dan serangkaian aturan repositori Starlark yang disematkan. Pengguna juga dapat menulis aturan repositori kustom untuk mendapatkan perilaku yang lebih kompleks.

Jenis dependensi eksternal yang didukung

Beberapa jenis dasar dependensi eksternal dapat digunakan:

Bergantung pada project Bazel lainnya

Jika ingin menggunakan target dari project Bazel kedua, Anda dapat menggunakan local_repository, git_repository, atau http_archive untuk membuat symlink dari sistem file lokal, merujuk ke repositori git, atau mendownloadnya (masing-masing).

Misalnya, Anda sedang mengerjakan project my-project/, dan ingin bergantung pada target dari project rekan kerja Anda, coworkers-project/. Kedua project menggunakan Bazel, sehingga Anda dapat menambahkan project rekan kerja Anda sebagai dependensi eksternal, lalu menggunakan target apa pun yang telah ditetapkan rekan kerja Anda dari file BUILD Anda sendiri. Anda akan menambahkan kode berikut ke my_project/WORKSPACE:

local_repository(
    name = "coworkers_project",
    path = "/path/to/coworkers-project",
)

Jika rekan kerja Anda memiliki target //foo:bar, project Anda dapat menyebutnya sebagai @coworkers_project//foo:bar. Nama project eksternal harus berupa nama ruang kerja yang valid.

Bergantung pada project non-Bazel

Aturan yang diawali dengan new_, seperti new_local_repository, memungkinkan Anda membuat target dari project yang tidak menggunakan Bazel.

Misalnya, Anda sedang mengerjakan project my-project/, dan ingin bergantung pada project rekan kerja Anda, coworkers-project/. Project rekan kerja Anda menggunakan make untuk membuat build, tetapi Anda ingin bergantung pada salah satu file .so yang dihasilkannya. Untuk melakukannya, tambahkan kode berikut ke my_project/WORKSPACE:

new_local_repository(
    name = "coworkers_project",
    path = "/path/to/coworkers-project",
    build_file = "coworker.BUILD",
)

build_file menetapkan file BUILD untuk ditempatkan pada project yang ada, misalnya:

cc_library(
    name = "some-lib",
    srcs = glob(["**"]),
    visibility = ["//visibility:public"],
)

Selanjutnya, Anda dapat bergantung pada @coworkers_project//:some-lib dari file BUILD project.

Bergantung pada paket eksternal

Artefak dan repositori Maven

Gunakan kumpulan aturan rules_jvm_external untuk mendownload artefak dari repositori Maven dan membuatnya tersedia sebagai dependensi Java.

Mengambil dependensi

Secara default, dependensi eksternal diambil sesuai kebutuhan selama bazel build. Jika Anda ingin mengambil data dependensi yang diperlukan untuk sekumpulan target tertentu, gunakan bazel fetch. Untuk mengambil semua dependensi eksternal tanpa syarat, gunakan bazel sync. Karena repositori yang diambil disimpan di basis output, pengambilan akan terjadi per ruang kerja.

Dependensi bayangan

Jika memungkinkan, sebaiknya buat satu kebijakan versi dalam project Anda. Ini diperlukan untuk dependensi yang Anda kompilasi dan akhirnya berada di biner akhir. Namun, jika tidak benar, Anda dapat membayangi dependensi. Pertimbangkan skenario berikut:

project saya/Ruang Kerja

workspace(name = "myproject")

local_repository(
    name = "A",
    path = "../A",
)
local_repository(
    name = "B",
    path = "../B",
)

A/WORKSPACE

workspace(name = "A")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "testrunner",
    urls = ["https://github.com/testrunner/v1.zip"],
    sha256 = "...",
)

B/Ruang Kerja

workspace(name = "B")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "testrunner",
    urls = ["https://github.com/testrunner/v2.zip"],
    sha256 = "..."
)

Kedua dependensi A dan B bergantung pada testrunner, tetapi keduanya bergantung pada versi testrunner yang berbeda. Tidak ada alasan bagi runner pengujian ini untuk tidak berdampingan secara damai dalam myproject, tetapi mereka akan bentrok satu sama lain karena memiliki nama yang sama. Untuk mendeklarasikan kedua dependensi, update myproject/WORKSPACE:

workspace(name = "myproject")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
    name = "testrunner-v1",
    urls = ["https://github.com/testrunner/v1.zip"],
    sha256 = "..."
)
http_archive(
    name = "testrunner-v2",
    urls = ["https://github.com/testrunner/v2.zip"],
    sha256 = "..."
)
local_repository(
    name = "A",
    path = "../A",
    repo_mapping = {"@testrunner" : "@testrunner-v1"}
)
local_repository(
    name = "B",
    path = "../B",
    repo_mapping = {"@testrunner" : "@testrunner-v2"}
)

Mekanisme ini juga bisa digunakan untuk menggabungkan berlian. Misalnya, jika A dan B memiliki dependensi yang sama, tetapi memanggilnya dengan nama yang berbeda, dependensi tersebut dapat digabungkan di myproject/WORKSPACE.

Mengganti repositori dari command line

Untuk mengganti repositori yang dideklarasikan dengan repositori lokal dari command line, gunakan tanda --override_repository. Menggunakan flag ini akan mengubah konten repositori eksternal tanpa mengubah kode sumber Anda.

Misalnya, untuk mengganti @foo ke direktori lokal /path/to/local/foo, teruskan flag --override_repository=foo=/path/to/local/foo.

Beberapa kasus penggunaan mencakup:

  • Masalah proses debug. Misalnya, Anda dapat mengganti repositori http_archive ke direktori lokal tempat Anda dapat membuat perubahan dengan lebih mudah.
  • Vendor. Jika Anda berada di lingkungan yang tidak dapat melakukan panggilan jaringan, ganti aturan repositori berbasis jaringan agar mengarah ke direktori lokal.

Menggunakan proxy

Bazel akan mengambil alamat proxy dari variabel lingkungan HTTPS_PROXY dan HTTP_PROXY serta menggunakannya untuk mendownload file HTTP/HTTPS (jika ditentukan).

Dukungan untuk IPv6

Pada komputer khusus IPv6, Bazel akan dapat mendownload dependensi tanpa perlu melakukan perubahan. Namun, pada mesin dual-stack IPv4/IPv6, Bazel mengikuti konvensi yang sama seperti Java: jika IPv4 diaktifkan, IPv4 akan lebih diutamakan. Dalam beberapa situasi, misalnya saat jaringan IPv4 tidak dapat me-resolve/menjangkau alamat eksternal, hal ini dapat menyebabkan pengecualian Network unreachable dan kegagalan build. Dalam hal ini, Anda dapat mengganti perilaku Bazel agar lebih memilih IPv6 menggunakan properti sistem java.net.preferIPv6Addresses=true. Khususnya:

  • Gunakan opsi startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true, misalnya dengan menambahkan baris berikut dalam file .bazelrc:

    startup --host_jvm_args=-Djava.net.preferIPv6Addresses=true

  • Jika Anda menjalankan target build Java yang juga perlu terhubung ke internet (pengujian integrasi terkadang memerlukannya), gunakan juga tanda alat --jvmopt=-Djava.net.preferIPv6Addresses=true, misalnya dengan menyertakan baris berikut dalam file .bazelrc:

    build --jvmopt=-Djava.net.preferIPv6Addresses

  • Jika Anda menggunakan rules_jvm_external, misalnya, untuk resolusi versi dependensi, tambahkan juga -Djava.net.preferIPv6Addresses=true ke variabel lingkungan COURSIER_OPTS guna menyediakan opsi JVM untuk Coursier

Dependensi transitif

Bazel hanya membaca dependensi yang tercantum dalam file WORKSPACE Anda. Jika project Anda (A) bergantung pada project lain (B) yang mencantumkan dependensi pada project ketiga (C) dalam file WORKSPACE-nya, Anda harus menambahkan B dan C ke file WORKSPACE project Anda. Persyaratan ini dapat membengkak ukuran file WORKSPACE, tetapi membatasi kemungkinan satu library menyertakan C pada versi 1.0 dan library lainnya menyertakan C pada versi 2.0.

Menyimpan cache dependensi eksternal

Secara default, Bazel hanya akan mendownload ulang dependensi eksternal jika definisinya berubah. Perubahan pada file yang dirujuk dalam definisi (seperti patch atau file BUILD) juga diperhitungkan oleh bazel.

Untuk memaksa download ulang, gunakan bazel sync.

Tata Letak

Semua dependensi eksternal didownload ke direktori pada subdirektori external dalam base output. Untuk repositori lokal, symlink akan dibuat di sana, bukan membuat direktori baru. Anda dapat melihat direktori external dengan menjalankan:

ls $(bazel info output_base)/external

Perlu diperhatikan bahwa menjalankan bazel clean tidak benar-benar akan menghapus direktori eksternal. Untuk menghapus semua artefak eksternal, gunakan bazel clean --expunge.

Build offline

Terkadang, Anda perlu atau perlu menjalankan build secara offline. Untuk kasus penggunaan sederhana, seperti bepergian di pesawat, pengambilan data repositori yang diperlukan dengan bazel fetch atau bazel sync sudah cukup; selain itu, dengan menggunakan opsi --nofetch, pengambilan repositori lebih lanjut dapat dinonaktifkan selama build.

Untuk build offline yang sebenarnya, ketika penyediaan file yang diperlukan dilakukan oleh entity yang berbeda dari bazel, bazel mendukung opsi --distdir. Setiap kali aturan repositori meminta bazel untuk mengambil file melalui ctx.download atau ctx.download_and_extract dan memberikan jumlah hash file yang diperlukan, bazel akan terlebih dahulu melihat direktori yang ditentukan oleh opsi tersebut untuk file yang cocok dengan nama dasar URL pertama yang diberikan, dan menggunakan salinan lokal tersebut jika hash cocok.

Bazel sendiri menggunakan teknik ini untuk melakukan bootstrap secara offline dari artefak distribusi. Hal ini dilakukan dengan mengumpulkan semua dependensi eksternal yang diperlukan dalam distdir_tar internal.

Namun, bazel memungkinkan eksekusi perintah arbitrer dalam aturan repositori, tanpa mengetahui apakah perintah tersebut terhubung ke jaringan. Oleh karena itu, bazel tidak memiliki opsi untuk menerapkan build yang sepenuhnya offline. Jadi, menguji apakah build berfungsi dengan benar secara offline memerlukan pemblokiran jaringan eksternal, seperti yang dilakukan bazel dalam pengujian bootstrap.

Praktik terbaik

Aturan repositori

Aturan repositori umumnya harus bertanggung jawab untuk:

  • Mendeteksi setelan sistem dan menulisnya ke file.
  • Mencari resource di tempat lain pada sistem.
  • Mendownload resource dari URL.
  • Membuat atau membuat symlink file BUILD ke direktori repositori eksternal.

Hindari penggunaan repository_ctx.execute jika memungkinkan. Misalnya, saat menggunakan library C++ non-Bazel yang memiliki build menggunakan Make, sebaiknya gunakan repository_ctx.download() lalu tulis file BUILD yang membangunnya, daripada menjalankan ctx.execute(["make"]).

Pilih http_archive dari git_repository dan new_git_repository. Alasannya adalah:

  • Aturan repositori Git bergantung pada git(1) sistem, sedangkan downloader HTTP dibangun ke dalam Bazel dan tidak memiliki dependensi sistem.
  • http_archive mendukung daftar urls sebagai duplikat, dan git_repository hanya mendukung satu remote.
  • http_archive berfungsi dengan cache repositori, tetapi tidak git_repository. Lihat #5116 untuk informasi selengkapnya.

Jangan gunakan bind(). Lihat "Pertimbangkan untuk menghapus pengikatan" untuk diskusi panjang tentang masalah dan alternatifnya.