Azimjon Abdurasulov

Bazel 2: O'rnatish va birinchi build — Bazelisk, .bazelversion, MODULE.bazel, .bazelrc va "Salom, Bazel!"

📦 Bazel iOS — Mukammal Qo‘llanma & Amaliyot

Bazel 2: O'rnatish va birinchi build — Bazelisk, .bazelversion, MODULE.bazel, .bazelrc va "Salom, Bazel!"

Holat: 2026-yil oktabr. Bu darsda Bazel'ni Bazelisk orqali o'rnatamiz, noldan minimal workspace yig'amiz (.bazelversion, MODULE.bazel, BUILD.bazel), birinchi swift_binary — "Salom, Bazel!" macOS CLI'sini build va run qilamiz, keyin output daraxti, client/server arxitekturasi va .bazelrc'ni chuqur o'rganamiz. Kod misollari Bazel 9.3.0, rules_swift 4.2.1 va Xcode 27.1 bilan Apple M4 Pro'da tekshirilgan.

Bu darsdan keyin siz: bo'sh papkadan boshlab ishlaydigan Bazel loyihasini o'z qo'lingiz bilan yig'asiz, birinchi target'ingizni build/run qilasiz va Bazel nima qayerga yozishini tushunasiz.

  • Bazelisk'ni o'rnatasiz va .bazelversion orqali jamoadagi hamma bir xil Bazel versiyasini ishlatishini ta'minlaysiz.
  • Minimal workspace'ning har bir faylini — MODULE.bazel, BUILD.bazel, .bazelrc — nima uchun kerakligini bilib yozasiz.
  • bazel build va bazel run farqini, output daraxtini (bazel-bin, bazel-out, output base) va nega ikkinchi build birinchisidan o'nlab barobar tez ekanini tushunasiz.
  • .bazelrc'da common/build/test/run bo'limlari, --config guruhlari va eng muhim flaglarni sozlaysiz.
  • bazel info, bazel clean vs --expunge, MODULE.bazel.lock, .gitignore va Buildifier'ni kundalik ishda to'g'ri ishlatasiz.

Mundarija

  1. Bazelisk bilan o'rnatish
  2. Birinchi workspace: to'rt fayl
  3. Birinchi build va run — "Salom, Bazel!"
  4. Ikkinchi modul: swift_library qo'shamiz
  5. Output daraxti: Bazel nima qayerga yozadi
  6. Client/server: nega ikkinchi build tez
  7. .bazelrc chuqur: flaglarni bir marta yozib qo'yish
  8. Kundalik buyruqlar: info, clean, lock, gitignore, Buildifier
  9. Amaliy mashqlar
  10. O'zingizni tekshiring
  11. Xulosa
  12. Manbalar

1. Bazelisk bilan o'rnatish {#ornatish}

Oldingi darsda (Bazel 1: Bazel nima va nega kerak) Bazel'ning nima ekani va nega katta iOS jamoalariga kerakligini ko'rdik. Endi uni ishga tushiramiz. Birinchi savol: Bazel'ning o'zini qanday o'rnatamiz?

Bazel'ni to'g'ridan-to'g'ri o'rnatish mumkin, lekin bu yo'l tavsiya etilmaydi. Muammo oddiy: loyihangiz Bazel 9.3.0'da ishlaydi, hamkasbingiz noutbukida Bazel 8.8 turibdi, CI serverida esa yana boshqa versiya. Build xatti-harakati versiyadan versiyaga o'zgaradi — kimdir build qila oladi, boshqasi yo'q. Bu "menda ishlayapti-ku" muammosining aynan build tizimidagi ko'rinishi.

Yechim — Bazelisk. Bu Bazel'ning rasmiy launcher'i (ishga tushiruvchisi): siz bazel deb yozasiz, lekin aslida Bazelisk ishlaydi, u loyihangiz talab qilgan aynan o'sha Bazel versiyasini yuklab oladi va ishga tushiradi. Node'dagi nvm, Ruby'dagi rbenv yoki Tuist'dagi mise nima vazifani bajarsa, Bazelisk ham Bazel uchun shuni qiladi.

O'rnatish (macOS, Homebrew)

brew install bazelisk

Homebrew bazelisk'ni o'rnatadi va bazel nomini ham unga ulaydi (symlink). Ya'ni siz terminalda bazel deb yozsangiz ham, aslida Bazelisk ishlaydi. Tekshiramiz:

which bazel bazelisk
bazel --version

Bizning mashinada natija:

/opt/homebrew/bin/bazel
/opt/homebrew/bin/bazelisk
bazel 9.3.0

bazel va bazelisk bir xil joyga ishora qiladi — demak bazel buyrug'i Bazelisk orqali ketyapti. Versiya 9.3.0 chiqdi, chunki pastda ko'rsatamiz — loyihamizda shu versiyani so'raganmiz.

🧠 Esda tuting: bazel install degan buyruq yo'q. Bazel'ni o'rnatish — bu Bazelisk'ni o'rnatish. Keyin har bir loyiha o'ziga kerak Bazel versiyasini .bazelversion faylida aytadi, Bazelisk esa uni avtomatik yuklab, keshlab, ishga tushiradi.

Bazelisk qaysi versiyani tanlashini qanday hal qiladi?

Bazelisk versiyani quyidagi tartibda qidiradi (birinchi topilgani yutadi):

  1. USE_BAZEL_VERSION muhit o'zgaruvchisi (environment variable) — CI'da bitta buyruq uchun versiyani majburlash uchun qulay.
  2. .bazeliskrc fayli.
  3. .bazelversion fayli — joriy papkadan boshlab yuqoriga (ota-papkalarga) qarab qidiriladi.
  4. USE_BAZEL_FALLBACK_VERSION.
  5. Hech biri bo'lmasa — eng oxirgi release.

Amalda 99% hollarda siz faqat .bazelversion faylidan foydalanasiz. U loyiha ildizida turadigan, ichida bitta qator — versiya raqami bo'lgan oddiy matn fayl:

# .bazelversion
9.3.0

.bazelversion qabul qiladigan yorliqlar faqat aniq raqam (9.3.0) bilan cheklanmaydi:

YorliqMa'nosi
9.3.0Aynan shu versiya (loyihalar uchun eng yaxshi — takrorlanadigan build)
9.xShu LTS liniyasining eng yangi release'i (RC'larsiz)
9.*Shu liniya, RC'lar bilan birga
latestEng oxirgi barqaror release
latest-1Undan bitta oldingi
last_greenHEAD'dagi oxirgi yashil (sinovdan o'tgan) build
rollingEng yangi rolling release

💡 Pro tip: Loyihangizda aniq versiyani (9.3.0) yozing, latest'ni emas. "Latest" bugun 9.3.0, ertaga 9.4.0 bo'lishi mumkin — va o'sha kuni CI'ingiz kutilmaganda sinishi mumkin. rules_apple'ning o'z repozitoriysi ham .bazelversion'da 9.x dan foydalanadi, lekin o'z mahsulot loyihangizda aniq raqam xavfsizroq: hamma — siz, hamkasbingiz, CI — millimetrgacha bir xil Bazel ishlatadi.

LTS va rolling: qaysi versiyani tanlash kerak?

Bazel 4.0'dan beri ikki xil release liniyasi bor:

  • LTS (Long Term Support) — har ~12 oyda bitta yangi major versiya (masalan Bazel 8, Bazel 9). Har bir major o'z ichida minor (9.1, 9.2, 9.3) va patch (9.3.0) release'lari oladi. Bu liniya barqaror va uzoq qo'llab-quvvatlanadi.
  • Rolling — HEAD'dan har ~2 haftada chiqadigan "oldindan ko'rish" release'lari. Ular keyingi LTS'ning nima bo'lishini ko'rsatadi, lekin mos kelmaydigan o'zgarishlar (incompatible changes) olib kelishi mumkin.

Bazel'ning rasmiy release modeliga ko'ra har bir major versiya to'rt bosqichdan o'tadi: Rolling → Active → Maintenance → Deprecated. Active — joriy tavsiya etilgan LTS; Maintenance — faqat xavfsizlik va OS-moslik tuzatishlari backport qilinadigan eski LTS.

2026-yil oktabr holatiga ko'ra:

VersiyaHolatiIzoh
9.3.0eng yangi barqaror (2026-10-07)biz shu bilan ishlaymiz
8.8.18.x LTS liniyasi (2026-09-24)oldingi avlod, hali qo'llab-quvvatlanadi
10.0.0rc1pre-release (2026-10-07)hali RC — mahsulotda ishlatmang

⚠️ Diqqat: 10.0.0rc1 chiqqan bo'lsa ham, .bazelversion'ga uni yozmang. "rc" — release candidate, ya'ni hali sinov bosqichida. Loyihangizda oxirgi barqaror versiyani (9.3.0) pinlang.

Bazel 9 — nega eski darsliklar ishlamaydi

Agar internetdan Bazel bo'yicha eski qo'llanma topsangiz va unda WORKSPACE fayli haqida gap ketsa — u eskirgan. Buni bilib qo'ying, chunki bu eng ko'p vaqt yeydigan tuzoq:

  • Bazel 9.0'dan boshlab Bzlmod har doim yoqilgan, WORKSPACE fayli mantiqi esa butunlay olib tashlangan. --enable_bzlmod va --enable_workspace flaglari endi hech narsa qilmaydi (no-op). Tashqi bog'liqliklar faqat MODULE.bazel orqali e'lon qilinadi.
  • Bazel 9'da barcha C/C++ va Objective-C rule'lari (cc_library, objc_library, ...) Bazel yadrosidan chiqarildi — ularni endi @rules_cc'dan aniq load() qilish kerak. Sof Swift loyihalar uchun bu muammo emas, lekin ObjC aralash kod yozsangiz buni eslang.
  • Bazel 9'da macOS'da output base (Bazel hamma narsani yozadigan joy) /private/var/tmp'dan ~/Library/Caches/bazel'ga ko'chdi — shuning uchun kesh OS yangilanishidan keyin ham saqlanadi.

Demak bu darsda ko'radigan hamma narsa — MODULE.bazel, bazel_dep, Bzlmod — Bazel 9'ning zamonaviy, yagona to'g'ri usuli. WORKSPACE so'zini unuting.


2. Birinchi workspace: to'rt fayl {#workspace}

Endi noldan ishlaydigan loyiha yig'amiz. Bazel dunyosida loyiha workspace deb ataladi — bu Bazel boshqaradigan fayllar daraxtining ildizi. Workspace'ni nima belgilaydi? Ildizda MODULE.bazel faylining mavjudligi. Bazel'ni shu fayl turgan papkadan (yoki uning ichki papkasidan) ishga tushirish shart — aks holda "repozitoriya topilmadi" degan xato chiqadi.

"Salom, Bazel!" macOS buyruq-qatori (CLI) dasturini yasaymiz. Bor-yo'g'i to'rtta fayl kerak:

salom/
├── .bazelversion      # Bazelisk uchun: qaysi Bazel versiyasi
├── MODULE.bazel       # modul nomi + tashqi bog'liqliklar (bazel_dep)
├── BUILD.bazel        # target'lar (nima build qilinadi)
└── main.swift         # Swift kodimiz

Har birini yozamiz.

.bazelversion

# .bazelversion
9.3.0

Bitta qator. Bu faylni ko'rgan Bazelisk aynan 9.3.0'ni yuklab ishga tushiradi.

MODULE.bazel

Bu — loyihaning "pasporti". U ikki ishni qiladi: (1) modulingizga nom beradi, (2) tashqi bog'liqliklarni (bazel_dep) e'lon qiladi. Swift kodini build qilish uchun Bazel'ga rules_swift kerak — bu Swift'ni qanday kompilyatsiya qilishni biladigan rasmiy rule to'plami.

# MODULE.bazel
module(
    name = "salom_bazel",
    version = "1.0.0",
)

bazel_dep(name = "rules_swift", version = "4.2.1")

module() — moduling nomi va versiyasi. bazel_dep() — tashqi modulga bog'lanish. rules_swift qayerdan keladi? Bazel Central Registry (BCR) dan — bu npm'ning registry.npmjs.org'i yoki CocoaPods'ning trunk'iga o'xshash markaziy ombor (bcr.bazel.build). Siz versiyani aytasiz, Bazel BCR'dan o'zi yuklab oladi. Hech qanday URL yoki git-hash yozish shart emas.

🧠 Esda tuting: rules_swift — bu Apple'ning rasmiy repozitoriysi (bazelbuild/rules_swift), lekin u Bazel yadrosining qismi EMAS. Bazel o'zi til bilmaydi; har bir tilni alohida rule to'plami o'rgatadi. Swift uchun rules_swift, iOS ilovalari uchun rules_apple (keyingi darslarda), C++ uchun rules_cc. Bu Bazel'ning kuchi: u ko'p tilli (polyglot).

2026-yil oktabr holatida BCR'dagi dolzarb versiyalar: rules_swift 4.2.1, rules_apple 5.3.0, apple_support 2.10.1. Hozircha sof Swift CLI uchun bizga faqat rules_swift yetarli.

BUILD.bazel

Bu fayl papkani packagega aylantiradi va unda targetlar e'lon qilinadi. Target — Bazel qura oladigan bir narsa: kutubxona, bajariladigan fayl, test. Bizning target — bajariladigan Swift dastur, uni swift_binary rule yasaydi.

# BUILD.bazel
load("@rules_swift//swift:swift_binary.bzl", "swift_binary")

swift_binary(
    name = "salom",
    srcs = ["main.swift"],
)

Ikki qism bor:

  • load(...) — swift_binary rule'ini rules_swift modulidan olib keladi. @rules_swift — biz MODULE.bazel'da e'lon qilgan modulga ishora. Bazel'da hech bir rule o'z-o'zidan mavjud bo'lmaydi: har birini ishlatishdan oldin aniq load() qilish kerak. Bu — Swift'dagi import kabi.
  • swift_binary(...) — target'ning o'zi. name — target nomi (undan //:salom label hosil bo'ladi), srcs — manba fayllar ro'yxati.

💡 Pro tip: rules_swift 4.2.1'da ikkita load yo'li ishlaydi: @rules_swift//swift:swift_binary.bzl (har bir rule alohida faylda — yangi, tavsiya etilgan uslub) va @rules_swift//swift:swift.bzl (hamma rule'ni bitta joydan re-eksport qiladigan eski "to'plam" fayl). Ikkalasi ham bir xil swift_binary'ni beradi. Biz yangi, aniq yo'lni ishlatamiz — kelajakda swift.bzl eskirishi mumkin.

main.swift

// main.swift
print("Salom, Bazel!")

Oddiy Swift. @main ham, main.swift'da hech qanday boilerplate ham kerak emas — main.swift nomli fayl o'zi dastur kirish nuqtasi bo'ladi (bu Swift tilining qoidasi, Bazel'niki emas).

Quyidagi xarita workspace'ning har bir faylini va uning vazifasini bir ko'rinishda jamlaydi. Bu to'rt fayl — zarur minimum; .bazelrc ixtiyoriy (uni 7-bo'limda qo'shamiz), MODULE.bazel.lock va bazel-* symlink'lari esa birinchi build'dan keyin o'zi paydo bo'ladi:

Minimal Bazel workspace anatomiyasi: .bazelversion, MODULE.bazel, MODULE.bazel.lock, .bazelrc, BUILD.bazel, main.swift va bazel-* symlink'lari — har birining vazifasi va qaysilari git'ga commit qilinishi.

Chap tomonda — fayllar daraxti, o'ngda — har birining roli; pastda qaysilari git'ga commit qilinishi (manba fayllar) va qaysilari .gitignore'ga ketishi (symlink'lar) ko'rsatilgan.

To'rt fayl tayyor. Endi build qilamiz.


3. Birinchi build va run — "Salom, Bazel!" {#birinchi-build}

bazel build — faqat quramiz

bazel build //:salom

//:salom — bu label. Uni shunday o'qing: // — workspace ildizi, :salom — ildizdagi BUILD.bazel'da turgan salom nomli target. Labellar haqida to'liq keyingi darsda (Bazel 3), hozircha "qaysi target'ni build qilaman" degan manzil deb bilsangiz yetarli.

Birinchi marta ishga tushirganda Bazel ancha "band" bo'ladi. Bizning mashinada birinchi (sovuq) build natijasi:

[255 / 289] Compiling absl/crc/crc32c.cc [for tool]; 2s darwin-sandbox ... (12 actions running)
[278 / 289] Compiling absl/synchronization/internal/stdcpp_waiter.cc [for tool]; 1s darwin-sandbox
[286 / 289] Compiling Swift module //:salom; 0s worker
Target //:salom up-to-date:
  bazel-bin/salom
INFO: Elapsed time: 44.230s, Critical Path: 11.65s
INFO: 289 processes: 117 internal, 171 darwin-sandbox, 1 worker.
INFO: Build completed successfully, 289 total actions

44 soniya — bitta print uchun? Ha, va bu normal. Sababini bilish muhim: bizning salom target'imiz 289 ta action'dan faqat bittasi. Qolgan 288'tasi — rules_swift'ning o'z persistent worker vositasini (Swift'ni tez kompilyatsiya qiladigan yordamchi dastur) noldan yig'ish. U C++'da yozilgan va abseil kutubxonasiga tayanadi — log'dagi Compiling absl/... qatorlari aynan shu. Bu bir martalik narx: mashinangizda bir marta to'lanadi, keyin kesh'da qoladi.

📊 Real raqamlar: Apple M4 Pro (12 yadro, 24 GB), Bazel 9.3.0, Xcode 27.1. Sovuq birinchi build (bo'sh output base, disk cache o'chirilgan): 44.2 s, 289 action. Shundan ~288'tasi — rules_swift worker'ini (abseil) kompilyatsiya qilish, bir martalik. Bizning bitta salom target'i esa oxirgi 0 soniyalik qadam.

Natija bazel-bin/salom'da — bu bajariladigan fayl. Uni to'g'ridan-to'g'ri ishga tushirsak ham bo'ladi:

./bazel-bin/salom
Salom, Bazel!

bazel run — quramiz va ishga tushiramiz

Ko'pincha "qur va darhol ishga tushir" kerak bo'ladi. Buning uchun bazel run:

bazel run //:salom
INFO: Elapsed time: 0.091s, Critical Path: 0.00s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action
INFO: Running command line: bazel-bin/salom
Salom, Bazel!

E'tibor bering: bu safar 0.091 s — chunki hech narsa o'zgarmagan, Bazel qayta build qilmadi, to'g'ridan-to'g'ri bazel-bin/salom'ni ishga tushirdi. bazel build va bazel run farqi shu: build faqat quradi, run quradi (agar kerak bo'lsa) va natijani bajaradi.

🚀 Motivatsiya: Birinchi build 44 soniya bo'ldi, lekin ikkinchisi — 0.16 soniyada "up-to-date" bo'ldi (hech narsa qurilmadi). Bu Bazel'ning asosiy va'dasi: o'zgarmagan ishni ikkinchi marta bajarmaydi. Katta loyihada bu farq soatlarni tejaydi. Buni o'z ko'zingiz bilan ko'rish uchun main.swift'ni ozgina o'zgartirib, qayta build qiling.

Inkremental build: bitta faylni o'zgartiramiz

main.swift'ni o'zgartiramiz:

// main.swift
let kim = "Bazel"
print("Salom, \(kim)!")
print("Birinchi build tizimi loyiham ishga tushdi.")
bazel build //:salom
Target //:salom up-to-date:
INFO: Elapsed time: 0.353s, Critical Path: 0.28s
INFO: 4 processes: 2 internal, 1 darwin-sandbox, 1 worker.
INFO: Build completed successfully, 4 total actions

289 action o'rniga atigi 4 ta — faqat o'zgargan faylga bog'liq ishlar qayta bajarildi. worker allaqachon tayyor (kesh'da), abseil qayta kompilyatsiya qilinmadi. Natija:

Salom, Bazel!
Birinchi build tizimi loyiham ishga tushdi.

📊 Real raqamlar: O'sha mashina. Bitta Swift faylni tahrirlab qayta build: 0.353 s, 289 o'rniga 4 action. Bu — Bazel'ning inkremental build'i: faqat o'zgarishga bog'liq bo'lgan qismni qayta quradi.

Mana Bazel'ning asosiy g'oyasi amalda: sovuq 44.2 s → inkremental 0.35 s. Build grafigi va action keshi tufayli Bazel aniq biladi — nima o'zgardi va nimani qayta qurish shart emas.


4. Ikkinchi modul: swift_library qo'shamiz {#swift-library}

Bitta swift_binary — bu boshlanish. Bazel'ning asl kuchi loyihani modullarga bo'lganda ko'rinadi: har bir modul alohida swift_library, Bazel esa faqat o'zgargan modulni qayta quradi. Buni hozir kichik miqyosda ko'ramiz — salomlashish mantiqini alohida kutubxonaga ajratamiz.

Yangi papka ochamiz: greeter/. Ichida ikki fayl.

greeter/Greeter.swift — kutubxona kodi

// greeter/Greeter.swift
public struct Greeter {
    public init() {}

    public func salom(_ kim: String) -> String {
        "Salom, \(kim)!"
    }
}

public muhim: boshqa modul (salom binary) bu tipdan foydalanishi uchun u ochiq bo'lishi kerak. Swift'da modul tashqarisiga chiqadigan hamma narsa public bo'lishi shart.

greeter/BUILD.bazel — kutubxona target'i

# greeter/BUILD.bazel
load("@rules_swift//swift:swift_library.bzl", "swift_library")

swift_library(
    name = "greeter",
    srcs = ["Greeter.swift"],
    module_name = "Greeter",
    visibility = ["//visibility:public"],
)

Uch atribut:

  • srcs — kutubxona manba fayllari.
  • module_name = "Greeter" — Swift modul nomi. Bu belgilanmasa, Bazel target label'idan avtomatik nom yasaydi (greeter), lekin aniq nom bergan ma'qul — import Greeter shunga bog'liq.
  • visibility = ["//visibility:public"] — bu target'ni kim ishlatishi mumkinligini belgilaydi. public — hamma. Visibility — Bazel'ning arxitektura qoidalarini majburlash mexanizmi (to'liq Bazel 3da); hozircha "boshqa papkadagi target shundan foydalana olsin" deb qo'yamiz.

Binary'ni kutubxonaga bog'laymiz

Root BUILD.bazel'ga deps qo'shamiz:

# BUILD.bazel
load("@rules_swift//swift:swift_binary.bzl", "swift_binary")

swift_binary(
    name = "salom",
    srcs = ["main.swift"],
    deps = ["//greeter"],
)

deps = ["//greeter"] — salom binary'si greeter kutubxonasiga bog'liq. //greeter — bu label: //greeter papkasidagi greeter nomli target (nom papka nomi bilan bir xil bo'lsa, :greeter qismi tushib qoladi).

main.swift — kutubxonadan foydalanamiz

// main.swift
import Greeter

let greeter = Greeter()
print(greeter.salom("Bazel"))
print(greeter.salom("iOS dasturchi"))

Build va run:

bazel run //:salom
INFO: Elapsed time: 1.964s, Critical Path: 1.81s
INFO: 8 processes: 3 action cache hit, 4 internal, 2 darwin-sandbox, 2 worker.
INFO: Running command line: bazel-bin/salom
Salom, Bazel!
Salom, iOS dasturchi!

Ikkita modul, ikkita swift_library/swift_binary, bitta deps bog'lanishi. Worker allaqachon kesh'da bo'lgani uchun bu build atigi ~2 soniya — rules_swift'ning C++ worker'ini qayta qurish shart emas edi.

📊 Real raqamlar: Apple M4 Pro, Bazel 9.3.0. Ikki modulli loyihani (greeter + salom) build + run: 1.964 s, 8 action. Worker kesh'da bo'lgani sabab 44 soniyalik sovuq narx qaytmadi.

Build grafigini ko'rish: bazel query

Bazel aniq biladi — qaysi target qaysisiga bog'liq. bazel query bu grafikni ko'rsatadi:

bazel query 'deps(//:salom)'

Natijaning loyihamizga tegishli qismi (tashqi modullar chiqarib tashlangan):

//:main.swift
//:salom
//greeter:Greeter.swift
//greeter:greeter

//:salom //greeter:greeter'ga, u esa o'z manbasiga bog'liq. Bu grafik — Bazel inkremental build'ining asosi: greeter/Greeter.swift'ni o'zgartirsangiz, Bazel faqat greeter va unga bog'liq salom'ni qayta quradi; main.swift'ni o'zgartirsangiz — faqat salom'ni, greeter tegilmaydi. Build grafigi va query haqida to'liq keyingi darsda.

🚀 Motivatsiya: Hozir atigi ikki modul. Tasavvur qiling — 200 modulli ilova. Bitta ekranni o'zgartirsangiz, Bazel qolgan 199 modulni tegmay, faqat o'shani qayta quradi. Oldingi darsda ko'rgan real jamoalar (Monzo, Trendyol) build vaqtini aynan shu tamoyil bilan daqiqalardan soniyalarga tushirgan.


5. Output daraxti: Bazel nima qayerga yozadi {#output-tree}

Birinchi build'dan keyin workspace'ingizda yangi narsalar paydo bo'ldi. Ularni ko'ramiz:

ls -la
$ ls -la    # (qisqartirilgan: egasi/sana ustunlari olib tashlandi, hash … bilan)
lrwxr-xr-x  bazel-bin      -> /Users/.../_bazel_codingtech/c632aa8f…/execroot/_main/bazel-out/darwin_arm64-fastbuild/bin
lrwxr-xr-x  bazel-out      -> /Users/.../_bazel_codingtech/c632aa8f…/execroot/_main/bazel-out
lrwxr-xr-x  bazel-salom    -> /Users/.../_bazel_codingtech/c632aa8f…/execroot/_main
lrwxr-xr-x  bazel-testlogs -> /Users/.../_bazel_codingtech/c632aa8f…/execroot/_main/bazel-out/darwin_arm64-fastbuild/testlogs

bazel-bin, bazel-out, bazel-<workspace-nomi> — bular oddiy papka emas, symlinklar (-> belgisiga e'tibor bering). Ular workspace'ingizdan tashqaridagi haqiqiy build papkalariga ishora qiladi. Nega tashqarida? Chunki build natijalari (vaqtinchalik, qayta yaratiladigan) manba kodingiz bilan aralashmasligi kerak.

Output base — hamma narsa shu yerda

Bazel hamma ishni output base degan papkada bajaradi. Uning yo'lini bazel info ko'rsatadi:

bazel info output_base
bazel info execution_root
bazel info bazel-bin

Bizning mashinada:

output_base:    /Users/codingtech/Library/Caches/bazel/_bazel_codingtech/c632aa8fbc05321e1c324ab1e0f95e76
execution_root: <output_base>/execroot/_main
bazel-bin:      <output_base>/execroot/_main/bazel-out/darwin_arm64-fastbuild/bin
release:        release 9.3.0

Yo'lni tahlil qilamiz. Bazel 9'da macOS'da ildiz — ~/Library/Caches/bazel (Bazel 8 va undan oldin /private/var/tmp edi). Undan keyin:

  • _bazel_<user>/ — foydalanuvchi bo'yicha papka. Bitta mashinada bir nechta odam ishlasa, har kimning o'z papkasi bo'ladi.
  • <hash>/ — bu workspace yo'lining MD5 hash'i. Shuning uchun har bir workspace o'z output base'iga ega. Ikki xil papkadagi ikki loyiha bir-biriga xalaqit bermaydi.

Output base ichidagi muhim qismlar (rasmiy hujjat layout'idan):

~/Library/Caches/bazel/_bazel_<user>/<hash>/
├── action_cache/      # qaysi action bajarilgani — inkremental build'ning xotirasi
├── command.log        # oxirgi buyruqning stdout/stderr nusxasi
├── external/          # yuklab olingan tashqi modullar (rules_swift ...)
├── server/            # Bazel server fayllari (socket, log)
│   └── jvm.out        # server debug chiqishi
└── execroot/
    └── _main/         # build ishlaydigan daraxt (execution root)
        └── bazel-out/ # BARCHA build natijalari shu yerda
            └── .../bin/salom   # bizning bajariladigan faylimiz

Qulaylik symlink'lari

Workspace ildizidagi symlink'lar shu chuqur yo'llarga qisqa yo'l beradi:

SymlinkIshora qiladiNima uchun
bazel-bin.../binbuild qilingan binary'lar (bazel-bin/salom)
bazel-out.../bazel-outbarcha output (bin, genfiles, testlogs)
bazel-testlogs.../testlogstest log'lari (keyingi darsda)
bazel-<dir>.../execroot/_mainexecution root (source + output aralash ko'rinish)

Bazel'ning o'zi bu symlink'lardan foydalanmaydi — ular faqat siz uchun qulaylik. Shuning uchun ularni .gitignore'ga qo'yish shart (pastda ko'ramiz).

🧠 Esda tuting: bazel info — eng foydali diagnostika buyrug'i. bazel info output_base serverni qidirmay turib javob beradi; bazel info release esa joriy Bazel versiyasini aytadi. "Build qayerda?" degan savol tug'ilsa — bazel info bazel-bin.


6. Client/server: nega ikkinchi build tez {#client-server}

3-bo'limda bir g'alati narsani ko'rdik: birinchi build 44 soniya, ikkinchisi — bir soniyadan kam. Buning sababi Bazel'ning ichki arxitekturasida.

Bazel ikki qismdan iborat: client va server. Siz terminalda bazel deb yozganingizda, aslida yengil client ishga tushadi. U haqiqiy ishni o'zi qilmaydi — uzoq yashovchi server (JVM jarayoni) bilan gaplashadi. Server esa build grafigini, o'qilgan BUILD/MODULE fayllarni va action keshini xotirada saqlaydi.

Bazel client/server arxitekturasi: yengil client gRPC orqali uzoq yashovchi JVM server bilan gaplashadi, server build grafigini xotirada saqlaydi, output base'ga yozadi.

Yuqoridagi sxema oqimni ko'rsatadi: client (bazel build //:salom) → server (xotiradagi graph + cache) → output base (diskdagi natijalar). Workspace ichidagi symlink'lar output base'ga ishora qiladi.

Nega bu muhim

  • Birinchi build: client serverni ishga tushiradi (yoki avval ishga tushirgan bo'lsa, topadi), server MODULE.bazel/BUILD.bazel'ni o'qiydi, tashqi modullarni yuklaydi, build grafigini noldan quradi, rules_swift worker'ini kompilyatsiya qiladi. 44.2 s shuning uchun.
  • Ikkinchi build: server allaqachon ishlab turibdi, graph uning xotirasida. Hech narsa o'zgarmagan bo'lsa, server darhol "up-to-date" deydi. Fayl yuklash, qayta tahlil — hech biri kerak emas.

Buni ps bilan ko'rish mumkin — server jarayoni workspace nomi bilan ko'rinadi:

ps -e | grep "bazel("

Server nomi bazel(salom) ko'rinishida bo'ladi (salom — workspace papka nomi). Har bir workspace uchun alohida server — shuning uchun bir nechta loyihada parallel ishlash mumkin.

Server qachon o'chadi

Server abadiy ishlamaydi. Standart holatda 3 soat bo'sh turgach o'chadi. Buni --max_idle_secs startup flagi bilan o'zgartirish mumkin:

# server 3 daqiqa bo'sh turgach o'chsin
bazel --max_idle_secs=180 build //:salom

Yoki .bazelrc'da doimiy qilib qo'yish mumkin: startup --max_idle_secs=180.

Serverni qo'lda o'chirish:

bazel shutdown

⚠️ Diqqat: Server o'chgandan keyingi birinchi build yana sekinroq bo'ladi — graph'ni qayta qurish kerak (lekin worker va action'lar disk cache'da bo'lsa, baribir sovuq 44 soniyadan ancha tez). Agar skript yozsangiz va u ko'p papkalarda build qilsa, bo'sh serverlar to'planib ketmasligi uchun ularni bazel shutdown bilan yoping yoki qisqa --max_idle_secs qo'ying. Rasmiy hujjat aynan shuni tavsiya qiladi.

🚀 Motivatsiya: Client/server modeli — Bazel tezligining yuragi. Xcode har safar loyihani "noldan tushunadi"; Bazel esa bir marta tushunib, xotirada saqlaydi. Katta loyihada (yuzlab modul) bu farq ulkan: grafik qurish o'zi daqiqalar olishi mumkin, Bazel uni bir marta qilib, keyingi barcha buyruqlarda qayta ishlatadi.


7. .bazelrc chuqur: flaglarni bir marta yozib qo'yish {#bazelrc}

Bazel'da juda ko'p flag bor. Ayrimlari har build'da o'zgaradi, ko'pchiligi esa doim bir xil qoladi (masalan disk cache yo'li yoki simulator nomi). Har safar qo'lda yozmaslik uchun ularni .bazelrc faylida bir marta yozib qo'yasiz. Bu — build sozlamalaringizning yagona manbasi.

Bazel qaysi rc fayllarni o'qiydi va qaysi tartibda

Bazel rc fayllarini quyidagi tartibda o'qiydi (keyingisi oldingisini bekor qila oladi):

  1. System rc — /etc/bazel.bazelrc (butun mashina uchun).
  2. Workspace rc — workspace ildizidagi .bazelrc (loyiha uchun; git'ga commit qilinadi).
  3. Home rc — $HOME/.bazelrc (sizning shaxsiy sozlamalaringiz).
  4. Environment rc — BAZELRC muhit o'zgaruvchisi ko'rsatgan fayl(lar).
  5. User-specified — --bazelrc=fayl bilan buyruq qatorida berilgan.

Amalda ishlatadiganingiz — **workspace .bazelrc (loyiha bilan birga ketadi, hamma uchun bir xil) va ba'zan home ~/.bazelrc** (faqat sizning mashinangizdagi afzalliklar). Masalan bu darsni yozayotgan mashinada home rc'da bitta qator bor:

# ~/.bazelrc
startup --max_idle_secs=180

Bu — server bo'sh turganida necha soniyada o'chishini belgilaydi (buni 6-bo'limda ko'rganmiz).

Sintaksis: har qator kimga tegishli

.bazelrc'ning har bir qatori <kim> <flaglar> ko'rinishida. Birinchi so'z flag qaysi buyruqlarga tegishli ekanini aytadi:

  • startup — startup flaglari (buyruqdan oldin keladi, masalan --max_idle_secs).
  • common — flagni qo'llab-quvvatlaydigan barcha buyruqlarga. Agar biror buyruq flagni bilmasa, u shunchaki e'tiborsiz qoldiriladi (xato bermaydi).
  • always — barcha buyruqlarga; agar buyruq flagni bilmasa — xato beradi.
  • build, test, run, query, ... — aniq buyruqqa (va undan meros oladigan buyruqlarga).

Eng muhim nuqta — meros (inheritance). test buyrug'i build'dan meros oladi. Ya'ni build qatoridagi hamma flag bazel test'ga ham tegishli. Rasmiy hujjatdagi meros grafigi:

  • Har bir buyruq common'dan meros oladi.
  • build'dan meros oladiganlar: test, run, clean, mobile-install, info, print_action, config, cquery, aquery.
  • coverage, fetch, vendor esa test'dan meros oladi.
# .bazelrc
# Hammaga tegishli
common --disk_cache=~/.cache/bazel-disk

# Faqat build (va undan meros oladigan test/run/...)
build --verbose_failures

# Faqat test
test --test_output=errors

Bu misolda bazel test buyrug'i uchta flagni ham oladi: --disk_cache (common'dan), --verbose_failures (build'dan meros), --test_output=errors (o'ziniki).

🧠 Esda tuting: Buyruq qatorida bergan flag har doim .bazelrc'dagidan ustun. Agar rc'da build -c opt tursa-yu, siz bazel build -c dbg desangiz — dbg yutadi. rc fayllar faqat standart qiymat beradi, majburlamaydi.

--config: flaglarni guruhlash

.bazelrc'da bir nechta flagni nom ostida guruhlash mumkin. Buning uchun buyruqdan keyin :nom qo'shasiz. Oddiy holatda bu flaglar e'tiborsiz qoldiriladi, faqat --config=nom berganda yoqiladi.

# .bazelrc
# "release" konfiguratsiyasi — optimallashtirilgan build
build:release -c opt
build:release --features=swift.enable_v6

# "ci" konfiguratsiyasi
build:ci --disk_cache=
build:ci --keep_going
bazel build //:salom --config=release   # -c opt + swift.enable_v6 qo'llanadi

Bu — eng ko'p ishlatiladigan naqsh. Masalan --config=ci CI serverida, --config=release relizda, --config=debug kundalik ishda. Keyingi darslarda (cache, CI/CD) buni ko'p ishlatamiz.

💡 Pro tip: Shaxsiy (home) rc'dagi config nomlarini _ bilan boshlang (build:_tez ...) — shunda ular loyiha rc'sidagi nomlar bilan to'qnashmaydi.

try-import: shaxsiy sozlamalar uchun

Jamoada har kimning o'z afzalliklari bo'ladi (masalan --jobs soni yoki local simulator). Buni loyiha rc'siga yozib bo'lmaydi — u hammaga tegishli. Yechim: try-import.

# .bazelrc (loyiha, git'ga commit qilinadi)
common --disk_cache=~/.cache/bazel-disk
build --verbose_failures

# Har bir dasturchining o'z sozlamalari (git'ga qo'shilmaydi)
try-import %workspace%/user.bazelrc
  • import — fayl bo'lmasa Bazel xato beradi.
  • try-import — fayl bo'lmasa xato bermaydi, shunchaki o'tkazib yuboradi.
  • %workspace% — workspace ildiziga nisbatan yo'l.

user.bazelrc'ni .gitignore'ga qo'shing. Endi har bir dasturchi o'ziga kerak flaglarni o'sha faylga yozadi, loyiha rc'si esa toza qoladi.

Kundalik ishda eng foydali flaglar

Quyidagilar — har kuni ishlatiladigan flaglar va ularning ta'siri:

FlagNima qiladi
-c fastbuildStandart rejim: optimizatsiyasiz, tez kompilyatsiya (kundalik ish)
-c dbgDebug ma'lumotlari bilan (breakpoint, LLDB)
-c optOptimallashtirilgan (reliz, performance test)
--disk_cache=<yo'l>Build natijalarini diskda keshlash (workspace'lar orasida bo'lishiladi)
--jobs=NParallel action soni (standart — CPU yadrolari soni)
--keep_going / -kBitta target sinsa ham qolganini qurishda davom etish
--verbose_failuresSingan action'ning to'liq buyruq qatorini ko'rsatish
-s / --subcommandsHar bir action'ning aniq buyruq qatorini chop etish
--announce_rcQaysi rc fayllar va flaglar qo'llanganini ko'rsatish

--announce_rc: nima qo'llanayotganini ko'rish

"Mening flagim qayerdan kelyapti?" degan savol tug'ilsa, --announce_rc javob beradi:

bazel build //:salom --announce_rc
  Inherited 'common' options: --isatty=0 --terminal_columns=80
INFO: Reading rc options for 'build' from <workspace>/.bazelrc:
  Inherited 'common' options: --disk_cache=~/.cache/bazel-disk

-s: Bazel aslida qanday buyruq ishga tushiradi

Bazel "qora quti" emas. -s (subcommands) bilan har bir action'ning aniq buyruq qatorini ko'rasiz — masalan swiftc qanday chaqirilgani. greeter modulini misol qilamiz:

bazel build //greeter:greeter -s

Chiqishning modulni kompilyatsiya qiladigan qismi (qisqartirilgan):

SUBCOMMAND: # swift_library rule target //greeter:greeter [action 'Compiling Swift module
//greeter:greeter', ..., mnemonic: SwiftCompile]
(cd /Users/.../_bazel_codingtech/c632aa8f…/execroot/_main && \
  bazel-out/darwin_arm64-opt-exec/bin/external/rules_swift+/tools/worker/worker \
  swiftc @bazel-out/darwin_arm64-fastbuild/bin/greeter/Greeter.swiftmodule-0.params)
[283 / 285] Compiling Swift module //greeter:greeter; 1s disk-cache, worker

Diqqat qilinadigan narsa: Bazel swiftc'ni to'g'ridan-to'g'ri emas, rules_swift'ning persistent worker'i orqali chaqiradi va unga .params flagfile beradi (Greeter.swiftmodule-0.params). O'sha fayl ichida aniq flaglar turadi: -target, -sdk, -emit-object, -module-name, -swift-version, -Onone (fastbuild rejimi) va boshqalar. -s — debugging uchun oltin: "nega bu fayl bunday kompilyatsiya qilindi?" degan savolga aniq javob beradi.

⚠️ Diqqat: -s chiqishi juda uzun bo'ladi (har bir action uchun bir nechta qator). Uni faqat muayyan muammoni tekshirayotganda yoqing, doimiy .bazelrc'ga qo'ymang.


8. Kundalik buyruqlar: info, clean, lock, gitignore, Buildifier {#kundalik}

Loyiha ishga tushdi. Endi har kuni ishlatadigan buyruqlar va fayllarni ko'rib chiqamiz.

bazel info — "qayerda, qaysi versiya?"

bazel info — diagnostika buyrug'i. Argumentsiz chaqirsangiz, o'nlab qatorli ma'lumot beradi; aniq kalit bersangiz — faqat o'shani:

bazel info release        # Bazel versiyasi
bazel info workspace      # workspace ildizi
bazel info output_base    # hamma narsa yoziladigan joy
bazel info bazel-bin      # binary'lar qayerda
bazel info execution_root # build ishlaydigan daraxt
release 9.3.0

bazel info release — eng oddiy "Bazel ishlayaptimi va qaysi versiya?" tekshiruvi.

bazel clean vs bazel clean --expunge

Ba'zan build holatini tozalash kerak bo'ladi. Ikki daraja bor:

  • **bazel clean** — build chiqishini (bazel-out), action keshini va workspace symlink'larini o'chiradi. Server ishlashda qoladi, tashqi modullar (external/) saqlanadi.
  • **bazel clean --expunge** — butun output base'ni o'chiradi: tashqi modullar, yuklab olingan hamma narsa ham ketadi. Serverni ham to'xtatadi.

⚠️ Diqqat: bazel clean'ni muammoni "hal qilish" uchun refleks sifatida ishlatmang. Bazel inkremental build'i ishonchli — toza build kamdan-kam kerak. clean 44 soniyalik sovuq narxni qaytaradi. --expunge esa bundan ham qimmatroq (tashqi modullarni qayta yuklaydi). Ularni faqat haqiqatan kesh buzilganiga ishonchingiz komil bo'lganda ishlating. Rasmiy hujjat ham aytadi: clean birinchi navbatda disk bo'shatish uchun, "muammoni tuzatish" uchun emas.

Lekin yaxshi xabar: **disk cache clean'dan omon qoladi**. Agar .bazelrc'da --disk_cache yoqilgan bo'lsa, bazel clean'dan keyingi build disk cache'dan tiklanadi:

bazel clean
bazel build //:salom
INFO: Elapsed time: 1.062s, Critical Path: 0.05s
INFO: 289 processes: 172 disk cache hit, 117 internal.

44 soniya o'rniga 1 soniya — 172 action disk cache'dan olindi, hech narsa qayta kompilyatsiya qilinmadi. Shuning uchun --disk_cache darsning boshidan .bazelrc'da turibdi.

📊 Real raqamlar: Apple M4 Pro, Bazel 9.3.0. bazel clean + qayta build, disk cache yoqilgan: 1.062 s, 172 ta disk cache hit. Disk cache cleandan omon qoladi, shuning uchun toza build ham sovuq emas.

MODULE.bazel.lock — commit qiling

Birinchi build'dan keyin MODULE.bazel.lock fayli paydo bo'ladi. Bu — tashqi bog'liqliklarning aniq qulflangan holati (npm'dagi package-lock.json, Swift'dagi Package.resolved kabi). U BCR'dan yuklangan modullarning aniq versiyalari va hash'larini yozadi.

Bu faylni git'ga commit qiling. Shunda hamkasbingiz va CI aynan siz ishlatgan modul versiyalarini oladi — "menda boshqa versiya yuklandi" muammosi bo'lmaydi.

🧠 Esda tuting: Commit qilinadigan: .bazelversion, MODULE.bazel, MODULE.bazel.lock, .bazelrc, BUILD.bazel fayllari va manba kod. Commit qilinmaydigan: bazel-* symlink'lari va user.bazelrc.

.gitignore

Bazel loyihasining .gitignore'i qisqa:

# .gitignore
# Bazel qulaylik symlink'lari (output base'ga ishora qiladi, qayta yaratiladi)
/bazel-*

# Shaxsiy rc (try-import orqali ulanadi)
/user.bazelrc

bazel-bin, bazel-out, bazel-testlogs, bazel-<dir> — hammasi symlink, har build'da qayta yaratiladi. Ularni commit qilish keraksiz va zararli.

Buildifier — BUILD fayllar uchun formatter va linter

BUILD.bazel va .bzl fayllar ham kod — ularni ham formatlash kerak. Buning rasmiy vositasi — Buildifier (Bazel jamoasining buildtools to'plamidan, Swift'dagi SwiftFormat/SwiftLint kabi).

brew install buildifier

Bizning mashinada Homebrew buildifier 10.1.0'ni o'rnatdi.

Formatlash. Tartibsiz yozilgan BUILD faylni ko'ramiz:

# BUILD.bazel (tartibsiz)
load("@rules_swift//swift:swift_binary.bzl","swift_binary")
swift_binary(name="salom",srcs=["main.swift"],deps=["//greeter"])

buildifier --mode=diff nima o'zgarishini ko'rsatadi (hech narsa o'zgartirmay):

-load("@rules_swift//swift:swift_binary.bzl","swift_binary")
-swift_binary(name="salom",srcs=["main.swift"],deps=["//greeter"])
+load("@rules_swift//swift:swift_binary.bzl", "swift_binary")
+
+swift_binary(
+    name = "salom",
+    srcs = ["main.swift"],
+    deps = ["//greeter"],
+)

buildifier BUILD.bazel (argumentsiz) esa faylni joyida formatlaydi: bo'sh joylar, har atribut alohida qatorga, standart ko'rinish.

deps'ni avtomatik tartiblaydi. BUILD fayllarda buildifier ro'yxatlarni (masalan deps) alifbo tartibida saralaydi:

     deps = [
-        "//zebra",
         "//apple",
         "//mango",
+        "//zebra",
     ],

Bu merge-conflict'larni kamaytiradi: hamma deps'ni bir xil tartibda saqlasa, ikki kishi bir vaqtda dependency qo'shganda to'qnashuv kamroq bo'ladi.

Lint. buildifier -lint=warn shubhali naqshlarni topadi. Masalan .bzl faylda bitta o'zgaruvchini ikki marta e'lon qilsangiz:

buildifier -lint=warn lintbad.bazel
lintbad.bazel:10: redefined-variable: Variable "x" has already been defined.
Redefining a global value is discouraged and will be forbidden in the future.
Consider using a new variable instead.
(https://github.com/bazel-contrib/buildtools/blob/main/WARNINGS.md#redefined-variable)

Har warning'da tushuntirish va hujjat havolasi bor. CI'da buildifier --mode=check qo'ysangiz, formatlanmagan BUILD fayl build'ni to'xtatadi — bu kodni toza saqlashning amaliy usuli.

Editor: VS Code

VS Code'da Bazel kengaytmasini (BazelBuild.vscode-bazel) o'rnating. U BUILD.bazel va .bzl fayllarga sintaksis ta'kidlash, target'larni ro'yxatda ko'rsatish va Buildifier bilan avtomatik formatlash beradi. Formatlashni saqlanganda ishga tushirish uchun .vscode/settings.json:

{
  "[starlark]": {
    "editor.defaultFormatter": "BazelBuild.vscode-bazel",
    "editor.formatOnSave": true
  }
}

Amaliy mashqlar {#mashqlar}

Bu mashqlarni o'z mashinangizda bajaring — Bazel'ni faqat o'qib emas, qo'l bilan yozib o'rganadigan tizim.

  1. O'rnatish va tekshirish. brew install bazelisk qiling, bo'sh papka ochib ichida .bazelversion yarating (9.3.0), bazel --version ishga tushiring. Natija bazel 9.3.0 chiqishi kerak. Keyin .bazelversion'ni 9.x ga o'zgartirib, bazel --version qayta ishga tushiring — Bazelisk eng yangi 9.x liniyasini tanlashini ko'ring.
  2. "Salom, Bazel!" noldan. Darsdagi to'rt faylni (.bazelversion, MODULE.bazel, BUILD.bazel, main.swift) o'zingiz yozing. bazel run //:salom bilan ishga tushiring. Keyin main.swift'da matnni o'zingiznikiga o'zgartirib, qayta run qiling.
  3. O'z raqamlaringizni o'lchang. Quyidagi jadvalni o'z mashinangizdagi natijalar bilan to'ldiring (INFO: Elapsed time qatoridan oling):
Build turiBuyruqVaqt
Sovuq (birinchi)bazel build //:salom (bo'sh workspace)?
No-op (ikkinchi)yana bazel build //:salom?
Inkrementalmain.swift'ni o'zgartirib build?

Sizning raqamlaringiz biznikidan farq qilishi normal — mashina va kesh holatiga bog'liq.

  1. Ikkinchi modul. greeter/ papkasida swift_library yarating, salom binary'sini unga deps orqali bog'lang, import Greeter bilan ishlating. Keyin bazel query 'deps(//:salom)' bilan bog'liqlik grafigini ko'ring. greeter/Greeter.swift'ni o'zgartiring va qayta build qiling — nechta action qayta bajarilganini kuzating.
  2. **⭐ .bazelrc konfiguratsiyasi.** .bazelrc'da build:release -c opt guruhini va try-import %workspace%/user.bazelrc qatorini yozing. user.bazelrc'ni yaratib ichiga build --jobs=4 yozing. bazel build //:salom --config=release --announce_rc bilan qaysi flag qayerdan kelayotganini tekshiring. user.bazelrc'ni .gitignore'ga qo'shing.
  3. ⭐ Buildifier. brew install buildifier qiling. BUILD.bazel'ni ataylab tartibsiz yozing (bo'sh joysiz, bir qatorda), buildifier --mode=diff BUILD.bazel bilan o'zgarishlarni ko'ring, keyin buildifier BUILD.bazel bilan formatlang. deps ro'yxatini teskari tartibda yozib, buildifier uni qanday saralashini ko'ring.

O'zingizni tekshiring {#checklist}

  • [ ] Nega to'g'ridan-to'g'ri Bazel emas, Bazelisk o'rnatiladi — tushuntira olasizmi?
  • [ ] .bazelversion nima vazifa bajaradi va nega aniq versiya (9.3.0) yoziladi, latest emas?
  • [ ] Minimal workspace'dagi MODULE.bazel va BUILD.bazel farqini ayta olasizmi?
  • [ ] bazel build va bazel run farqi nima?
  • [ ] Nega birinchi build 44 soniya, ikkinchisi bir soniyadan kam — client/server bilan tushuntira olasizmi?
  • [ ] bazel-bin nima — oddiy papkami yoki symlink? U qayerga ishora qiladi?
  • [ ] .bazelrc'dagi common, build, test qatorlari farqi va --config nima uchun kerak?
  • [ ] Qaysi fayllar git'ga commit qilinadi, qaysilari .gitignore'ga ketadi?
  • [ ] bazel clean va bazel clean --expunge farqi, va nega clean'ni refleks sifatida ishlatmaslik kerak?

Xulosa {#xulosa}

  • Bazelisk — Bazel'ni o'rnatishning to'g'ri yo'li. .bazelversion fayli jamoadagi hamma bir xil Bazel versiyasini ishlatishini ta'minlaydi; aniq versiya (9.3.0) pinlang, latest emas.
  • Minimal workspace — to'rt fayl: .bazelversion (versiya), MODULE.bazel (modul + bazel_dep), BUILD.bazel (target'lar), manba kod. Bazel 9'da faqat Bzlmod (MODULE.bazel) ishlatiladi — WORKSPACE butunlay olib tashlangan.
  • swift_binary va swift_library — rules_swift'dan load() qilinadi. Bazel yadrosida til yo'q; har bir tilni alohida rule to'plami o'rgatadi.
  • Birinchi build sekin (bizda 44.2 s — asosan rules_swift worker'ini kompilyatsiya qilish, bir martalik), ikkinchisi tez (0.16 s), inkremental ham tez (0.35 s). Bu Bazel'ning asosiy va'dasi: o'zgarmaganni qayta qilmaydi.
  • Sababi — client/server arxitekturasi: yengil client uzoq yashovchi JVM server bilan gaplashadi, server build grafigini xotirada saqlaydi. --max_idle_secs serverni qachon o'chishini, bazel shutdown qo'lda to'xtatishni boshqaradi.
  • Bazel hamma narsani output base'da saqlaydi (~/Library/Caches/bazel/...), bazel-bin kabi symlink'lar unga qisqa yo'l beradi — ularni .gitignore'ga qo'ying.
  • .bazelrc — flaglarning yagona manbasi: common/build/test/run bo'limlari, --config guruhlari, shaxsiy sozlamalar uchun try-import.
  • MODULE.bazel.lock'ni commit qiling; bazel info, bazel query, Buildifier — kundalik asboblar. bazel clean'ni ehtiyot bo'lib ishlating, lekin --disk_cache cleandan omon qoladi (bizda clean'dan keyin 1 soniyada tiklandi).
  • Keyingi dars: Bazel 3: Asosiy tushunchalar — workspace, package, target, label, rule, visibility va build graph — bu darsda ishlatgan //:salom, //greeter labellari, visibility va build grafigi aslida qanday ishlashini chuqur o'rganamiz.

Manbalar {#manbalar}

  1. Bazelisk — rasmiy launcher (versiya tanlash tartibi) — USE_BAZEL_VERSION, .bazelversion, qabul qilinadigan yorliqlar.
  2. Bazel release modeli — LTS va rolling — qo'llab-quvvatlash bosqichlari va release kadansi.
  3. Bazel 9.0 blogi (2026-01-20) — Bzlmod har doim yoqilgan, WORKSPACE olib tashlandi, output base macOS'da ko'chdi.
  4. Bazel 9.3.0 release (2026-10-07) — joriy barqaror versiya.
  5. [.bazelrc konfiguratsiya fayllari](https://bazel.build/run/bazelrc) — rc fayl joylari, sintaksis, --config, try-import, meros tartibi.
  6. Bazel client/server implementatsiyasi — server, --max_idle_secs, bazel shutdown.
  7. Output Directory Layout — output base, execroot, symlink'lar, bazel clean vs --expunge.
  8. rules_swift — releases (4.2.1) — joriy versiya, Swift 6.4 moslik.
  9. [rules_swift — swift_binary / swift_library hujjati](https://github.com/bazelbuild/rules_swift/blob/main/doc/rules.md) — rule atributlari va load yo'llari.
  10. Bazel Central Registry (BCR) — bazel_dep modullari manbai.
  11. Buildifier / buildtools — BUILD fayl formatter va linter, warning ro'yxati.
  12. VS Code Bazel kengaytmasi — sintaksis, target ro'yxati, Buildifier integratsiyasi.

Markdown manba

iOS Lessons