# 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](#ornatish)
2. [Birinchi workspace: to'rt fayl](#workspace)
3. [Birinchi build va run — "Salom, Bazel!"](#birinchi-build)
4. [Ikkinchi modul: swift_library qo'shamiz](#swift-library)
5. [Output daraxti: Bazel nima qayerga yozadi](#output-tree)
6. [Client/server: nega ikkinchi build tez](#client-server)
7. [.bazelrc chuqur: flaglarni bir marta yozib qo'yish](#bazelrc)
8. [Kundalik buyruqlar: info, clean, lock, gitignore, Buildifier](#kundalik)
9. [Amaliy mashqlar](#mashqlar)
10. [O'zingizni tekshiring](#checklist)
11. [Xulosa](#xulosa)
12. [Manbalar](#manbalar)

---

## 1. Bazelisk bilan o'rnatish {#ornatish}

Oldingi darsda ([Bazel 1: Bazel nima va nega kerak](/ios-lessons/bazel-01-kirish)) 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)

```bash
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:

```bash
which bazel bazelisk
bazel --version
```

Bizning mashinada natija:

```text
/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:

```text
# .bazelversion
9.3.0
```

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

| Yorliq       | Ma'nosi                                                                |
| ------------ | ---------------------------------------------------------------------- |
| `9.3.0`      | Aynan shu versiya (loyihalar uchun eng yaxshi — takrorlanadigan build) |
| `9.x`        | Shu LTS liniyasining eng yangi release'i (RC'larsiz)                   |
| `9.*`        | Shu liniya, RC'lar bilan birga                                         |
| `latest`     | Eng oxirgi barqaror release                                            |
| `latest-1`   | Undan bitta oldingi                                                    |
| `last_green` | HEAD'dagi oxirgi yashil (sinovdan o'tgan) build                        |
| `rolling`    | Eng 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:

| Versiya   | Holati                          | Izoh                                     |
| --------- | ------------------------------- | ---------------------------------------- |
| **9.3.0** | eng yangi barqaror (2026-10-07) | biz shu bilan ishlaymiz                  |
| 8.8.1     | 8.x LTS liniyasi (2026-09-24)   | oldingi avlod, hali qo'llab-quvvatlanadi |
| 10.0.0rc1 | pre-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:

```text
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`

```text
# .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.

```starlark
# 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 **package**ga aylantiradi va unda **target**lar e'lon qilinadi. Target — Bazel qura oladigan bir narsa: kutubxona, bajariladigan fayl, test. Bizning target — bajariladigan Swift dastur, uni `swift_binary` rule yasaydi.

```starlark
# 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`

```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.](/lessons/images/bazel/bazel_02_workspace_anatomy.svg)

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

```bash
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](/ios-lessons/bazel-03-tushunchalar)), 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:

```text
[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:

```bash
./bazel-bin/salom
```

```text
Salom, Bazel!
```

### `bazel run` — quramiz va ishga tushiramiz

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

```bash
bazel run //:salom
```

```text
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:

```swift
// main.swift
let kim = "Bazel"
print("Salom, \(kim)!")
print("Birinchi build tizimi loyiham ishga tushdi.")
```

```bash
bazel build //:salom
```

```text
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:

```text
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

```swift
// 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

```starlark
# 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 mumkin**ligini belgilaydi. `public` — hamma. Visibility — Bazel'ning arxitektura qoidalarini majburlash mexanizmi (to'liq [Bazel 3](/ios-lessons/bazel-03-tushunchalar)da); hozircha "boshqa papkadagi target shundan foydalana olsin" deb qo'yamiz.

### Binary'ni kutubxonaga bog'laymiz

Root `BUILD.bazel`'ga `deps` qo'shamiz:

```starlark
# 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

```swift
// main.swift
import Greeter

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

Build va run:

```bash
bazel run //:salom
```

```text
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:

```bash
bazel query 'deps(//:salom)'
```

Natijaning loyihamizga tegishli qismi (tashqi modullar chiqarib tashlangan):

```text
//: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:

```bash
ls -la
```

```text
$ 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, **symlink**lar (`->` 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:

```bash
bazel info output_base
bazel info execution_root
bazel info bazel-bin
```

Bizning mashinada:

```text
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):

```text
~/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:

| Symlink          | Ishora qiladi        | Nima uchun                                         |
| ---------------- | -------------------- | -------------------------------------------------- |
| `bazel-bin`      | `.../bin`            | build qilingan binary'lar (`bazel-bin/salom`)      |
| `bazel-out`      | `.../bazel-out`      | barcha output (bin, genfiles, testlogs)            |
| `bazel-testlogs` | `.../testlogs`       | test log'lari (keyingi darsda)                     |
| `bazel-<dir>`    | `.../execroot/_main` | execution 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.](/lessons/images/bazel/bazel_02_client_server.svg)

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:

```bash
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:

```bash
# 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:

```bash
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:

```text
# ~/.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.

```text
# .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.

```text
# .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
```

```bash
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`.

```text
# .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:

| Flag                   | Nima qiladi                                                             |
| ---------------------- | ----------------------------------------------------------------------- |
| `-c fastbuild`         | Standart rejim: optimizatsiyasiz, tez kompilyatsiya (kundalik ish)      |
| `-c dbg`               | Debug ma'lumotlari bilan (breakpoint, LLDB)                             |
| `-c opt`               | Optimallashtirilgan (reliz, performance test)                           |
| `--disk_cache=<yo'l>`  | Build natijalarini diskda keshlash (workspace'lar orasida bo'lishiladi) |
| `--jobs=N`             | Parallel action soni (standart — CPU yadrolari soni)                    |
| `--keep_going` / `-k`  | Bitta target sinsa ham qolganini qurishda davom etish                   |
| `--verbose_failures`   | Singan action'ning to'liq buyruq qatorini ko'rsatish                    |
| `-s` / `--subcommands` | Har bir action'ning aniq buyruq qatorini chop etish                     |
| `--announce_rc`        | Qaysi 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:

```bash
bazel build //:salom --announce_rc
```

```text
  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:

```bash
bazel build //greeter:greeter -s
```

Chiqishning modulni kompilyatsiya qiladigan qismi (qisqartirilgan):

```text
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:

```bash
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
```

```text
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:

```bash
bazel clean
bazel build //:salom
```

```text
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 `clean`dan 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:

```text
# .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).

```bash
brew install buildifier
```

Bizning mashinada Homebrew `buildifier` 10.1.0'ni o'rnatdi.

**Formatlash.** Tartibsiz yozilgan BUILD faylni ko'ramiz:

```starlark
# 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):

```text
-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:

```text
     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:

```bash
buildifier -lint=warn lintbad.bazel
```

```text
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`:

```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 turi       | Buyruq                                   | Vaqt |
   | ---------------- | ---------------------------------------- | ---- |
   | Sovuq (birinchi) | `bazel build //:salom` (bo'sh workspace) | ?    |
   | No-op (ikkinchi) | yana `bazel build //:salom`              | ?    |
   | Inkremental      | `main.swift`'ni o'zgartirib build        | ?    |

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

4. **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.

5. **⭐ `.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.

6. **⭐ 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` `clean`dan omon qoladi (bizda clean'dan keyin 1 soniyada tiklandi).
- **Keyingi dars:** [Bazel 3: Asosiy tushunchalar — workspace, package, target, label, rule, visibility va build graph](/ios-lessons/bazel-03-tushunchalar) — 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)](https://github.com/bazelbuild/bazelisk) — `USE_BAZEL_VERSION`, `.bazelversion`, qabul qilinadigan yorliqlar.
2. [Bazel release modeli — LTS va rolling](https://bazel.build/release) — qo'llab-quvvatlash bosqichlari va release kadansi.
3. [Bazel 9.0 blogi (2026-01-20)](https://blog.bazel.build/2026/01/20/bazel-9.html) — Bzlmod har doim yoqilgan, WORKSPACE olib tashlandi, output base macOS'da ko'chdi.
4. [Bazel 9.3.0 release (2026-10-07)](https://github.com/bazelbuild/bazel/releases/tag/9.3.0) — 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](https://bazel.build/run/client-server) — server, `--max_idle_secs`, `bazel shutdown`.
7. [Output Directory Layout](https://bazel.build/remote/output-directories) — output base, execroot, symlink'lar, `bazel clean` vs `--expunge`.
8. [rules_swift — releases (4.2.1)](https://github.com/bazelbuild/rules_swift/releases) — 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)](https://bcr.bazel.build) — `bazel_dep` modullari manbai.
11. [Buildifier / buildtools](https://github.com/bazel-contrib/buildtools) — BUILD fayl formatter va linter, warning ro'yxati.
12. [VS Code Bazel kengaytmasi](https://marketplace.visualstudio.com/items?itemName=BazelBuild.vscode-bazel) — sintaksis, target ro'yxati, Buildifier integratsiyasi.
