# Bazel 3: Asosiy tushunchalar — workspace, package, target, label, rule, visibility va build graph

> **Holat:** 2026-yil oktabr. Bu darsda Bazel'ning asosiy lug'atini — repository/workspace, package chegaralari, target (rule/file/generated), label va target pattern'lar, rule va attribute'lar, `glob()`, visibility, build'ning uch bosqichi (loading, analysis, execution), Skyframe, action graph, sandboxing hamda `bazel query`/`cquery`/`aquery` — bitta 3-paketli macOS workspace misolida o'rganamiz. Barcha kod va o'lchovlar Bazel 9.3.0 (Bazelisk 1.29.0), rules_swift 4.2.1, apple_support 2.10.1 va Xcode 27.1 bilan Apple M4 Pro (12 core, 24 GB) kompyuterida tekshirilgan.

> **Bu darsdan keyin siz:** har qanday BUILD faylni o'qib, "bu yerda nechta target bor, ularning manzili nima, kim kimga bog'liq, nima qachon qayta quriladi?" degan savollarga aniq javob bera olasiz — va `bazel query` bilan buni o'zingiz tekshira olasiz.

- Repository, workspace va package o'rtasidagi farqni, package chegarasini (BUILD fayli) va `glob()` nega chegaradan o'tmasligini tushunasiz.
- Label sintaksisini (`@repo//package:target`) va barcha qisqartmalarni (`//Core`, `:name`, file target) hamda target pattern'larni (`//...`, `//Core/...`, `:all`, istisno) erkin yozasiz.
- Rule va uning attribute'larini (`srcs`, `deps`, `data`, `visibility`, `testonly`) va visibility'ni arxitektura quroli sifatida ishlatasiz — haqiqiy visibility xatosini o'zingiz chiqarib ko'rasiz.
- Build'ning uch bosqichini, Skyframe nega ikkinchi build'ni tezlashtirishini, action graph va sandbox nega e'lon qilinmagan input'ni ushlab qolishini bilasiz.
- `bazel query`, `cquery` va `aquery` bilan target grafini, konfiguratsiyani va haqiqiy `swiftc` buyruq satrini ko'rasiz.

## Mundarija

1. [Nega bu tushunchalar kerak](#nega-kerak)
2. [Repository, workspace va package](#workspace-package)
3. [Target: rule, file va generated](#target)
4. [Label: har bir target'ning manzili](#label)
5. [Rule va attribute'lar](#rule-attribute)
6. [glob() va package chegaralari](#glob)
7. [Visibility: arxitekturani majburlash](#visibility)
8. [Build'ning uch bosqichi va Skyframe](#uch-bosqich)
9. [Action graph va sandboxing](#action-graph)
10. [bazel query, cquery va aquery](#query)
11. [Amaliy mashqlar](#mashqlar)
12. [O'zingizni tekshiring](#checklist)
13. [Xulosa](#xulosa)
14. [Manbalar](#manbalar)

---

## 1. Nega bu tushunchalar kerak {#nega-kerak}

[Bazel 2](/ios-lessons/bazel-02-ornatish) darsida siz bitta paketli "Salom, Bazel!" workspace'ini qurdingiz va `bazel build` ishlaganini ko'rdingiz. U yerda hammasi "shunchaki ishladi". Lekin haqiqiy loyihada yuzlab target, o'nlab modul va murakkab bog'liqliklar bo'ladi. O'shanda "ishladi" yetarli emas — sizga **model** kerak: kod qanday tashkil qilinadi, target'lar qanday manzillanadi, nima qachon qayta quriladi.

Xcode'da bu modelning yarmi yashirin. `project.pbxproj` ichida target'lar, build phase'lar va implicit bog'liqliklar bor, lekin siz ularni to'g'ridan-to'g'ri o'qiy olmaysiz va "agar men bu faylni o'zgartirsam, nima qayta quriladi?" degan savolga ishonchli javob bera olmaysiz. Bazel'da aksincha — **hamma narsa aniq e'lon qilinadi va so'rab olinadi**. Bu darsning oxirida siz shu savolga bir buyruq bilan javob berasiz:

```bash
# "Agar Models modulini o'zgartirsam, nima qayta quriladi?"
bazel query 'rdeps(//..., //Models)'
```

```text
//App:App
//Models:Models
//Services:Services
```

> **🚀 Motivatsiya:** Aynan shu savol — "o'zgarishim nimaga ta'sir qiladi?" — katta jamoalarda CI'ni tezlashtiradigan "faqat ta'sirlanganini build/test qil" strategiyasining poydevori. G'oya oddiy: `git diff` → o'zgargan fayllar → ularga tegishli target'lar → `rdeps` bilan ta'sirlangan target'lar → faqat o'shalarni qur va testla. Gojek jamoasi o'z iOS build'larini Bazel bilan "3 barobar" tezlashtirgani haqida muhandislik maqolasi e'lon qilgan (Gojek Engineering, Medium — [Manbalar](#manbalar)). Biz bu strategiyani [Bazel 11](/ios-lessons/bazel-11-ci-cd) va [Bazel 16](/ios-lessons/bazel-16-loyiha-monorepo) darslarida `bazel-diff` bilan to'liq quramiz — lekin uning "dvigateli" shu darsdagi `query` va build graph.

Bu darsni o'qib chiqqach, BUILD fayl siz uchun sirli emas, balki **o'qiladigan arxitektura xaritasi** bo'ladi.

### Dars davomidagi workspace: `shaharlar`

Butun darsni bitta kichik, lekin haqiqiy ko'p-paketli workspace'da olib boramiz. U uchta package'dan iborat: `//Models` (ma'lumot turlari), `//Services` (biznes mantiq) va `//App` (macOS buyruq qatori dasturi). Mana uning tuzilishi:

```text
shaharlar/
├── .bazelversion          # 9.3.0
├── MODULE.bazel           # modul + bazel_dep (rules_swift, apple_support)
├── .bazelrc               # umumiy flaglar (disk_cache, verbose_failures)
├── BUILD.bazel            # ildiz package (bo'sh)
├── Models/
│   ├── BUILD.bazel        # swift_library "Models"
│   └── City.swift
├── Services/
│   ├── BUILD.bazel        # swift_library "Services" → //Models
│   └── CityService.swift
└── App/
    ├── BUILD.bazel        # swift_binary "App" → //Services
    └── main.swift
```

`MODULE.bazel` [Bazel 2](/ios-lessons/bazel-02-ornatish) dagi kabi — faqat modul nomi va ikkita tashqi rule to'plami:

```starlark
# MODULE.bazel
module(name = "shaharlar", version = "1.0.0")

bazel_dep(name = "apple_support", version = "2.10.1")
bazel_dep(name = "rules_swift", version = "4.2.1")
```

Swift kodi juda sodda — chunki darsning mavzusi Swift emas, balki Bazel tushunchalari. `//Models` bitta ma'lumot turini e'lon qiladi:

```swift
// Models/City.swift
// Bitta shaharni ifodalovchi oddiy ma'lumot turi.
public struct City {
    public let name: String
    public let population: Int
    public let region: String

    public init(name: String, population: Int, region: String) {
        self.name = name
        self.population = population
        self.region = region
    }
}
```

`//Services` `//Models`'ga tayanib, saralash va yig'indi mantig'ini beradi:

```swift
// Services/CityService.swift
import Models

public struct CityService {
    public let cities: [City]

    public init(cities: [City]) {
        self.cities = cities
    }

    // aholisi bo'yicha kamayish tartibida saralaydi
    public func sortedByPopulation() -> [City] {
        cities.sorted { $0.population > $1.population }
    }

    // barcha shaharlar aholisining yig'indisi
    public func totalPopulation() -> Int {
        cities.reduce(0) { $0 + $1.population }
    }
}
```

`//App` esa macOS buyruq qatori dasturi — u `//Services`'ga tayanadi:

```swift
// App/main.swift
import Models
import Services

// Namuna ma'lumotlar (aniq statistik raqamlar emas)
let cities = [
    City(name: "Toshkent", population: 2_900_000, region: "Toshkent"),
    City(name: "Namangan", population: 650_000, region: "Namangan"),
    City(name: "Samarqand", population: 560_000, region: "Samarqand"),
    City(name: "Andijon", population: 450_000, region: "Andijon"),
    City(name: "Buxoro", population: 280_000, region: "Buxoro")
]

let service = CityService(cities: cities)

print("Shaharlar (aholisi bo'yicha):")
for city in service.sortedByPopulation() {
    print("  \(city.name) — \(city.population) kishi")
}
print("Jami: \(service.totalPopulation()) kishi")
```

Har bir package'ning BUILD faylini quyida, tegishli bo'limlarda ochamiz. Hozircha bitta narsani ko'rib qo'yaylik — bu workspace quriladi va ishlaydi:

```bash
bazel run //App
```

```text
Shaharlar (aholisi bo'yicha):
  Toshkent — 2900000 kishi
  Namangan — 650000 kishi
  Samarqand — 560000 kishi
  Andijon — 450000 kishi
  Buxoro — 280000 kishi
Jami: 4840000 kishi
```

Endi shu `//App`, `//Services`, `//Models` degan nomlar aslida nima ekanligini qism-qismga ajratamiz.

---

## 2. Repository, workspace va package {#workspace-package}

Bazel kodni uch darajali ierarxiyada ko'radi: **repository → package → target**. Bu uchta so'zni ko'pincha chalkashtirishadi, shuning uchun har birini aniq ta'riflaymiz (manba: Bazel rasmiy hujjatlari, `concepts/build-ref`).

### Repository (repo)

**Repository** — ildizida chegara belgisi fayli bo'lgan papkalar daraxti. Bazel 9'da bu belgi `MODULE.bazel` (yoki `REPO.bazel`; eski kontekstda `WORKSPACE`). Bizning `shaharlar/` papkamiz ildizida `MODULE.bazel` bor — demak u repository.

Hozirgi buyruq ishlayotgan repo **main repo** deyiladi. Qolgan (tashqi) repo'lar — masalan `rules_swift`, `apple_support` — repo rule'lar orqali aniqlanadi va ular ham build'ga qo'shiladi.

> **🧠 Esda tuting:** Bazel 9.0'da eski `WORKSPACE` mexanizmi butunlay olib tashlangan — endi bog'liqliklar faqat `MODULE.bazel` (Bzlmod) orqali e'lon qilinadi, `--enable_workspace` esa hech narsa qilmaydigan ("no-op") flagga aylangan (manba: Bazel 9.0 release notes, [Manbalar](#manbalar)). Shuning uchun eski darsliklardagi `WORKSPACE` fayli bizda umuman yo'q.

### Workspace

**Workspace** — bitta main repo'dan ishga tushirilgan barcha Bazel buyruqlari bo'lishadigan muhit. U main repo'ni va barcha aniqlangan tashqi repo'larni o'z ichiga oladi. Tarixan "repository" va "workspace" so'zlari bir-birining o'rnida ishlatilib kelingan, shuning uchun amalda ko'pchilik "workspace" deganda main repo'ni nazarda tutadi — biz ham shunday qilamiz.

### Package

**Package** — repository ichidagi kodni tashkil qilishning asosiy birligi. Ta'rif juda aniq:

> Package — ichida `BUILD` (yoki `BUILD.bazel`) fayli bo'lgan papka. Package o'z papkasidagi barcha fayllarni **va** quyidagi barcha papkalarni o'z ichiga oladi — faqat ichida o'zining `BUILD` fayli bo'lgan papkalardan tashqari.

Shu ta'rifdan juda muhim xulosa chiqadi: **hech bir fayl ikkita package'ga tegishli bo'la olmaydi.** BUILD fayli — bu chegara. Qaerda yangi BUILD fayli paydo bo'lsa, o'sha yerda yangi package boshlanadi.

Bizning workspace'da to'rtta joyda BUILD fayli bor: ildizda, `Models/`, `Services/` va `App/` da. Demak to'rtta package. Buni o'zimiz tekshiramiz:

```bash
bazel query //... --output package
```

```text
App
Models
Services
```

Bo'sh ildiz package ro'yxatda yo'q — chunki unda birorta ham target yo'q, `--output package` esa faqat target'i bor package'larni ko'rsatadi. `BUILD.bazel` nomi `BUILD`'dan ustun turadi (ikkalasi ham bo'lsa). Ildiz package'ni biz ataylab bo'sh qoldirdik — bu Bazel hujjatlari tavsiya qiladigan amaliyot: shunda barcha ma'noli package'lar tavsiflovchi nomga ega bo'ladi (`Models`, `Services`, `App`), ildiz esa faqat workspace chegarasini belgilaydi.

> **💡 Pro tip:** Package ≠ papka. Papka — bu fayl tizimidagi tushuncha. Package — bu BUILD fayli bilan belgilangan Bazel tushunchasi. `Models/` papkasi `Models/Geo/` papkasini o'z ichiga oladi, lekin agar `Models/Geo/` da o'z BUILD fayli bo'lsa, u alohida package (`//Models/Geo`) bo'ladi va `//Models` package'iga kirmaydi. Buni [6-bo'limda](#glob) `glob()` bilan amalda ko'ramiz.

---

## 3. Target: rule, file va generated {#target}

Package — bu **target**lar uchun idish. Target'lar package'ning BUILD faylida aniqlanadi. Ularning ikki asosiy turi bor: **file**lar va **rule**lar.

### File target'lar

File target ikki xil: **source file** (odam yozadigan va repo'ga commit qilinadigan fayl, masalan `City.swift`) va **generated file** (boshqa rule chiqaradigan, commit qilinmaydigan fayl, masalan kompilyator chiqargan `Models.swiftmodule`).

### Rule target'lar

**Rule** target rule chaqiruvi bilan e'lon qilinadi va bir to'plam input'ni bir to'plam output'ga bog'laydi. `swift_library`, `swift_binary`, `genrule` — bularning hammasi rule. Rule target'ning input'i source file bo'lishi mumkin, lekin boshqa rule'ning output'i ham bo'lishi mumkin — aynan shundan **bog'liqlik grafi** tug'iladi.

Bizning workspace'dagi barcha target'larni, ularning turi bilan birga, bitta buyruq bilan ko'rsak bo'ladi:

```bash
bazel query //... --output label_kind
```

```text
swift_binary rule //App:App
swift_library rule //Models:Models
swift_library rule //Services:Services
```

Bu uchta **rule target**. Ularning har biri ortida yashiringan **file target**lar ham bor — masalan source fayllar. Ularni `deps` ichida ko'rish uchun `deps` so'rovidan foydalanamiz (buni [10-bo'limda](#query) chuqur o'rganamiz):

```bash
bazel query 'deps(//App)' --noimplicit_deps
```

```text
//App:App
//App:main.swift
//Models:City.swift
//Models:Models
//Services:CityService.swift
//Services:Services
```

E'tibor bering: `//App:main.swift`, `//Models:City.swift`, `//Services:CityService.swift` — bular **source file target**lar. Ular BUILD faylda alohida e'lon qilinmagan, lekin rule'larning `srcs` ichida ishlatilgani uchun avtomatik target bo'lib qoladi.

> **🧠 Esda tuting:** Rule target va file target o'rtasidagi farq muhim, chunki Bazel ularni bir xil "manzil tizimi" — label bilan ataydi. `//Models:Models` — rule target; `//Models:City.swift` — file target. Ikkalasi ham label, ikkalasi ham bog'liqlik grafining tuguni.

Rule chaqiruvi target yaratganda, o'sha rule chiqaradigan **generated file**lar har doim rule bilan **bir xil package**da bo'ladi — boshqa package'ga fayl "chiqarib bo'lmaydi". Bu qoida build grafini bashorat qilinadigan qiladi.

---

## 4. Label: har bir target'ning manzili {#label}

Har bir target noyob **label** bilan ataladi. Label — bu target'ning to'liq manzili. Uning to'liq (canonical) ko'rinishi uch qismdan iborat:

![Label anatomiyasi: repository, package va target qismlari hamda qisqartmalar jadvali](/lessons/images/bazel/bazel_03_label_anatomy.svg)

Yuqoridagi rasmda `@rules_swift//swift:swift_library` labeli uch bo'lakka ajratilgan: `@rules_swift` — repository, `//swift` — package, `:swift_library` — target. Pastdagi jadval esa qisqartmalarni ko'rsatadi.

### Uch qism

```text
@rules_swift//swift:swift_library
│           │      │
│           │      └─ target nomi (:target)
│           └─ package (repo ildizidan yo'l)
└─ repository nomi (@repo)
```

- **Repository nomi** (`@rules_swift`): qaysi repo. Bitta `@` — bu _apparent_ (ko'rinadigan) repo nomi, kontekstga bog'liq. Ikkita `@@` — bu _canonical_ (yagona) repo nomi, hamma joyda bir xil. Agar repo nomi yozilmasa, label o'z (main) repo'siga ishora qiladi.
- **Package nomi** (`//swift`): repo ildizidan package papkasigacha bo'lgan yo'l. `//` — har doim repo ildizidan boshlanishini bildiradi.
- **Target nomi** (`:swift_library`): BUILD ichidagi `name = "..."` qiymati (rule target), yoki package ichidagi fayl yo'li (file target).

### Qisqartmalar

Amalda label'lar deyarli har doim qisqargan ko'rinishda yoziladi. Uchta asosiy qoida bor va biz ularni o'zimizning workspace'da tekshiramiz:

**1-qoida: package nomi target nomiga teng bo'lsa, target nomi tushib qoladi.** `//Models` — bu aslida `//Models:Models`. Tekshiramiz — ikkala so'rov bir xil javob beradi:

```bash
bazel query //Models
bazel query //Models:Models
```

```text
//Models:Models
//Models:Models
```

**2-qoida: shu package ichida repo va package qismini tashlab, `:target` deb yozsa bo'ladi.** Masalan `App/BUILD.bazel` ichida `:App` — bu `//App:App`.

**3-qoida: file target odatda `:` bilan yoziladi.** `//Models:City.swift` — `Models` package'idagi `City.swift` fayli. (Konvensiya bo'yicha fayl uchun `:` saqlanadi, rule uchun esa ko'pincha tushiriladi — lekin bu faqat o'qish uchun, ma'nosi bir xil.)

> **⚠️ Diqqat:** `//Models` — bu **package emas, target**. Ko'p yangi boshlovchilar `//Models` deb package'ni yoki "Models ichidagi hamma target"ni nazarda tutadi — bu xato. `//Models` har doim `//Models:Models` target'iga teng. "Models package'idagi hamma target" uchun `//Models:all` yoki `//Models:*` yoziladi. Faqat `package_group` va `.bzl` fayllar ichida `//Models` package ma'nosida ishlatiladi.

### Load label'i

BUILD faylining birinchi qatoridagi `load(...)` ham label ishlatadi — lekin u rule target'ga emas, `.bzl` **fayliga** ishora qiladi:

```starlark
# Models/BUILD.bazel (birinchi qator)
load("@rules_swift//swift:swift.bzl", "swift_library")
```

Bu yerda `@rules_swift//swift:swift.bzl` — `rules_swift` repo'sidagi `swift/` package'idagi `swift.bzl` fayli. Undan `swift_library` belgisini (symbol) olib kelamiz. [Bazel 2](/ios-lessons/bazel-02-ornatish) da ko'rganimizdek, `swift_library`/`swift_binary` Bazel'ning o'zida emas — ular `rules_swift`'dan `load()` bilan keltiriladi.

### Target pattern'lar: bir vaqtda ko'p target

Bitta label bitta target'ni ko'rsatadi. **Target pattern** esa bir to'plam target'ni ko'rsatadi — build va query buyruqlarida juda ko'p ishlatiladi:

| Pattern                      | Ma'nosi                              | `shaharlar`'da natija                                 |
| ---------------------------- | ------------------------------------ | ----------------------------------------------------- |
| `//...`                      | butun repo'dagi hamma target         | `//App:App`, `//Models:Models`, `//Services:Services` |
| `//Services/...`             | `Services` va uning ost-package'lari | `//Services:Services`                                 |
| `//App:all` (yoki `//App:*`) | bitta package ichidagi hamma target  | `//App:App`                                           |
| `//... except //Models:all`  | istisno (`-` yoki `except`)          | `//App:App`, `//Services:Services`                    |

Haqiqiy natijalarni o'zimiz ko'ramiz:

```bash
bazel query '//...'
```

```text
//App:App
//Models:Models
//Services:Services
```

```bash
bazel query '//... except //Models:all'
```

```text
//App:App
//Services:Services
```

> **💡 Pro tip:** `bazel build //...` — "hammasini qur". `bazel test //...` — "hamma testni ishga tushir". `bazel build //Services/...` — "faqat Services subtree'sini qur". Bu pattern'lar CI'da va kundalik ishda eng ko'p ishlatiladigan narsa. `//...` ildizdan boshlab, `//Services/...` esa faqat shu papkadan pastdagi package'larni qamrab oladi.

---

## 5. Rule va attribute'lar {#rule-attribute}

Endi BUILD fayllarning ichiga kiramiz. Har bir rule chaqiruvi — bu `name` va bir nechta **attribute** bilan target yaratish. Mana `//Models` package'ining to'liq BUILD fayli:

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

swift_library(
    name = "Models",
    srcs = glob(["*.swift"]),
    module_name = "Models",
    visibility = ["//visibility:public"],
)
```

Bu yerda to'rtta attribute bor. Ularning ba'zilari **hamma rule**da uchraydi (umumiy attribute'lar), ba'zilari esa rule'ga xos (`swift_library`'ning `module_name`'i). Keling, eng muhim umumiy attribute'larni ko'rib chiqamiz.

### `srcs` — manba fayllar

`srcs` — rule bevosita kompilyatsiya qiladigan source (yoki generated) fayllar ro'yxati. `swift_library` uchun bu `.swift` fayllar. Biz `glob(["*.swift"])` ishlatdik — u package ichidagi barcha `.swift` fayllarni oladi (`glob()` haqida [keyingi bo'limda](#glob) batafsil).

Tur jihatidan `srcs` — bu "label ro'yxati": har bir element — rule'ga input bo'lgan target label'i. `swift_library`'da `srcs` **majburiy** (manba: rules_swift 4.2.1 `rules.md`).

### `deps` — modul bog'liqliklari

`deps` — alohida kompilyatsiya qilingan modullarga bog'liqlik. `//Services` `//Models`'ga `deps` orqali bog'lanadi:

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

swift_library(
    name = "Services",
    srcs = glob(["*.swift"]),
    module_name = "Services",
    visibility = ["//visibility:public"],
    deps = ["//Models"],
)
```

`deps = ["//Models"]` — bu "Services'ni qurish uchun avval Models'ni qur, uning `.swiftmodule`'ini va simvollarini menga ber" degani. rules_swift hujjatlariga ko'ra, `swift_library`'ning `deps`'iga `swift_library` (yoki `SwiftInfo` tarqatadigan boshqa target), `cc_library` va `objc_library` kirishi mumkin.

Va `//App` — bu `swift_binary`, u `//Services`'ga bog'liq:

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

swift_binary(
    name = "App",
    srcs = glob(["*.swift"]),
    deps = ["//Services"],
)
```

> **🧠 Esda tuting:** `swift_binary` Apple platformasida **bitta arxitekturali** ijro etiluvchi fayl chiqaradi va asosan lokal mashinada ishlaydigan Swift vositalari (CLI) uchun mo'ljallangan (manba: rules_swift `rules.md`). iOS ilovasi yoki universal binary kerak bo'lsa, [Bazel 5](/ios-lessons/bazel-05-ios-ilova) dagi `rules_apple`'ning `ios_application`'i ishlatiladi. Shuning uchun bizning `//App` — macOS CLI.

### `srcs` vs `deps` vs `data` — farqi nimada?

Ko'p rule'da uchta umumiy bog'liqlik attribute'i bor va ularni ajratish muhim (manba: `concepts/dependencies`):

| Attribute | Nima                                                                        | Qachon kerak         |
| --------- | --------------------------------------------------------------------------- | -------------------- |
| `srcs`    | rule bevosita kompilyatsiya/qayta ishlaydigan fayllar                       | build vaqtida        |
| `deps`    | alohida kompilyatsiya qilingan modullar (header, simvol, kutubxona beradi)  | build vaqtida        |
| `data`    | ishga tushirish paytida kerak bo'ladigan fayllar (build'ga ta'sir qilmaydi) | **run/test vaqtida** |

`data` nozik nuqta: unga qo'yilgan fayllar target'ning `runfiles` papkasida paydo bo'ladi va dastur/test ishlaganda ochiladi. Test faqat `data`'da e'lon qilingan fayllarni ko'ra oladi (bu [Bazel 6](/ios-lessons/bazel-06-testlar) da muhim bo'ladi).

### `module_name`, `visibility`, `testonly`

- **`module_name`** (`swift_library`/`swift_binary`'ga xos): Swift modulining nomi. Biz `"Models"` deb aniq berdik, shunda `import Models` ishlaydi. Agar berilmasa, Bazel uni label'dan hisoblab chiqaradi — `//` ni olib tashlab, `/`, `:` va boshqa belgilarni `_` ga almashtirib (manba: rules_swift `rules.md`).
- **`visibility`** (hamma rule'da): bu target'ni kim `deps`'ida ishlatishi mumkinligini belgilaydi. [7-bo'limda](#visibility) chuqur ko'ramiz.
- **`testonly`** (hamma rule'da): `True` bo'lsa, bu target'ni faqat boshqa test yoki `testonly` target ishlatishi mumkin — test yordamchi kodini xatolik bilan production'ga qo'shib yuborishdan saqlaydi.

> **💡 Pro tip:** Attribute'lar — lug'at (dictionary): kalit (nom) → tipik qiymat. Har bir attribute'ning aniq turi bor: `string`, `label`, `label ro'yxati`, `string ro'yxati` va h.k. Qaysi rule'da qaysi attribute borligini bilish uchun rules_swift/rules_apple hujjatlariga yoki `bazel query --output=build //Models:Models` ga qarang — oxirgisi target'ning barcha haqiqiy attribute qiymatlarini ko'rsatadi.

---

## 6. glob() va package chegaralari {#glob}

`glob()` — BUILD faylda fayllarni qo'lda sanab o'tirmaslik uchun ishlatiladigan funksiya. `glob(["*.swift"])` package ichidagi barcha `.swift` fayllarni oladi. U **loading** bosqichida ishlaydi (buni [8-bo'limda](#uch-bosqich) ko'ramiz).

Lekin `glob()`ning bitta muhim va ko'pincha e'tibordan chetda qoladigan xususiyati bor: **u package chegarasidan hech qachon o'tmaydi.** Buni o'z ko'zimiz bilan ko'ramiz. `//Models` package'iga yangi ost-papka qo'shamiz — `Geo/` — va unga **o'z BUILD faylini** beramiz:

```text
Models/
├── BUILD.bazel
├── City.swift
└── Geo/
    ├── BUILD.bazel          # ← yangi: Geo'ni ALOHIDA package qiladi
    └── Coordinate.swift
```

```swift
// Models/Geo/Coordinate.swift
public struct Coordinate {
    public let lat: Double
    public let lon: Double
    public init(lat: Double, lon: Double) { self.lat = lat; self.lon = lon }
}
```

```starlark
# Models/Geo/BUILD.bazel
load("@rules_swift//swift:swift.bzl", "swift_library")

swift_library(
    name = "Geo",
    srcs = glob(["*.swift"]),
    module_name = "Geo",
    visibility = ["//visibility:public"],
)
```

`Models/Geo/` da BUILD fayli paydo bo'lishi bilanoq, u alohida package — `//Models/Geo` — ga aylanadi. `Coordinate.swift` endi `//Models` emas, `//Models/Geo` package'iga tegishli. Tekshiramiz:

```bash
bazel query 'Models/Geo/Coordinate.swift'
```

```text
//Models/Geo:Coordinate.swift
```

```bash
bazel query 'Models/...' --output package
```

```text
Models
Models/Geo
```

Endi eng muhim test. `//Models`'ning `srcs`'i `glob(["*.swift"])`. Nazariy jihatdan `*.swift` faqat yuqori darajani oladi. Lekin uni **rekursiv** `glob(["**/*.swift"])` ga o'zgartirsak-chi — u `Geo/Coordinate.swift`'ni oladimi? Ko'pchilik "ha, `**` hamma narsani oladi" deb o'ylaydi. Haqiqat esa boshqacha:

```bash
# Models/BUILD.bazel da: srcs = glob(["**/*.swift"])
bazel query 'kind("source file", deps(//Models))'
```

```text
//Models:City.swift
```

`Coordinate.swift` **yo'q**. `**` bo'lishiga qaramay, `glob()` `Models/Geo/` package'iga kirmadi — chunki u alohida package. Eng xavflisi: build **xatosiz** o'tadi, shunchaki `Coordinate.swift` jim turib qoladi:

```bash
bazel build //Models    # srcs = glob(["**/*.swift"]) bilan
```

```text
INFO: Build completed successfully, 1 total action
```

> **⚠️ Diqqat:** Bu — Bazel'ga yangi o'tganlar tez-tez tushadigan tuzoq. Siz kodni ost-papkaga ko'chirasiz, lekin uning o'z BUILD faylini unutmaysiz (yoki yaratmaysiz) — natijada `glob()` o'sha fayllarni **jimgina chetlab o'tadi** va "nega mening yangi klasim topilmayapti?" degan chalkashlik boshlanadi. Qoida oddiy: **har bir package faqat o'z fayllarini `glob` qiladi.** Ost-package kerak bo'lsa, uni `deps` orqali bog'lang, fayllarni emas.

> **🧠 Esda tuting:** `glob()`ning bu xatti-harakati bejiz emas — u "hech bir fayl ikkita package'ga tegishli bo'la olmaydi" qoidasini majburlaydi. Agar `//Models`'ning glob'i `Geo/` fayllarini ham olsa, `Coordinate.swift` ikkita package'da (`//Models` va `//Models/Geo`) bo'lib qolardi — bu esa build grafini chalkashtirar edi.

Biz `//Models` ni asl holiga — `glob(["*.swift"])` ga — qaytaramiz va `//Models/Geo` ni mustaqil package sifatida qoldiramiz.

---

## 7. Visibility: arxitekturani majburlash {#visibility}

Sukut bo'yicha har bir target **private** (shaxsiy) — ya'ni uni faqat o'sha package ichidagi target'lar ishlatishi mumkin (agar package'da `default_visibility` berilmagan bo'lsa). Boshqa package'dan foydalanish uchun target o'zini ochib berishi kerak — bu `visibility` attribute'i orqali qilinadi.

### Visibility formati

`visibility` — label ro'yxati. Har bir element quyidagi shakllardan biri (manba: `concepts/visibility`):

| Shakl                         | Ma'nosi                                        |
| ----------------------------- | ---------------------------------------------- |
| `"//visibility:public"`       | hamma package ko'ra oladi                      |
| `"//visibility:private"`      | faqat shu package (sukut bo'yicha)             |
| `"//foo/bar:__pkg__"`         | faqat `//foo/bar` package (ost-package'larsiz) |
| `"//foo/bar:__subpackages__"` | `//foo/bar` va uning barcha ost-package'lari   |
| `"//some_pkg:my_group"`       | `package_group` ichidagi barcha package'lar    |

### Haqiqiy visibility xatosi

Buni gapirib emas, **chiqarib** ko'ramiz. `//Models` ni private qilamiz va `//Services` ni qurishga urinamiz (`Services` `//Models`'ga bog'liq):

```starlark
# Models/BUILD.bazel — vaqtincha private qilamiz
swift_library(
    name = "Models",
    srcs = glob(["*.swift"]),
    module_name = "Models",
    visibility = ["//visibility:private"],   # ← faqat //Models o'zi
)
```

```bash
bazel build //Services
```

```text
ERROR: .../Services/BUILD.bazel:3:14: in swift_library rule //Services:Services:
Visibility error:
target '//Models:Models' is not visible from
target '//Services:Services'
Recommendation: modify the visibility declaration if you think the dependency
is legitimate. For more info see https://bazel.build/concepts/visibility
ERROR: .../Services/BUILD.bazel:3:14: Analysis of target '//Services:Services'
(config: 2d89340) failed
ERROR: Analysis of target '//Services:Services' failed; build aborted
```

Ikki narsaga e'tibor bering. Birinchidan, xato aniq: `//Models:Models` `//Services:Services`'dan **ko'rinmaydi**. Ikkinchidan — va bu muhim — xato **Analysis** bosqichida yuz berdi (`Analysis of target ... failed`). Visibility hech qachon kompilyatsiyagacha yetib bormaydi; u analysis'da, ya'ni haqiqiy ish boshlanishidan oldin tekshiriladi. Bu bizni [keyingi bo'limdagi](#uch-bosqich) uch bosqich mavzusiga olib keladi.

### Visibility — arxitektura quroli

Visibility'ni shunchaki "public/private" deb tushunmang. U bilan siz **arxitekturani majburlashingiz** mumkin: "App faqat Services orqali ishlasin, Models'ga to'g'ridan-to'g'ri tegmasin". Buni amalda ko'ramiz. `//Models` ni faqat `//Services` package'iga ochamiz:

```starlark
# Models/BUILD.bazel
swift_library(
    name = "Models",
    srcs = glob(["*.swift"]),
    module_name = "Models",
    visibility = ["//Services:__pkg__"],   # ← faqat Services package
)
```

Endi `//Services` ham, `//App` ham quriladi:

```bash
bazel build //Services    # Services — ruxsat etilgan package
bazel build //App         # App — Services orqali, Models'ga to'g'ridan-to'g'ri tegmaydi
```

```text
INFO: Build completed successfully, 1 total action
INFO: Build completed successfully, 1 total action
```

`//App` ishladi, chunki u `//Models`'ga **to'g'ridan-to'g'ri** bog'lanmagan — u `//Services`'ga bog'langan, Services esa Models'ga. Visibility faqat **bevosita** `deps`'ni tekshiradi. Endi `//App`'ga Models'ga **to'g'ridan-to'g'ri** bog'lanishni qo'shsak:

```starlark
# App/BUILD.bazel — ataylab Models'ga to'g'ridan-to'g'ri bog'lanamiz
swift_binary(
    name = "App",
    srcs = glob(["*.swift"]),
    deps = ["//Services", "//Models"],   # ← //Models endi bevosita dep
)
```

```bash
bazel build //App
```

```text
ERROR: .../App/BUILD.bazel:3:13: in swift_binary rule //App:App:
Visibility error:
target '//Models:Models' is not visible from
target '//App:App'
```

Mana — arxitektura qoidasi kod bilan majburlandi. `//App` qancha urinmasin, `//Models`'ning ichki detallariga to'g'ridan-to'g'ri yeta olmaydi; u Services'ning ommaviy API'si orqali o'tishi **shart**.

> **🏢 Real-world:** Aynan shu usul — visibility bilan qatlamlarni majburlash — katta monorepo'larda arxitekturani saqlab turadi. Bazel hujjatlari bir nechta target'ni bir xil to'plamga ochish uchun har joyda ro'yxatni takrorlamay, `package_group` ishlatishni tavsiya qiladi; "boshqa jamoaning loyihasiga ochganda `__pkg__` o'rniga `__subpackages__` ni afzal ko'ring" deydi (manba: `concepts/visibility`). Biz buni [Bazel 16 — Monorepo](/ios-lessons/bazel-16-loyiha-monorepo) da `package_group` bilan to'liq quramiz, u yerda "app internal package'ga qo'l cho'zsa" haqiqiy xato chiqaramiz.

> **💡 Pro tip:** Prototip paytida visibility'ni vaqtincha o'chirib turish uchun `--check_visibility=false` bor — lekin uni commit qilinadigan kodda **hech qachon** ishlatmang. Yaxshi amaliyot: `default_visibility`'ni public qilib qo'ymang; har bir package o'zining ommaviy interfeysini aniq ko'rsatsin.

Biz `//Models` ni va `//App` ni asl holiga (`//visibility:public` va `deps = ["//Services"]`) qaytaramiz.

---

## 8. Build'ning uch bosqichi va Skyframe {#uch-bosqich}

`bazel build` ishlaganda, u uchta ketma-ket bosqichdan o'tadi: **loading → analysis → execution**. Bu uchlikni tushunish — Bazel'ni chinakam tushunishning kaliti, chunki xatolar qaysi bosqichda yuz berishi, nima qachon keshlanishini va nega ikkinchi build tez bo'lishini aynan shu izohlaydi.

![Build'ning uch bosqichi: loading, analysis, execution va ularning kirish/natijalari; Skyframe keshi](/lessons/images/bazel/bazel_03_three_phases.svg)

### 1. Loading bosqichi

Bazel `BUILD` va `.bzl` fayllarni bajarib, **package**'larni yaratadi. Aynan shu yerda:

- BUILD fayllar Starlark kodi sifatida bajariladi;
- `glob()` shu yerda ishlaydi (fayl tizimiga qaraydi);
- macro'lar ochiladi (ular haqida [Bazel 4](/ios-lessons/bazel-04-starlark) da).

**Natija:** _target graph_ — target'lar va ular orasidagi e'lon qilingan bog'liqliklar.

### 2. Analysis bosqichi

Bazel target graph'ni olib, rule'larning implementatsiyasini baholaydi va **action graph** quradi. Shu yerda:

- har bir rule o'z action'larini (masalan "bu `.swift` fayllarni kompilyatsiya qil") aniqlaydi;
- **configuration** qo'llanadi (masalan `darwin_arm64-fastbuild` — platforma + build turi);
- **visibility tekshiriladi** ([7-bo'limdagi](#visibility) xato aynan shu yerda chiqqan edi).

**Natija:** _action graph_ — bajariladigan aniq action'lar va ular chiqaradigan artefaktlar (lekin hali hech narsa ishlamagan).

> **🧠 Esda tuting:** Loading va analysis bir-biriga **aralashib** ishlaydi — Bazel target'larni yuklab borar ekan, darhol ularni tahlil qila boshlaydi. Shuning uchun amalda siz ularni "grafni tushunish" bosqichi deb bir butun qilib tasavvur qilsangiz bo'ladi. Execution esa alohida, oxirgi bosqich.

### 3. Execution bosqichi

Bazel action graph'dagi action'larni bajaradi: `swiftc` ishga tushadi, obyekt fayllar yoziladi, binary link qilinadi. Har bir action **sandbox** ichida, izolyatsiyada ishlaydi ([keyingi bo'lim](#action-graph)). Faqat **eskirgan yoki hali qurilmagan** action'lar bajariladi — qolganlari keshdan olinadi.

**Natija:** artefaktlar — masalan `bazel-bin/App/App`.

### Bosqichlarni o'z ko'zimiz bilan ajratish

`--nobuild` flagi Bazel'ni loading + analysis'dan keyin **to'xtatadi** — execution'siz. Bu bosqichlarni ajratib ko'rishning eng oson usuli:

```bash
bazel build //App --nobuild
```

```text
INFO: Analyzed target //App:App (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
INFO: Elapsed time: 0.106s, Critical Path: 0.00s
INFO: 0 processes.
INFO: Build completed successfully, 0 total actions
```

Diqqat: `0 total actions`. Bazel target'ni to'liq **tahlil qildi** (label'ni topdi, grafni qurdi, visibility'ni tekshirdi), lekin birorta ham action bajarmadi. Oddiy `bazel build`'ning chiqishida esa siz avval `Loading:`, keyin `Analyzing:`, so'ng `[N / M]` action hisoblagichini ko'rasiz — bu uch bosqichning jonli ko'rinishi.

### Skyframe: nega ikkinchi build tez?

Bazel'ning yuragida **Skyframe** turadi — parallel, funksional va inkremental baholash dvigateli. Skyframe har bir bosqich natijasini (yuklangan package'lar, tahlil qilingan target'lar, bajarilgan action'lar) JVM server'ining xotirasida saqlaydi. Ikkinchi marta build qilganingizda, o'zgarmagan tugunlar qayta hisoblanmaydi:

```bash
bazel build //App    # hech narsa o'zgarmagan
```

```text
Target //App:App up-to-date:
INFO: Elapsed time: 0.114s, Critical Path: 0.00s
```

Butun build 0.114 soniyada tugadi — chunki Skyframe "hech narsa o'zgarmadi" deb bildi. Bu — [Bazel 2](/ios-lessons/bazel-02-ornatish) da ko'rgan client/server arxitekturasining mevasi: server xotirada grafni ushlab turadi. `bazel shutdown` server'ni to'xtatadi va bu xotiradagi grafni (analiz keshini) tozalaydi.

### Inkremental build: faqat kerakli qism

Eng muhim amaliy xulosa: faqat **o'zgargan fayldan ta'sirlangan** target'lar qayta quriladi. Buni o'lchab ko'ramiz. Avval "bitta faylni o'zgartirsam, nima qayta quriladi?" degan savolga `rdeps` javob beradi:

```bash
bazel query 'rdeps(//..., //Models)'
```

```text
//App:App
//Models:Models
//Services:Services
```

Models o'zgarsa, uchalasi ham ta'sirlanadi (chunki Services → Models, App → Services). Endi haqiqiy o'lchov. Ikki xil o'zgarish qilamiz va har birida `bazel build //App`'ning nechta `swiftc` (worker) ishga tushishini sanaymiz:

**O'lchov sharti:** Apple M4 Pro (12 core, 24 GB), Bazel 9.3.0, rules_swift 4.2.1, Xcode 27.1, umumiy disk cache yoqilgan, o'lchovlar eksklyuziv rejimda (bitta vaqtda bitta build).

| Operatsiya                                            | Vaqt      | Nima ishladi                                                                                                |
| ----------------------------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------- |
| Butunlay sovuq build (bo'sh cache, yangi output base) | ~83.7 s\* | 350 action; vaqtning katta qismi — rules_swift worker'ini abseil'dan kompilyatsiya (mashinaga bir martalik) |
| `bazel clean` + disk cache bilan qayta build          | 2.7 s     | 298 process, 179 disk cache hit                                                                             |
| No-op (hech narsa o'zgarmagan)                        | 0.1 s     | 0 action (Skyframe xotiradan)                                                                               |
| **Leaf** o'zgarish (`App/main.swift`)                 | 0.8 s     | **1 swiftc** — faqat App qayta kompilyatsiya + link                                                         |
| **Core API** o'zgarish (`Models/City.swift`)          | 1.2 s     | **3 swiftc** — Models, Services, App uchalasi (fan-out)                                                     |

\* "Sovuq" build raqami (~83.7 s) FACTS.md'dan — shu mashinada, shunga o'xshash 2-modulli ilova uchun o'lchangan. Mening bu yerdagi birinchi build'im umumiy disk cache allaqachon to'la bo'lgani uchun 20.3 s bo'ldi (173 disk cache hit); demak butunlay "sovuq" raqam faqat bo'sh keshda ko'rinadi.

Ikki pastki qatorni solishtiring. `App/main.swift` (grafning tepasi, "leaf") o'zgarsa — faqat **1** ta modul qayta kompilyatsiya qilinadi. `Models/City.swift`'ga yangi `public` property qo'shsak (grafning tubi, "core") — **3** ta modul qayta kompilyatsiya qilinadi, chunki Models'ning interfeysi o'zgardi va yuqoridagilar unga bog'liq. Bu aynan `rdeps` ko'rsatgan to'plam.

> **📊 Real raqamlar:** Leaf o'zgarish `1.230 s` emas, `0.823 s`; core o'zgarish `3` ta `swiftc`. Farq kichik ko'rinadi, chunki loyiha kichik. Lekin 200 modulli ilovada bu farq ulkanlashadi: leaf o'zgarish hamon 1 modulni qayta quradi, core o'zgarish esa unga bog'liq o'nlab modulni. Aynan shu sabab katta jamoalar arxitekturani shunday quradiki, tez-tez o'zgaradigan kod "leaf"da, barqaror kod "core"da bo'lsin — [Bazel 13](/ios-lessons/bazel-13-loyiha-vazifalar) da buni rebuild fan-out bilan o'lchaymiz.

> **💡 Pro tip:** Bazel fayl o'zgarganini **vaqt belgisi (mtime)** bilan emas, **mazmun hashi** bilan aniqlaydi. Shuning uchun `touch file.swift` hech narsani qayta qurdirmaydi — fayl mazmuni o'zgarmagan. Bundan ham qizig'i: `Models/City.swift`'ga shunchaki **izoh (comment)** qo'shsak, Models qayta kompilyatsiya bo'ladi, lekin uning `.swiftmodule` chiqishi o'zgarmagani uchun Services va App qayta qurilmaydi — Bazel natija bo'yicha ham keshni tekshiradi. Fan-out faqat haqiqatan **interfeys** o'zgarganda (yangi public a'zo) yuz beradi.

---

## 9. Action graph va sandboxing {#action-graph}

Siz BUILD faylda **target** yozasiz. Lekin Bazel haqiqatda **action**larni bajaradi. Bitta target analysis'da bir nechta action'ga yoyiladi. Bu farqni ko'rish — Bazel'ni "sehr" bo'lishdan to'xtatib, tushunarli mexanizmga aylantiradi.

![Target graph va action graph yonma-yon: bitta target bir nechta SwiftCompile action'iga yoyiladi](/lessons/images/bazel/bazel_03_target_vs_action_graph.svg)

Chap tomonda — siz yozgan **target graph** (`bazel query` ko'rsatadi): 3 ta target. O'ng tomonda — Bazel bajaradigan **action graph** (`bazel aquery` ko'rsatadi): har bir `swift_library` kamida bitta `SwiftCompile` action'iga aylanadi, `swift_binary` esa kompilyatsiya + link'ga.

### Action nima?

**Action** — build paytida ishga tushadigan buyruq: masalan kompilyatorga chaqiruv. Har bir action'da metama'lumot bor: buyruq satri, input artefaktlar, output artefaktlar, muhit o'zgaruvchilari va **action key**. `bazel aquery` bilan `//Models`'ni quradigan action'ni ko'ramiz:

```bash
bazel aquery '//Models'
```

```text
action 'Compiling Swift module //Models:Models'
  Mnemonic: SwiftCompile
  Target: //Models:Models
  Configuration: darwin_arm64-fastbuild
  Execution platform: @@platforms//host:host
  ActionKey: ba9da2be0ed0427411fcaf33a3adc46a6f24077c21775da4fb7a704dd7de569f
  Inputs: [Models/City.swift, .../Models.output_file_map.json, ... (toolchain)]
  Outputs: [.../Models.swiftmodule, .../Models_objs/City.swift.o, ...]
```

Mana — target emas, **action**. Uning:

- **Mnemonic**'i (`SwiftCompile`) — action turining qisqa nomi;
- **Configuration**'i (`darwin_arm64-fastbuild`) — qaysi platforma/rejim uchun;
- **Inputs/Outputs** — aniq fayllar;
- **ActionKey** (bu uzun hash) — keshning kaliti. Agar action'ning biror jihati (buyruq, input mazmuni, muhit) o'zgarsa, kalit o'zgaradi va action qayta ishlaydi. Bu — [Bazel 10 — Cache](/ios-lessons/bazel-10-cache) ning asosi.

### Haqiqiy swiftc buyruq satri

`aquery` buyruq satrini ham ko'rsatadi — bu "expert" darajadagi ko'rinish. Mana `SwiftCompile //Models` aslida qanday `swiftc` chaqiruvi (qisqartirilgan):

```text
Command Line: (exec bazel-out/.../rules_swift+/tools/worker/worker \
    swiftc \
    -target arm64-apple-macos27.0 \
    -sdk __BAZEL_XCODE_SDKROOT__ \
    -emit-object \
    -output-file-map .../Models.output_file_map.json \
    -emit-module-path .../Models.swiftmodule \
    -module-name Models \
    ... )
```

E'tibor bering: `swiftc` to'g'ridan-to'g'ri emas, rules_swift'ning **persistent worker**'i orqali chaqiriladi (`tools/worker/worker`) — bu kompilyatorni jarayon sifatida tirik saqlab, keyingi kompilyatsiyalarni tezlashtiradi. SDK yo'li esa `__BAZEL_XCODE_SDKROOT__` kabi joy egasi (placeholder) bilan yoziladi — bu hermetiklik uchun: aniq yo'l mashinaga bog'liq bo'lib action key'ni "iflos" qilmasligi kerak.

### cquery: konfiguratsiyalangan target

`bazel query` konfiguratsiyagacha bo'lgan grafni ko'rsatadi. `bazel cquery` esa **konfiguratsiyalangan** target'ni — ya'ni qaysi platforma/rejim uchun ekanligini — ko'rsatadi:

```bash
bazel cquery 'deps(//App)' --noimplicit_deps
```

```text
//App:App (2d89340)
//Services:Services (2d89340)
//App:main.swift (null)
//Models:Models (2d89340)
//Services:CityService.swift (null)
//Models:City.swift (null)
```

Qavs ichidagi `(2d89340)` — konfiguratsiya hashi. Rule target'lar konfiguratsiyaga ega; source fayllar esa `(null)` — ular konfiguratsiyaga bog'liq emas (fayl har qanday platformada bir xil fayl). Agar `//App`'ni ikki xil arxitektura uchun qursangiz, bitta target ikkita konfiguratsiyalangan target bo'lib ko'rinadi — [Bazel 5](/ios-lessons/bazel-05-ios-ilova) dagi `--ios_multi_cpus` aynan shuni qiladi.

### Sandboxing: nega e'lon qilinmagan input ishdan chiqadi

**Sandboxing** — har bir action'ni cheklangan, vaqtinchalik papkada izolyatsiya qilish, shunda u e'lon qilinmagan input'ni **o'qiy olmasin** va e'lon qilinmagan output **yoza olmasin**. macOS'da bu `darwin-sandbox` strategiyasi (biz build chiqishida `darwin-sandbox` process'larini ko'rdik). Bu — **hermetiklik**ning asosiy quroli: build faqat o'zi e'lon qilgan narsalarga tayanadi.

Nega bu muhim? Chunki sandbox xatoni **darhol** chiqaradi — u CI'da, boshqa mashinada yoki remote cache'da "portlab" ketishidan oldin. Buni amalda ko'ramiz. Ataylab buzuq `genrule` yozamiz — u `version.txt` faylini o'qiydi, lekin uni `srcs`'da **e'lon qilmaydi**:

```starlark
# Report/BUILD.bazel
# DIQQAT: bu genrule ataylab buzuq — version.txt srcs'da e'lon qilinmagan.
genrule(
    name = "report",
    srcs = [],  # version.txt YO'Q — e'lon qilinmagan input
    outs = ["report.txt"],
    cmd = "cat Report/version.txt > $@",
)
```

Sukut bo'yicha (darwin-sandbox) qurganda — **ishdan chiqadi**:

```bash
bazel build //Report:report
```

```text
ERROR: .../Report/BUILD.bazel:4:8: Executing genrule //Report:report failed:
(Exit 1): bash failed: error executing Genrule command
cat: Report/version.txt: No such file or directory
Target //Report:report failed to build
```

`version.txt` fayl tizimida bor, lekin sandbox ichida **yo'q** — chunki u e'lon qilinmagan. Endi sandbox'ni o'chiramiz (`--spawn_strategy=local`) va **o'sha** genrule muvaffaqiyatli o'tadi:

```bash
bazel build //Report:report --spawn_strategy=local
```

```text
INFO: Build completed successfully, 2 total actions
```

```bash
cat bazel-bin/Report/report.txt
```

```text
v1.0.0
```

Mana xavf: sandbox'siz, bu buzuq genrule **sizning mashinangizda ishlaydi**, lekin CI'da yoki hamkasbingizning mashinasida `version.txt` boshqacha bo'lsa yoki umuman bo'lmasa — build sinadi. Sandbox bu bombani oldindan portlatib, sizni ogohlantiradi.

To'g'ri yechim — input'ni **e'lon qilish** va `$(location ...)` bilan to'g'ri yo'lni olish:

```starlark
# Report/BUILD.bazel — TO'G'RILANGAN
genrule(
    name = "report",
    srcs = ["version.txt"],              # endi e'lon qilingan
    outs = ["report.txt"],
    cmd = "cat $(location version.txt) > $@",
)
```

Endi sandbox ichida ham muammosiz quriladi:

```bash
bazel build //Report:report
```

```text
INFO: 2 processes: 1 internal, 1 darwin-sandbox.
INFO: Build completed successfully, 2 total actions
```

> **🧠 Esda tuting:** Bazel'ning asosiy va'dasi — "build = e'lon qilingan input'lardan kelib chiqadigan sof funksiya". Sandbox shu va'dani majburlaydi: e'lon qilmagan narsangizga tayana olmaysiz. Shuning uchun Bazel'da "mening mashinamda ishlayapti, CI'da esa yo'q" muammosi kamayadi — agar sandbox'da ishlasa, u deyarli hamma joyda ishlaydi.

---

## 10. bazel query, cquery va aquery {#query}

Butun dars davomida biz `bazel query` bilan grafni "so'rab" keldik. Endi uni alohida vosita sifatida jamlaymiz, chunki bu — Bazel'ning eng kuchli kundalik quroli. `query` — build grafiga savol berish tili.

### Eng ko'p ishlatiladigan funksiyalar

| Funksiya         | Savol                                | Misol                                |
| ---------------- | ------------------------------------ | ------------------------------------ |
| `deps(x)`        | x nimaga bog'liq? (barcha transitiv) | `deps(//App)`                        |
| `deps(x, N)`     | x ning N-darajagacha bog'liqliklari  | `deps(//App, 1)` — faqat bevosita    |
| `rdeps(u, x)`    | u ichida kim x'ga bog'liq?           | `rdeps(//..., //Models)`             |
| `somepath(x, y)` | x'dan y'gacha **bitta** yo'l         | `somepath(//App, //Models)`          |
| `allpaths(x, y)` | x'dan y'gacha **barcha** yo'llar     | `allpaths(//App, //Models)`          |
| `kind(k, x)`     | x ichidagi k turidagi target'lar     | `kind(swift_library, //...)`         |
| `attr(a, v, x)`  | a attribute'i v'ga teng target'lar   | `attr(module_name, Services, //...)` |

To'plam amallari ham bor: `except` (yoki `-`), `intersect`, `union` (yoki `+`). Bir nechtasini birlashtirib ko'ramiz:

```bash
# App'ga faqat bevosita bog'langan target'lar:
bazel query 'deps(//App, 1)' --noimplicit_deps
```

```text
//App:App
//App:main.swift
//Services:Services
```

```bash
# App'dan Models'gacha bitta yo'l — "nega App Models'ga bog'liq?"
bazel query 'somepath(//App, //Models)' --noimplicit_deps
```

```text
//App:App
//Services:Services
//Models:Models
```

`kind` bilan turlarni filtrlang. Diqqat: [6-bo'limda](#glob) `//Models/Geo` package'ini qo'shganimiz uchun endi uchta `swift_library` bor:

```bash
bazel query 'kind(swift_library, //...)'
```

```text
//Models:Models
//Models/Geo:Geo
//Services:Services
```

### `--output` formatlari

Bir xil so'rovni har xil ko'rinishda olish mumkin:

| `--output`      | Nima beradi                                              |
| --------------- | -------------------------------------------------------- |
| `label` (sukut) | faqat label'lar                                          |
| `label_kind`    | label + rule turi (`swift_library rule //Models:Models`) |
| `package`       | package nomlari                                          |
| `build`         | target'ning to'liq BUILD ko'rinishi (hamma attribute)    |
| `graph`         | Graphviz DOT formati                                     |

### Grafni rasm qilib chizish

`--output graph` DOT matnini beradi; uni `dot` (Graphviz) bilan rasmga aylantirasiz:

```bash
brew install graphviz   # bir martalik
bazel query 'deps(//App)' --noimplicit_deps --output graph > graph.dot
dot -Tsvg graph.dot -o graph.svg
```

DOT matnining o'zi ham o'qiladigan:

```text
digraph mygraph {
  node [shape=box];
  "//App:App" -> "//App:main.swift"
  "//App:App" -> "//Services:Services"
  "//Services:Services" -> "//Services:CityService.swift"
  "//Services:Services" -> "//Models:Models"
  "//Models:Models" -> "//Models:City.swift"
}
```

Chizilgan rasmda `//App:App` eng tepada turadi; undan ikkita strelka pastga tushadi — biri `main.swift`'ga (uning manba fayli), ikkinchisi `//Services:Services`'ga; Services'dan `CityService.swift` va `//Models:Models`'ga; Models'dan esa `City.swift`'ga. Ya'ni aynan biz qurgan uch qavatli graf.

> **💡 Pro tip:** Katta loyihada `deps(//App)` grafi minglab tugunli bo'lib, rasm o'qib bo'lmaydigan "makaron"ga aylanadi. Shuning uchun amalda `somepath`/`allpaths` bilan grafni ikki nuqta orasiga toraytiring, yoki `--output graph` o'rniga `--output package` bilan "qaysi package'lar kerak?" degan savolga javob oling.

### query vs cquery vs aquery

Uchta "query" bor va ular grafning uch bosqichiga mos keladi ([8-bo'limga](#uch-bosqich) qarang):

| Vosita         | Qaysi bosqichdan keyin | Nimani ko'rsatadi                                                             |
| -------------- | ---------------------- | ----------------------------------------------------------------------------- |
| `bazel query`  | loading                | **target graph** — konfiguratsiyasiz target'lar va e'lon qilingan deps        |
| `bazel cquery` | analysis               | **konfiguratsiyalangan** target'lar (platforma/rejim bilan, `(2d89340)` hash) |
| `bazel aquery` | analysis               | **action graph** — aniq buyruqlar, input/output, ActionKey                    |

Oddiy qoida: "kim kimga bog'liq?" — `query`. "qaysi konfiguratsiyada?" — `cquery`. "aslida qanday buyruq ishlaydi?" — `aquery`. Biz [9-bo'limda](#action-graph) `aquery` bilan haqiqiy `swiftc` buyruq satrini va `cquery` bilan konfiguratsiya hashini ko'rdik.

> **🧠 Esda tuting:** `bazel query` build qilmaydi — u faqat grafni tahlil qiladi, shuning uchun juda tez. `cquery` va `aquery` esa analysis'ni talab qiladi (lekin execution'ni emas). Hech biri haqiqiy kompilyatsiyani ishga tushirmaydi — shuning uchun ularni CI'da "o'zgarish nimaga ta'sir qiladi?" degan savolga tez javob olish uchun bemalol ishlatish mumkin.

---

## Amaliy mashqlar {#mashqlar}

Barcha mashqlar shu darsdagi `shaharlar` workspace'ida bajariladi. Har birida avval javobni o'ylab, keyin buyruq bilan tekshiring.

1. **Label tarjimoni.** Quyidagilarni qisqartiring yoki yoying: (a) `//Services:Services` → ?; (b) `App/BUILD.bazel` ichida `//App:App` ni qanday qisqa yozasiz?; (c) `Models` package'idagi `City.swift` faylining to'liq label'i qanday? Javobni `bazel query` bilan tekshiring.

2. **Source fayllarni sanash.** `//App` ni qurish uchun nechta `.swift` source fayl kerak? Avval taxmin qiling, keyin `bazel query 'kind("source file", deps(//App))'` bilan tekshiring. Natija nega aynan shuncha?

3. **Yangi package qo'shish.** `//Utils` degan yangi `swift_library` package yarating (bitta oddiy `String` kengaytmasi bilan), `//Services` uni `deps`'iga qo'shsin. Keyin `bazel query 'rdeps(//..., //Utils)'` ni ishga tushiring — natija nimani ko'rsatadi va nega `//App` ham ro'yxatda?

4. **⭐ package_group bilan visibility.** `//Models` ni `package_group` orqali faqat `//Services` ko'radigan qiling (`__pkg__` o'rniga guruh ishlatib). `//App` hamon qurilishini tekshiring. Keyin `//App`'ga `//Models` ni bevosita `deps` qilib qo'shing va analysis bosqichidagi visibility xatosini o'z ko'zingiz bilan ko'ring. (Eslatma: `package_group` har doim ommaviy, `visibility` attribute'i yo'q.)

5. **⭐ Sandbox detektivi.** Ikkita e'lon qilingan faylni birlashtiradigan `genrule` yozing (`cat $(location a.txt) $(location b.txt) > $@`). U ishlasin. Keyin bittasini `srcs`'dan olib tashlang (lekin `cmd`'da qoldiring) va `bazel build` ni ishga tushiring — qanday xato chiqadi, qaysi bosqichda? `--spawn_strategy=local` bilan nima o'zgaradi va nega bu xavfli?

6. **⭐ Grafni chizish.** `brew install graphviz` qiling, so'ng `allpaths(//App, //Models)` grafini SVG qilib chizing va brauzerda oching. Keyin `deps(//App)` (to'liq, `--noimplicit_deps`siz) grafini chizing — u nega ancha kattaroq? (Maslahat: implicit toolchain bog'liqliklari.)

---

## O'zingizni tekshiring {#checklist}

- [ ] Label'ning uch qismini (`@repo//package:target`) va `@` vs `@@` farqini ayta olaman.
- [ ] `//Foo` = `//Foo:Foo` ekanini, va `//Foo` package emas, target ekanini bilaman.
- [ ] Package BUILD fayli bilan belgilanishini va `glob()` package chegarasidan o'tmasligini tushunaman.
- [ ] Visibility xatosi qaysi bosqichda (analysis) chiqishini va `__pkg__`/`__subpackages__`/`package_group` farqini bilaman.
- [ ] Loading, analysis va execution bosqichlarini va har birida nima bo'lishini ayta olaman.
- [ ] Skyframe nega ikkinchi build'ni tez qilishini va `touch` nega qayta build qildirmasligini bilaman.
- [ ] Leaf va core o'zgarish rebuild fan-out'ini `rdeps` bilan oldindan bashorat qila olaman.
- [ ] `query`, `cquery` va `aquery` farqini va `aquery` bilan haqiqiy buyruq satrini ko'rishni bilaman.

---

## Xulosa {#xulosa}

- Bazel kodni **repository → package → target** ierarxiyasida ko'radi. Package — BUILD fayli bo'lgan papka; BUILD fayli — package chegarasi. Bitta fayl ikkita package'ga tegishli bo'la olmaydi.
- **Label** — target'ning manzili: `@repo//package:target`. Amalda qisqartmalar ishlatiladi (`//Services`, `:App`, `//Models:City.swift`). **Target pattern** (`//...`, `//Services/...`, `:all`, `except`) bir vaqtda ko'p target'ni qamraydi.
- **Rule** target'lar `srcs`/`deps`/`data`/`visibility`/`testonly` kabi attribute'lar bilan aniqlanadi. `srcs` — kompilyatsiya qilinadigan fayllar, `deps` — modullar, `data` — run vaqtidagi fayllar.
- **`glob()`** package chegarasidan o'tmaydi — ost-package fayllarini jimgina chetlab o'tadi. Ularni `deps` bilan bog'lang.
- **Visibility** sukut bo'yicha private; u arxitekturani majburlaydi va buzilsa **analysis** bosqichida xato beradi.
- Build uch bosqichdan iborat: **loading** (target graph) → **analysis** (action graph, visibility, configuration) → **execution** (action'lar sandbox'da). **Skyframe** natijalarni xotirada saqlab, ikkinchi build'ni sekundning ulushiga tushiradi.
- O'zimiz o'lchadik: leaf o'zgarish 1 ta modulni, core API o'zgarish esa butun fan-out'ni (3 ta modul) qayta quradi — bu aynan `rdeps` ko'rsatgan to'plam.
- **Sandboxing** hermetiklikni majburlaydi: e'lon qilinmagan input'ni o'qib bo'lmaydi — biz buni haqiqiy genrule xatosi bilan ko'rdik.
- **`bazel query`/`cquery`/`aquery`** — grafni, konfiguratsiyani va haqiqiy buyruqlarni ko'rish quroli; "o'zgarishim nimaga ta'sir qiladi?" degan savolning javobi.
- **Keyingi dars:** [Bazel 4: Starlark tili — BUILD va .bzl fayllar, macro'lar, select() va konfiguratsiya](/ios-lessons/bazel-04-starlark)

---

## Manbalar {#manbalar}

1. [Bazel — Repositories, workspaces, packages, and targets](https://bazel.build/concepts/build-ref) — package ta'rifi va chegaralari.
2. [Bazel — Labels](https://bazel.build/concepts/labels) — label sintaksisi, canonical/apparent repo, qisqartmalar.
3. [Bazel — BUILD files](https://bazel.build/concepts/build-files) — Starlark, `load()`, rule oilalari.
4. [Bazel — Dependencies](https://bazel.build/concepts/dependencies) — `srcs`/`deps`/`data` farqi, e'lon qilingan vs haqiqiy bog'liqlik.
5. [Bazel — Visibility](https://bazel.build/concepts/visibility) — `public`/`private`/`__pkg__`/`__subpackages__`/`package_group`.
6. [Bazel — Query guide](https://bazel.build/query/guide) — `deps`, `rdeps`, `somepath`, `allpaths`, `kind`, `attr`.
7. [Bazel — Action Graph Query (aquery)](https://bazel.build/query/aquery) — action'lar, ActionKey, buyruq satri.
8. [Bazel — Configurable Query (cquery)](https://bazel.build/query/cquery) — konfiguratsiyalangan target'lar.
9. [Bazel — Glossary](https://bazel.build/reference/glossary) — loading/analysis/execution phase, Skyframe, action, sandboxing ta'riflari.
10. [Bazel — Build programs (target patterns)](https://bazel.build/run/build) — `//...`, `:all`, istisno sintaksisi.
11. [rules_swift — Rules reference](https://github.com/bazelbuild/rules_swift/blob/master/doc/rules.md) — `swift_library`/`swift_binary` attribute'lari (4.2.1).
12. [Bazel 9.0 release notes](https://github.com/bazelbuild/bazel/releases/tag/9.0.0) — WORKSPACE olib tashlangani, Bzlmod har doim yoqiq.
13. [Gojek Engineering — Gojek's Journey to 3x Faster iOS Builds with Bazel](https://medium.com/gojekengineering/gojeks-journey-to-3x-faster-ios-builds-with-bazel-90fbe3f22f81) (Medium) — "faqat ta'sirlanganini test qil" strategiyasi va `bazel-diff` haqida muhandislik hikoyasi.
