# Bazel 7: Tashqi dependency'lar — Bzlmod, BCR, SPM paketlari va xcframework'lar

> **Holat:** 2026-yil oktabr. Bu darsda Bazel'ga tashqi kodni uch yo'l bilan kiritamiz: BCR registry orqali Bazel modullar (`bazel_dep`), `rules_swift_package_manager` orqali Swift Package Manager paketlari va `apple_*_xcframework_import` orqali tayyor binary'lar. Kod misollari Bazel 9.3.0 (Bazelisk 1.29.0), rules_apple 5.3.0, rules_swift 4.2.1, apple_support 2.10.1, rules_swift_package_manager 1.25.0 va Xcode 27.1 bilan Apple M4 Pro'da tekshirilgan.

> **Bu darsdan keyin siz:** loyihangizga istalgan tashqi kutubxonani — Bazel moduli, SPM paketi yoki yopiq binary — to'g'ri versiya bilan, qaytariladigan (reproducible) va xavfsiz tarzda ulay olasiz.

- Bzlmod'ning ishlash modelini tushunasiz: module, repo, registry (BCR) va Minimal Version Selection (MVS).
- `MODULE.bazel`'da `bazel_dep` bilan dependency qo'shasiz, `bazel mod` bilan grafni o'rganasiz.
- `MODULE.bazel.lock` nega muhimligini va override'lar (`single_version_override`, `local_path_override`, `git_override`, `archive_override`) qachon kerakligini bilasiz.
- `rules_swift_package_manager` bilan haqiqiy SPM paketini (swift-collections) iOS ilovaga ulaysiz — to'liq, tekshirilgan oqim bilan.
- Tayyor `.xcframework`'ni `apple_static_xcframework_import` bilan import qilasiz va `http_archive` + `sha256` nega supply chain xavfsizligi ekanini tushunasiz.
- `bazel vendor` bilan dependency'larni offline build uchun lokal nusxalaysiz.

## Mundarija

1. [Nega tashqi dependency — va u qaysi muammoni tug'diradi](#nega)
2. [Bzlmod: modullar, repolar va registry](#bzlmod)
3. [Birinchi dependency: `MODULE.bazel` va `bazel_dep`](#birinchi)
4. [MVS — versiyalar qanday tanlanadi](#mvs)
5. [`bazel mod` bilan grafni o'rganish](#mod)
6. [`MODULE.bazel.lock` va reproduksiya](#lock)
7. [Override'lar — dependency'ni o'z qo'lingizga olish](#override)
8. [SPM paketlarini ulash: `rules_swift_package_manager`](#spm)
9. [Ko'prik ichida nima bor: module extension va `use_repo`](#extension)
10. [Tayyor binary'lar: xcframework import](#xcframework)
11. [`http_archive`, integrity va supply chain xavfsizligi](#supply)
12. [Offline build: `bazel vendor`](#vendor)
13. [Qaysi yo'lni qachon tanlash](#qaysi)
14. [Amaliy mashqlar](#mashqlar)
15. [O'zingizni tekshiring](#checklist)
16. [Xulosa](#xulosa)
17. [Manbalar](#manbalar)

---

## 1. Nega tashqi dependency — va u qaysi muammoni tug'diradi {#nega}

5-darsda birinchi iOS ilovamizni, 6-darsda esa unga testlar yozdik. Butun kod bizniki edi: `//Core`, `//App`. Lekin haqiqiy loyihada siz hamma narsani noldan yozmaysiz. Tarmoq (networking), Auto Layout, ma'lumotlar bazasi, analitika, log yig'ish — bularning aksariyati allaqachon yozilgan va ochiq kodli yoki tayyor kutubxona sifatida mavjud. Masala shunda: **bu kodni loyihangizga qanday olib kirasiz — va buni shunday qilasizki, hamkasbingizdagi va CI'dagi build aynan siznikidek bo'lsin.**

Xcode'da bu masala odatda ikki yo'l bilan hal qilinadi: Swift Package Manager (SPM) paketlarini "File → Add Package Dependencies" orqali qo'shish, yoki CocoaPods. Ikkalasi ham ishlaydi, lekin ikkala holatda ham bir muammo bor: **versiya va yuklab olingan fayl aniq qulflanmagan bo'lsa, "menda ishlaydi, sende ishlamaydi" holatiga tushasiz.** SPM `Package.resolved` fayli yordam beradi, lekin `swiftc` qaysi fayllarni, qaysi flaglar bilan kompilyatsiya qilganini Xcode build tizimi sizga ochiq ko'rsatmaydi.

Bazel bu masalaga boshqacha yondashadi. Bazel uchun tashqi dependency ham xuddi sizning kodingiz kabi — **e'lon qilingan input'lardan hosil bo'ladigan sof funksiya.** Har bir tashqi paket:

- aniq versiya bilan e'lon qilinadi (`rules_swift` emas, `rules_swift` **4.2.1**);
- yuklab olingan arxiv `sha256` (integrity) bilan tekshiriladi — ya'ni bayt-baytigacha bir xil fayl;
- natija `MODULE.bazel.lock` faylida qulflanadi — hamkasbingizda ham, CI'da ham aynan shu graf qayta tiklanadi.

Bu "{Fast, Correct} — ikkitasini tanla" shiorining dependency'larga tatbig'i: sekinroq birinchi marta, lekin har doim **to'g'ri va qaytariladigan.**

> **🚀 Motivatsiya:** Bazel'da dependency qo'shish — bu "qaysidir versiya yuklanib qoldi" degan lotereya emas. Siz aniq versiyani yozasiz, Bazel uni `sha256` bilan tekshiradi va `MODULE.bazel.lock`'ga yozadi. Olti oydan keyin ham, boshqa Mac'da ham, CI'da ham — aynan o'sha fayllar, aynan o'sha build. Bu "clean build fixes it" davrining oxiri.

Bu darsda biz tashqi kodni kiritishning **uchta yo'lini** o'rganamiz, va ularning har birini o'z qo'limiz bilan ishga tushiramiz:

![Tashqi kodni kiritishning uchta yo'li: BCR registry orqali Bazel moduli, rules_swift_package_manager orqali SPM paketi va xcframework import orqali tayyor binary — uchalasi ham sha256 bilan hermetik](/lessons/images/bazel/bazel_07_dependency_types.svg)

Yuqoridagi uch ustun — darsning xaritasi. **Bazel moduli** (1-ustun) Bazel'ni biladigan ruleset va kutubxonalar uchun; **SPM paketi** (2-ustun) katta iOS ekotizimi uchun; **tayyor binary** (3-ustun) esa yopiq kodli vendor SDK'lari uchun. Keling, poydevordan — Bzlmod'dan — boshlaymiz.

---

## 2. Bzlmod: modullar, repolar va registry {#bzlmod}

Avval terminologiya, chunki keyingi hamma narsa shu uch so'zga tayanadi. Bazel'ning tashqi dependency tizimi — **Bzlmod** (codename) — ikki tushunchaga quriladi (Bazel rasmiy hujjati, `external/overview`):

- **Module (modul)** — versiyalanadigan Bazel loyihasi. Har modulning ildizida `MODULE.bazel` fayli bo'ladi, unda modul nomi, versiyasi va to'g'ridan-to'g'ri bog'liqliklari yoziladi. `rules_swift` — modul. `rules_apple` — modul. Sizning loyihangiz ham — **root module**.
- **Repository (repo)** — ildizida chegara belgisi (`MODULE.bazel`, `REPO.bazel`, yoki eski `WORKSPACE`) bo'lgan papka daraxti. Har bir modul lokal diskda bitta repo bilan ifodalanadi.

Bazel ildiz modulingizdan boshlaydi, uning `MODULE.bazel` faylini o'qiydi va har bir bog'liqlikning `MODULE.bazel` faylini **registry**'dan so'raydi — bu esa butun transitive grafni topguncha davom etadi.

**Registry** — Bazel modullari haqidagi ma'lumotlar bazasi. Standart registry — **Bazel Central Registry (BCR)**, `bcr.bazel.build` manzilida (web interfeysi: `registry.bazel.build`). Registry har bir modulning har bir versiyasi uchun ikki asosiy faylni saqlaydi (`external/registry`):

- `MODULE.bazel` — o'sha versiyaning manifesti (bog'liqliklari);
- `source.json` — manbani qayerdan olish (URL, `integrity` sha256, `strip_prefix`).

Diqqat qiling: registry **arxivning o'zini saqlamaydi** — u faqat "qayerdan yuklab olish va natija qanday sha256 bo'lishi kerak"ligini biladi. Arxivning o'zi GitHub Releases'dan yoki boshqa manbadan yuklanadi.

> **🧠 Esda tuting:** `MODULE.bazel`'da siz faqat **to'g'ridan-to'g'ri** bog'liqliklarni yozasiz. Transitive bog'liqliklar (sizning bog'liqligingizning bog'liqligi) avtomatik hal qilinadi. Bu — eski `WORKSPACE` tizimining eng katta dardiga davo: `WORKSPACE`'da siz hamma transitive dependency'ni qo'lda, to'g'ri tartibda yozishga majbur edingiz.

### WORKSPACE o'ldi — uzil-kesil

Agar internetda Bazel bo'yicha eski qo'llanmani ko'rsangiz va unda `WORKSPACE` fayli, `http_archive(...)` to'g'ridan-to'g'ri `WORKSPACE`'da, yoki `load("@build_bazel_rules_apple//...")` ko'rsangiz — **u eskirgan.** Bazel 9.0'da (2026-yil yanvar) `WORKSPACE` kodi butunlay olib tashlangan: `--enable_bzlmod` va `--enable_workspace` endi hech narsa qilmaydigan (no-op) flaglar (Bazel 9.0 release notes, bazelbuild/bazel#26131). Bazel 8.0'da `WORKSPACE` allaqachon default'da o'chirilgan edi; 9.0 uni o'chirib yubordi.

Buning amaliy natijasi: **biz faqat `MODULE.bazel` bilan ishlaymiz.** Va rules_apple 5.x, rules_swift 4.x snippetlarida `repo_name = "build_bazel_rules_apple"` kabi qatorlar yo'q — biz to'g'ridan-to'g'ri `@rules_apple//` va `@rules_swift//` yozamiz (bu FACTS'da tekshirilgan va eng sodda yo'l).

> **⚠️ Diqqat:** Bazel 9'da yana bir o'zgarish — C/C++ oilasi rule'lari (shu jumladan `objc_library`) endi Bazel yadrosida yo'q, ularni `@rules_cc`'dan `load()` qilish kerak. Bu bizga kamdan-kam kerak bo'ladi (biz asosan Swift yozamiz), lekin eski Objective-C misollarida `objc_library` to'g'ridan-to'g'ri ishlatilgan bo'lsa — endi `load("@rules_cc//cc:defs.bzl", "objc_library")` kerak.

---

## 3. Birinchi dependency: `MODULE.bazel` va `bazel_dep` {#birinchi}

Keling, bo'sh ish papkasida kichik workspace yasaymiz va birinchi dependency'ni qo'shamiz. (Barcha misollarni men `scratchpad/work/bazel/07_dependency/` papkasida haqiqatan ishga tushirdim — natijalar quyida.)

Avval minimal `MODULE.bazel`:

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

bazel_dep(name = "apple_support", version = "2.10.1")
bazel_dep(name = "rules_swift", version = "4.2.1")
bazel_dep(name = "rules_apple", version = "5.3.0")
bazel_dep(name = "bazel_skylib", version = "1.9.2")
```

Bu yerda har bir `bazel_dep` qatori — bitta to'g'ridan-to'g'ri bog'liqlik. Nimalarni qo'shdik:

- **`apple_support`** — Apple toolchain'ini (Xcode, clang) topadi va sozlaydi. rules_apple README unga ko'ra `apple_support` `rules_cc`'dan **yuqorida** yozilishi kerak, chunki birinchi ro'yxatdan o'tgan toolchain g'olib bo'ladi.
- **`rules_swift`** — Swift kompilyatsiyasi (`swift_library`, `swift_binary`, `swift_test`).
- **`rules_apple`** — Apple bundling (`ios_application`, `ios_unit_test`, xcframework rule'lari).
- **`bazel_skylib`** — Starlark uchun standart yordamchi kutubxona (bu yerda MVS'ni ko'rsatish uchun qo'shdik).

Endi bitta `swift_library` qo'shamiz:

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

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

```swift
// Core/Sources/Greeter.swift
public struct Greeter {
    public init() {}
    public func salom(_ ism: String) -> String {
        "Salom, \(ism)!"
    }
}
```

Va build qilamiz:

```bash
bazel build //Core:Core
```

Natija (M4 Pro, disk cache bilan):

```text
INFO: Analyzed target //Core:Core (167 packages loaded, 4479 targets configured).
Target //Core:Core up-to-date:
  bazel-bin/Core/Core.swiftmodule
  bazel-bin/Core/libCore.a
INFO: Elapsed time: 19.782s, Critical Path: 0.87s
INFO: 288 processes: 173 disk cache hit, 113 internal, 1 darwin-sandbox, 1 worker.
```

Bitta kichik `swift_library` uchun **167 package yuklandi va 4479 target konfiguratsiya qilindi** — chunki `rules_swift`, `rules_apple`, `apple_support` o'zlari ham bir talay transitive bog'liqlikni (protobuf, abseil, rules_cc, rules_python...) olib keladi. Bu — Bazel'ning tabiati: u butun grafni oldindan biladi. Yaxshi xabar: bularning hammasi `MODULE.bazel.lock`'ga yoziladi va disk cache'da saqlanadi, shuning uchun ikkinchi marta build soniyalarda tugaydi.

> **💡 Pro tip:** `bazel_dep`'da `version` — bu **minimal** so'rov, aniq qulf emas (qulflash `single_version_override` yoki lock fayl ishi). Agar transitive bog'liqliklardan biri `bazel_skylib`'ning yuqoriroq versiyasini so'rasa, MVS yuqorirog'ini tanlaydi. Buni keyingi bo'limda aniq ko'ramiz.

### `compatibility_level` — mos kelmaslikni e'lon qilish

Semantik versiya (SemVer)'da katta (major) raqamning oshishi "buzuvchi o'zgarish" degani. Lekin MVS har doim eng yuqori versiyani tanlaydi va "yangi versiya orqaga mos" deb faraz qiladi. Agar modul muallifi **chindan ham** buzuvchi o'zgarish kiritsa-chi?

Buning uchun `module()` funksiyasida `compatibility_level` bor (masalan, `rules_swift`ning `MODULE.bazel`'ida `compatibility_level = 3`). Bu raqam oshsa, Bazel o'sha modulning turli compatibility_level'dagi versiyalarini **bir grafda birga yashay olmaydi** deb biladi va aniq xato beradi, "jim-jit noto'g'ri build" o'rniga. Ya'ni `compatibility_level` — bu MVS'ning "orqaga mos" farazini buzadigan holatni ochiq e'lon qilish usuli.

---

## 4. MVS — versiyalar qanday tanlanadi {#mvs}

Dependency boshqaruvidagi klassik muammo — **"diamond" (olmos) muammosi.** Tasavvur qiling:

```text
       A 1.0
      /     \
   B 1.0    C 1.1
     |        |
   D 1.0    D 1.1
```

`B` `D 1.0`'ni, `C` esa `D 1.1`'ni so'raydi. Qaysi `D` ishlatilsin? npm tarixan bir nechta nusxani yonma-yon saqlardi (`node_modules` ichida takror-takror), bu esa hajmni va chalkashlikni oshirardi. Bazel esa **Minimal Version Selection (MVS)** algoritmidan foydalanadi — bu Go modul tizimidan olingan (Russ Cox, research.swtch.com/vgo-mvs).

MVS qoidasi oddiy: **har modul uchun, uni so'ragan barcha versiyalardan eng yuqorisi tanlanadi.** Yuqoridagi misolda `D 1.1` tanlanadi. "Minimal" so'zi shuni bildiradi: `D 1.1` — barcha talablarni qondiradigan **eng erta** versiya; agar `D 1.2` mavjud bo'lsa ham, uni tanlamaymiz, chunki hech kim uni so'ramagan. Natija — **yuqori aniqlikdagi (high-fidelity) va qaytariladigan (reproducible)** tanlov.

Buni o'z grafimizda ko'raylik. `bazel mod explain bazel_skylib` — `bazel_skylib` grafda qayerda paydo bo'lishini va kim uni so'rashini ko'rsatadi:

```text
<root> (bzlmod_demo@1.0.0)
├───apple_support@2.10.1
│   ├───bazel_features@1.51.0
│   │   └───bazel_skylib@1.9.2 #
│   ├───bazel_skylib@1.9.2 #
│   └───rules_cc@0.2.26
│       └───bazel_skylib@1.9.2 #
├───bazel_skylib@1.9.2 #
├───rules_apple@5.3.0
│   ├───bazel_skylib@1.9.2 #
│   ├───rules_python@1.7.0
│   │   └───stardoc@0.7.2
│   │       └───bazel_skylib@1.9.2 #
│   └───rules_shell@0.6.1
│       └───bazel_skylib@1.9.2 #
└───rules_swift@4.2.1
    ├───abseil-cpp@20250814.1
    │   └───bazel_skylib@1.9.2 #
    └───protobuf@34.0.bcr.1
        ├───rules_java@9.1.0
        │   └───bazel_skylib@1.9.2 #
        └───rules_kotlin@1.9.6
            └───bazel_skylib@1.9.2 #
```

(Natija qisqartirildi — haqiqatda o'nlab modul `bazel_skylib`'ni so'raydi.) `#` belgisi — **tanlangan versiya.** Diqqat qiling: o'nlab turli modul `bazel_skylib`'ni so'rasa ham, grafda **faqat bitta versiya — 1.9.2 — yashaydi.** Hech qanday takror nusxa yo'q.

Endi eng qiziqi: nega aynan 1.9.2? `--verbose --include_unused` bilan Bazel qaysi versiya qaysisiga almashtirilganini aytadi:

```text
│   ├───bazel_features@1.27.0 (to 1.51.0, cause rules_swift@4.2.1, rules_swift@4.1.1)
...
│           ├───rules_proto@4.0.0 (to 7.1.0, cause protobuf@33.4, protobuf@32.1)
│           │   └───bazel_skylib@1.0.3 # (to 1.9.2, cause <root>)
...
    └───rules_swift@1.16.0
        └───rules_cc@0.0.2 (to 0.2.26, cause apple_support@2.10.1)
            └───bazel_skylib@1.0.3 # (to 1.9.2, cause <root>)
```

Mana MVS'ning jonli ishi. Transitive modullar `bazel_skylib`'ning juda eski versiyalarini (1.0.3, 1.4.1, 1.7.1, ...) so'rashgan, lekin hammasi **1.9.2'ga ko'tarilgan** — va sabab aniq yozilgan: `(to 1.9.2, cause <root>)`. Ya'ni **biz** (root module) `MODULE.bazel`'da `bazel_dep(name = "bazel_skylib", version = "1.9.2")` deb yozganimiz uchun. Boshqa joyda esa `(cause rules_swift@4.2.1)` — ya'ni `rules_swift` yuqoriroq versiyani talab qilgani uchun ko'tarilgan.

![Bzlmod dependency'larni hal qilish bosqichlari: MODULE.bazel'dan BCR registry orqali to'liq grafga, MVS bilan versiya tanlashdan MODULE.bazel.lock'gacha; o'ng tomonda bazel_skylib uchun uchta turli so'rovdan eng yuqorisi tanlanishi](/lessons/images/bazel/bazel_07_bzlmod_resolution.svg)

Diagrammaning o'ng tomoni — bizning haqiqiy misolimiz: `root` 1.9.2'ni, `rules_apple` 1.8.2'ni, `rules_swift` 1.7.1'ni so'radi — MVS eng yuqorisini, 1.9.2'ni tanladi.

> **📊 Real raqamlar:** Bizning 4 qatorlik `MODULE.bazel`'imiz 167 package va 50'dan ortiq modul olib keldi. Ularning har biri `bazel_skylib`ga bog'liq, lekin diskda `bazel_skylib`ning **bitta** nusxasi bor (1.9.2). MVS tufayli "dependency hell" — turli versiyalar to'qnashuvi — Bazel'da deyarli yo'q. (M4 Pro, Bazel 9.3.0, 2026-10-13.)

### Yanked (chaqirib olingan) versiyalar

Registry ba'zi versiyalarni **yanked** deb belgilashi mumkin — masalan, xavfsizlik zaifligi tufayli. Agar MVS yanked versiyani tanlasa, Bazel xato beradi. Yechish: yangiroq (yanked bo'lmagan) versiyaga o'ting, yoki aniq ruxsat bering — `--allow_yanked_versions`. Bu — supply chain xavfsizligining bir qismi: zararli yoki buzuq versiya chiqarilsa, registry uni "yanked" deb belgilaydi va sizning build'ingiz uni jim-jit ishlatib yubormaydi.

---

## 5. `bazel mod` bilan grafni o'rganish {#mod}

Katta loyihada dependency grafi ulkan bo'ladi. "Nega bizda `rules_python` bor?", "Bu `protobuf` qayerdan keldi?", "Qaysi versiya tanlandi?" — bu savollarga `bazel mod` buyrug'i javob beradi (`external/mod-command`). Eng foydali subkomandalar:

```bash
bazel mod graph                       # butun grafni daraxt ko'rinishida
bazel mod graph --include_unused --verbose   # + almashtirilgan versiyalar sababi bilan
bazel mod deps <modul>                # bitta modulning to'g'ridan-to'g'ri bog'liqliklari
bazel mod explain <modul>             # modul grafda qayerda va kim so'raydi
bazel mod show_repo <modul>           # modul qanday repo bilan ta'minlanadi (http_archive...)
bazel mod show_extension <ext>        # extension qaysi repo'larni yaratadi
bazel mod path <modul>                # root'dan modulga yo'l
```

`bazel mod show_repo` — ayniqsa foydali: u modul qayerdan, qanday yuklab olinishini aniq ko'rsatadi. Masalan, `rules_swift`:

```bash
bazel mod show_repo rules_swift
```

```text
## rules_swift@4.2.1:
http_archive(
  name = "rules_swift+",
  urls = ["https://github.com/bazelbuild/rules_swift/releases/download/4.2.1/rules_swift.4.2.1.tar.gz"],
  integrity = "sha256-u86GfU3Hqj31vI/ECVjyxYQ5P/10x4IKBxRBXySGpag=",
  strip_prefix = "",
  remote_patches = {"https://bcr.bazel.build/modules/rules_swift/4.2.1/patches/module_dot_bazel_version.patch": "sha256-..."},
  remote_module_file_urls = ["https://bcr.bazel.build/modules/rules_swift/4.2.1/MODULE.bazel"],
  remote_module_file_integrity = "sha256-VQornucMgW3U4QaoXfPKuSxcqF3o9gYAEHXGjIMnAOY=",
  remote_patch_strip = 1,
)
```

Bu bizga aniq ko'rsatadi: `rules_swift` 4.2.1 **aynan shu URL**'dan yuklanadi, **aynan shu `sha256`** bilan tekshiriladi, va BCR uni bitta patch bilan qo'llaydi. Hech qanday sehr yo'q — har bir bayt hisobga olingan. Bu — "men bu kod qayerdan kelganini aniq bilaman" degani, bu esa supply chain xavfsizligining asosi.

> **💡 Pro tip:** Grafni rasm sifatida ko'rish uchun: `bazel mod graph --output graph | dot -Tsvg > graph.svg` (`brew install graphviz` kerak). Katta loyihada bu "biz nimaga bog'liqmiz" savoliga eng tez javob.

---

## 6. `MODULE.bazel.lock` va reproduksiya {#lock}

Birinchi `bazel build`'dan keyin workspace ildizida yangi fayl paydo bo'ladi: `MODULE.bazel.lock`. Bu — Bazel'ning qulf (lockfile) fayli. U module resolution va extension'larni ishga tushirish natijasini saqlaydi (`external/lockfile`).

Bizning loyihamizda u 521 qator chiqdi. Boshi shunday:

```json
{
  "lockFileVersion": 28,
  "registryFileHashes": {
    "https://bcr.bazel.build/bazel_registry.json": "...",
    "https://bcr.bazel.build/modules/rules_swift/4.2.1/MODULE.bazel": "...",
    "https://bcr.bazel.build/modules/rules_swift/4.2.1/source.json": "...",
    ...
  }
}
```

Lock fayl ikki asosiy narsani saqlaydi:

1. **`registryFileHashes`** — resolution paytida o'qilgan har bir registry faylining (har modulning `MODULE.bazel` va `source.json`'i) hash'i. Resolution algoritmi bir xil input'larda to'liq deterministik bo'lgani uchun, bu hash'lar natijani to'liq qaytariladigan qiladi.
2. **`moduleExtensions`** — har bir module extension (masalan, keyin ko'radigan `swift_deps`)ning input va natijasi.

> **🧠 Esda tuting:** `MODULE.bazel.lock`'ni **git'ga commit qiling.** `.bazelversion` bilan birga (Bazelisk o'qiydigan), lock fayl butun jamoada va CI'da aynan bir xil dependency grafini kafolatlaydi. `package-lock.json` yoki `Package.resolved` nima qilsa — shu.

`--lockfile_mode` flagi lock fayl bilan munosabatni boshqaradi:

- `update` (default) — yetishmayotgan ma'lumotni qo'shadi;
- `error` — agar biror narsa lock bilan mos kelmasa, xato beradi va tarmoqqa chiqmaydi (CI uchun ideal: "lock faylga tegilmagan bo'lsin");
- `off` — lock fayl tekshirilmaydi ham, yangilanmaydi ham.

CI'da `--lockfile_mode=error` qo'ying: agar kimdir `MODULE.bazel`'ni o'zgartirib, lock faylni yangilashni unutsa — CI darrov ushlaydi.

> **💡 Pro tip:** Lock fayl merge conflict berishi mumkin. Bazel buning uchun maxsus git merge driver beradi (`.gitattributes`'ga `MODULE.bazel.lock merge=bazel-lockfile-merge`). Yoki sodda yo'l: konfliktda `git checkout MODULE.bazel.lock` bilan eski holatga qaytaring, `MODULE.bazel`'dagi konfliktni hal qiling, so'ng `bazel mod deps` bilan lock faylni qayta yarating.

---

## 7. Override'lar — dependency'ni o'z qo'lingizga olish {#override}

Ba'zan registry'dagi versiya sizga to'g'ri kelmaydi: patch qo'shishingiz, yangi (hali BCR'da yo'q) versiyani sinashingiz, yoki dependency'ni lokal nusxada tahrirlashingiz kerak. Buning uchun **override'lar** bor. Muhim qoida: **faqat root module'ning override'lari ishlaydi** — agar sizning modulingiz boshqa birovga dependency bo'lsa, sizning override'laringiz e'tiborsiz qoldiriladi (`external/module`).

Beshta override turi bor. Avval ularni jadval bilan, keyin ikkitasini amalda:

| Override                    | Nima qiladi                                                                 | Qachon                                           |
| --------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------ |
| `single_version_override`   | Bitta versiyaga qotiradi (pin), registry'ni o'zgartiradi yoki patch qo'yadi | Transitive dependency'ni aniq versiyaga qotirish |
| `multiple_version_override` | Bir modulning bir nechta versiyasini birga yashashga ruxsat beradi          | Kamdan-kam; migratsiya paytida                   |
| `archive_override`          | Modulni registry o'rniga URL'dagi arxivdan oladi                            | Fork yoki hali chiqmagan versiya                 |
| `git_override`              | Modulni git repo'dan (commit bo'yicha) oladi                                | Upstream'ning aniq commit'ini sinash             |
| `local_path_override`       | Modulni lokal diskdagi papkadan oladi                                       | Dependency'ni lokal tahrirlash / debug           |

### `single_version_override` va bir real xato

Avval `bazel_skylib`'ni past versiyaga qotirishga urinib ko'raylik:

```starlark
# MODULE.bazel (qo'shimcha)
single_version_override(
    module_name = "bazel_skylib",
    version = "1.8.0",
)
```

```bash
bazel mod graph
```

```text
ERROR: module 'bazel_skylib' is overridden to use version '1.8.0',
which is lower than the version '1.9.2' requested by the root module
```

Mana foydali dars: `single_version_override` **root module o'zi `bazel_dep` bilan so'ragan versiyadan pastga** tusha olmaydi. Ya'ni biz `bazel_dep(... version = "1.9.2")` deb yozgan ekanmiz, override uni 1.8.0'ga tushira olmaydi. Mantiqiy: override — bu "men bu versiyani xohlayman" degani, lekin root'ning o'z `bazel_dep`'i ham bir talab. Ularni kelishtirish kerak. Agar chindan past versiya kerak bo'lsa — `bazel_dep`'dagi versiyani ham tushiring.

`single_version_override`ning haqiqiy foydasi — **transitive** dependency'ni (siz to'g'ridan-to'g'ri so'ramagan modulni) qotirishda, yoki unga patch qo'yishda:

```starlark
# Transitive dependency'ni aniq versiyaga qotirish (xavfsizlik patch'i chiqqanda)
single_version_override(
    module_name = "protobuf",
    version = "34.0.bcr.1",
)

# Yoki: patch qo'yish
single_version_override(
    module_name = "some_dep",
    patches = ["//patches:fix.patch"],
    patch_strip = 1,
)
```

### `local_path_override` — dependency'ni lokal tahrirlash (tekshirilgan)

Eng amaliy override — bu `local_path_override`. Tasavvur qiling: `rules_swift`'da bug bor va siz uni tuzatmoqchisiz, yoki o'zingizning ruleset'ingizni loyiha yonida ishlab chiqyapsiz. Buni ko'rsatish uchun kichik lokal modul yasadim:

```starlark
# ../greet_rules/MODULE.bazel
module(name = "greet_rules", version = "0.0.0")

bazel_dep(name = "bazel_skylib", version = "1.9.2")
```

```starlark
# ../greet_rules/defs.bzl — lokal tahrirlanadigan macro
def banner(name, text, visibility = None):
    native.genrule(
        name = name,
        outs = [name + ".txt"],
        cmd = "echo '=== %s ===' > $@" % text,
        visibility = visibility,
    )
```

Endi uni root `MODULE.bazel`'da registry o'rniga lokal papkadan olamiz:

```starlark
# MODULE.bazel (qo'shimcha)
bazel_dep(name = "greet_rules", version = "0.0.0")
local_path_override(
    module_name = "greet_rules",
    path = "../greet_rules",
)
```

```starlark
# BUILD.bazel
load("@greet_rules//:defs.bzl", "banner")

banner(
    name = "welcome",
    text = "Bazel 7: dependencylar",
)
```

```bash
bazel build //:welcome && cat bazel-bin/welcome.txt
```

```text
INFO: Build completed successfully, 2 total actions
=== Bazel 7: dependencylar ===
```

Ishladi. `bazel mod show_repo greet_rules` buni tasdiqlaydi — modul endi registry'dan emas, lokal papkadan olinmoqda:

```text
## greet_rules@_:
local_repository(
  name = "greet_rules+",
  path = "../greet_rules",
)
```

Diqqat qiling: canonical nom `greet_rules@_` — bu `_` non-registry override belgisidir (versiya o'rniga). Endi `../greet_rules/defs.bzl`'ni tahrirlasangiz, keyingi build darrov yangi kodni oladi — hech narsa qayta yuklab olinmaydi. Aynan shu usul bilan `rules_swift_package_manager` o'z misollarini sinaydi: `local_path_override(module_name = "rules_swift_package_manager", path = "../..")`.

> **⚠️ Diqqat:** `git_override` va `archive_override` tarmoqqa chiqadi (git clone yoki arxiv yuklash). `archive_override`'da `integrity = "sha256-..."` berib, yuklangan fayl to'g'riligini kafolatlang. Bu override'lar fork yoki hali-BCR'da-yo'q versiya uchun; lekin ularni vaqtincha deb bilib, imkoni bo'lsa BCR versiyasiga qayting — override'lar lock faylni va reproduksiyani murakkablashtiradi.

---

## 8. SPM paketlarini ulash: `rules_swift_package_manager` {#spm}

Mana darsning eng amaliy qismi. iOS ekotizimining **aksariyati** Bazel moduli emas — ular Swift Package Manager paketlari: SnapKit, Alamofire, GRDB, swift-collections, Kingfisher va yuzlab boshqalar. Bazel bulardan qanday foydalanadi?

BCR'da ularning ko'pi yo'q. Shuning uchun alohida ko'prik bor: **`rules_swift_package_manager`** (qisqasi RSPM; muallif: cgrindel). U `Package.swift` va `Package.resolved` fayllaringizni o'qiydi, har bir paketni yuklab oladi, va uni `rules_swift` + `rules_apple` bilan **Bazel target'lariga** aylantiradi (`github.com/cgrindel/rules_swift_package_manager`).

> **🧠 Esda tuting:** RSPM 1.25.0 **faqat Bzlmod** bilan ishlaydi. Bazel 9'da bu muammo emas — Bzlmod har doim yoqilgan. (RSPM README'da `common --enable_bzlmod` qatori bor, lekin Bazel 9.3.0'da bu **no-op** — biz lokal tekshirdik: `--enable_bzlmod` ham, `--noenable_bzlmod` ham xatosiz qabul qilinadi. Ya'ni bu qatorni yozishingiz shart emas.)

Keling, qadam-baqadam. Biz "Vazifalar" (tasklar) iOS ilovasiga Apple'ning rasmiy **swift-collections** paketini ulaymiz va undagi `OrderedSet` bilan dublikatsiz, tartibli ro'yxat yasaymiz.

### 1-qadam: `MODULE.bazel`'da extension'ni yoqish

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

bazel_dep(name = "apple_support", version = "2.10.1")
bazel_dep(name = "rules_swift", version = "4.2.1")
bazel_dep(name = "rules_apple", version = "5.3.0")
bazel_dep(name = "rules_swift_package_manager", version = "1.25.0")

swift_deps = use_extension(
    "@rules_swift_package_manager//:extensions.bzl",
    "swift_deps",
)
swift_deps.from_package(
    resolved = "//:Package.resolved",
    swift = "//:Package.swift",
)
use_repo(
    swift_deps,
    # bu ro'yxatni hozircha bo'sh qoldiramiz —
    # `bazel mod tidy` keyin to'ldiradi
)
```

`use_extension` — `swift_deps` module extension'ini sahnaga olib keladi. `from_package` unga `Package.swift` va `Package.resolved` qayerdaligini aytadi. `use_repo` esa extension yaratgan repo'larni modulga ko'rinadigan qiladi — lekin qaysilarini aniq, buni biz qo'lda yozmaymiz, `bazel mod tidy` hal qiladi.

### 2-qadam: ildizda `BUILD.bazel` va `Package.swift`

`swift_deps` extension `//:Package.resolved`'ni o'qiy olishi uchun ildiz papka **package** bo'lishi kerak — ya'ni unda `BUILD.bazel` bo'lishi shart:

```starlark
# BUILD.bazel (ildiz)
exports_files(["Package.swift", "Package.resolved"])
```

> **⚠️ Diqqat:** Agar ildizda `BUILD.bazel` bo'lmasa, aniq xato olasiz: `Unable to load package for //:Package.resolved: BUILD file not found`. Yechim — ildizda (bo'sh bo'lsa ham) `BUILD.bazel` yarating. Bu FACTS'da ham ushlangan real xato.

```swift
// Package.swift
// swift-tools-version: 5.9
import PackageDescription

let package = Package(
    name: "spm_demo",
    dependencies: [
        .package(url: "https://github.com/apple/swift-collections", from: "1.1.0"),
    ]
)
```

### 3-qadam: `Package.resolved`'ni yaratish

`Package.resolved` — aniq versiya va git commit'ini qulflaydigan fayl. Uni tizim `swift` bilan yaratamiz:

```bash
swift package resolve
```

```text
Fetching https://github.com/apple/swift-collections
Computed https://github.com/apple/swift-collections at 1.7.3 (7.26s)
Working copy of https://github.com/apple/swift-collections resolved at 1.7.3
```

Hosil bo'lgan `Package.resolved`:

```json
{
  "pins": [
    {
      "identity": "swift-collections",
      "kind": "remoteSourceControl",
      "location": "https://github.com/apple/swift-collections",
      "state": {
        "revision": "35a1edcb8ebd2bfe251d587f0b69e62af28f508c",
        "version": "1.7.3"
      }
    }
  ],
  "version": 2
}
```

Diqqat: `from: "1.1.0"` deb yozdik, lekin SPM eng yangi mos versiyani — **1.7.3**'ni — tanladi va uni `revision` (aniq git commit) bilan qulfladi.

### 4-qadam: `bazel mod tidy` — `use_repo`'ni to'ldirish

Endi Bazel'ga "qaysi repo'larni ko'rsatish kerak"ligini aytamiz. Buni qo'lda yozish shart emas — `bazel mod tidy` avtomatik to'ldiradi:

```bash
bazel mod tidy
```

```text
INFO: Updated use_repo calls for @rules_swift_package_manager//:extensions.bzl%swift_deps
```

Natijada `MODULE.bazel`'imizning oxiri shunday bo'ldi (`bazel mod tidy` o'zi yozdi):

```starlark
use_repo(
    swift_deps,
    "swift_package",
    "swiftpkg_swift_collections",
)
```

Ikki repo qo'shildi:

- **`swiftpkg_swift_collections`** — swift-collections paketining Bazel repo'si. Nom qoidasi: `swiftpkg_` + paket identity, kichik harflarda, tinish belgilari `_` bilan almashtirilgan (`apple/swift-nio` → `swiftpkg_swift_nio`).
- **`swift_package`** — `swift package` buyruqlarini Bazel ichidan ishga tushirish uchun yordamchi repo (default yoqilgan).

> **💡 Pro tip:** Eski qo'llanmalarda `use_repo(swift_deps, "swift_deps_info", ...)` deb yoziladi. `swift_deps_info` — faqat Gazelle plugin (BUILD fayllarini avtomatik generatsiya qilish) uchun kerak va u `declare_swift_deps_info = True` bilan yoqiladi. Biz Gazelle ishlatmaymiz, shuning uchun `bazel mod tidy` uni o'zi olib tashladi. Ishonmang — `bazel mod tidy`'ga ishoning: u aniq kerakli repo'larni yozadi.

### 5-qadam: qaysi target'ni ulashni topish

swift-collections bir nechta modul (product) beradi. Qaysi label kerakligini `bazel query` bilan ko'ramiz:

```bash
bazel query '@swiftpkg_swift_collections//:all'
```

```text
@swiftpkg_swift_collections//:Collections
@swiftpkg_swift_collections//:DequeModule
@swiftpkg_swift_collections//:HeapModule
@swiftpkg_swift_collections//:OrderedCollections
@swiftpkg_swift_collections//:BitCollections
...
```

Bizga `OrderedSet` kerak, u `OrderedCollections` modulida. Demak label — `@swiftpkg_swift_collections//:OrderedCollections`.

### 6-qadam: ilovada ishlatish

```swift
// App/Sources/TaskStore.swift
import Foundation
import OrderedCollections

// OrderedSet tartibni saqlaydi VA dublikatni tushiradi — ro'yxatga allaqachon
// bor vazifani qayta qo'shib bo'lmaydi.
@Observable
final class TaskStore {
    private(set) var tasks: OrderedSet<String> = ["Nonushta", "Mashq", "Kod yozish"]

    func add(_ title: String) {
        let trimmed = title.trimmingCharacters(in: .whitespaces)
        guard !trimmed.isEmpty else { return }
        tasks.append(trimmed)   // dublikat bo'lsa, OrderedSet uni e'tiborsiz qoldiradi
    }

    func remove(_ title: String) {
        tasks.remove(title)
    }
}
```

```swift
// App/Sources/ContentView.swift
import SwiftUI

struct ContentView: View {
    @State private var store = TaskStore()
    @State private var yangi = ""

    var body: some View {
        NavigationStack {
            List {
                ForEach(Array(store.tasks), id: \.self) { task in
                    Text(task)
                }
            }
            .navigationTitle("Vazifalar")
            .safeAreaInset(edge: .bottom) {
                HStack {
                    TextField("Yangi vazifa", text: $yangi)
                        .textFieldStyle(.roundedBorder)
                    Button("Qo'shish") {
                        store.add(yangi)
                        yangi = ""
                    }
                }
                .padding()
            }
        }
    }
}
```

Va `App/BUILD.bazel`'da dependency'ni ulaymiz:

```starlark
# App/BUILD.bazel
load("@rules_swift//swift:swift.bzl", "swift_library")
load("@rules_apple//apple:ios.bzl", "ios_application")

swift_library(
    name = "AppLib",
    srcs = glob(["Sources/**/*.swift"]),
    module_name = "AppLib",
    deps = [
        "@swiftpkg_swift_collections//:OrderedCollections",
    ],
)

ios_application(
    name = "Vazifalar",
    bundle_id = "uz.azimjondev.vazifalar",
    families = ["iphone"],
    infoplists = ["Info.plist"],
    minimum_os_version = "17.0",
    deps = [":AppLib"],
)
```

E'tibor bering: SPM dependency oddiy `deps = ["@swiftpkg_.../..."]` sifatida ulanadi — xuddi o'zimizning `//Core` kabi. Bazel uchun tashqi paket ham, bizning modulimiz ham — bir xil fuqaro.

```bash
bazel build //App:Vazifalar
```

```text
[343 / 354] Compiling Swift module @swiftpkg_swift_collections//:OrderedCollections.rspm.__impl; 1s disk-cache, worker
[345 / 354] Compiling Swift module //App:AppLib; 1s disk-cache, worker
[351 / 354] Bundling Vazifalar
[352 / 354] Processing and signing Vazifalar
Target //App:Vazifalar up-to-date:
  bazel-bin/App/Vazifalar.ipa
INFO: Build completed successfully, 354 total actions
```

`Vazifalar.ipa` tayyor, swift-collections ichida kompilyatsiya qilingan holatda.

### SPM ko'prigi ichida nima bo'lyapti

![SPM paketlari Bazel'ga qanday ulanadi: Package.swift va Package.resolved fayllaridan swift_deps module extension orqali swiftpkg_swift_collections repo'siga, undan esa ilovaning swift_library deps'iga; pastda uch bosqichli ish tartibi](/lessons/images/bazel/bazel_07_spm_bridge.svg)

Diagramma oqimni ko'rsatadi: ikki manba fayl (`Package.swift` — nima kerak; `Package.resolved` — aniq versiya) → `swift_deps` extension ularni o'qiydi → `@swiftpkg_swift_collections` repo'sini yaratadi (ichida tayyor `swift_library`'lar) → siz uni `deps`'ga qo'shasiz.

### Har paket qo'shilganda uchta fayl yangilanadi

Bu — RSPM'ning halol narxi. Har safar paket qo'shsangiz yoki versiyasini o'zgartirsangiz, **uchta fayl** o'zgaradi:

1. `Package.swift` — yangi `.package(...)` qatori;
2. `Package.resolved` — yangi versiya/revision (`swift package resolve` yoki `bazel run @swift_package//:resolve`);
3. `MODULE.bazel` — yangi `use_repo` repo'si (`bazel mod tidy`).

Paketni yangilash uchun RSPM yordamchi target beradi:

```bash
bazel run @swift_package//:update              # hamma paketni yangilash
bazel run @swift_package//:update -- SomePackage   # bittasini
bazel run @swift_package//:resolve             # faqat Package.resolved'ni yangilash
```

So'ng yana `bazel mod tidy`. Uchala faylni ham git'ga commit qiling.

### O'lchov: dependency qancha turadi?

Eng muhim savol: tashqi paket build'ni qancha sekinlashtiradi? O'lchadim (M4 Pro 12-core 24 GB, Xcode 27.1, Bazel 9.3.0, RSPM 1.25.0, swift-collections 1.7.3; har o'lchov eksklyuziv build-slot bilan):

| Holat                                        | Vaqt       | Nima bo'ldi                                                                                       |
| -------------------------------------------- | ---------- | ------------------------------------------------------------------------------------------------- |
| Birinchi marta (cold, cache butunlay o'chiq) | **73.1 s** | Hammasi noldan: rules_swift ishchi tooli (abseil'dan, bir martalik), swift-collections va ilova   |
| Yangi checkout + umumiy disk cache           | **19.1 s** | 188 action disk cache'dan; faqat fetch + analysis + link qayta                                    |
| Server issiq + disk cache (qayta build)      | **2.2 s**  | 354 action'ning hammasi cache'dan                                                                 |
| Bitta ilova faylini tahrirlab qayta build    | **5.1 s**  | Faqat `AppLib` qayta kompilyatsiya + bundle; **swift-collections qayta kompilyatsiya qilinmaydi** |

> **📊 Real raqamlar:** Eng muhim qatori — oxirgisi. Siz ilova kodingizni o'zgartirganda (`ContentView.swift`), Bazel faqat **2 ta action** bajardi: `AppLib`'ni qayta kompilyatsiya qildi va ipa'ni qayta yig'di. swift-collections **qayta kompilyatsiya qilinmadi** — u o'zgarmagani uchun cache'dan keldi. Ana shu — Bazel'ning asosiy ustunligi: dependency bir marta kompilyatsiya qilinadi, keyin hech qachon (o'zi o'zgarmaguncha) qayta tegilmaydi. Birinchi 73 soniyaning katta qismi esa swift-collections emas, `rules_swift`ning ishchi toolini (persistent worker) abseil'dan bir marta kompilyatsiya qilish — bu har mashina/cache uchun bir martalik narx.

> **🏢 Real-world:** BuildBuddy'ning iOS→Bazel migratsiya qo'llanmasida (Brentley Jones, 2024, Mastodon forki) SPM dependency'lar aynan shu yo'l bilan — `rules_swift_package_manager` + Gazelle orqali — olib kiriladi. Katta loyihalarda (masalan Toss, ~1000 modul) jamoalar uchinchi tomon dependency'larini **alohida repoga** ko'chirishni va grafni "cache'ga yaroqli" holatga keltirishni tavsiya qiladi (Tuist case study, 2026-10-01) — chunki qancha dependency barqaror bo'lsa, cache shuncha samarali.

---

## 9. Ko'prik ichida nima bor: module extension va `use_repo` {#extension}

8-bo'limda `use_extension`, `from_package`, `use_repo` so'zlarini sehr kabi ishlatdik. Endi parda ortiga qaraymiz, chunki bu mexanizm — Bzlmod'ning eng kuchli qismi va uni tushunsangiz, istalgan ruleset'ning dependency tizimini o'qiy olasiz.

**Module extension** — bu Bzlmod tizimini kengaytirish usuli (`external/extension`). `bazel_dep` faqat Bazel modullari (BCR'dagilar) uchun. Lekin SPM paketlari Bazel moduli emas — ularni yuklab olish, `Package.resolved`'ni o'qish, har bir paketni `swift_library`'ga aylantirish kerak. Buni oddiy `bazel_dep` qila olmaydi. Module extension esa **fayl o'qishi, tarmoqqa chiqishi va repo yaratishi** mumkin — xuddi `swift_deps` qilgandek.

Mexanizm uch qismdan iborat:

1. **`use_extension`** — extension'ni sahnaga oladi:

   ```starlark
   swift_deps = use_extension("@rules_swift_package_manager//:extensions.bzl", "swift_deps")
   ```

   Bu `rules_swift_package_manager` modulidagi `extensions.bzl` faylida aniqlangan `swift_deps` nomli extension'ni qaytaradi.

2. **Tag'lar** — extension'ga ma'lumot uzatasiz. `swift_deps.from_package(...)` — bu "tag". Extension muallifi `tag_class` bilan tag'ning sxemasini belgilaydi (qanday atributlar bo'lishi mumkin). Bizning holatda tag `resolved` va `swift` atributlarini oladi.

3. **`use_repo`** — extension yaratgan repo'larni modulingizga **ko'rinadigan** qiladi:
   ```starlark
   use_repo(swift_deps, "swiftpkg_swift_collections")
   ```
   Extension o'nlab repo yaratishi mumkin, lekin siz faqat `use_repo`'da sanaganlaringizga label bilan murojaat qila olasiz. `bazel mod tidy` aynan shu ro'yxatni to'g'rilaydi.

Extension'lar **dangasa (lazy)** ishga tushadi: repo'si ishlatilmasa, extension umuman ishga tushmaydi. `bazel mod show_extension` bilan extension qaysi repo'larni yaratishini ko'rishingiz mumkin.

> **🧠 Esda tuting:** Bu — "qanday qilib Bazel SPM'ni ham, Maven'ni ham, PyPI'ni ham, Go modullarni ham tushunadi?" degan savolning javobi. Har bir ekotizim uchun bitta module extension yoziladi: `rules_jvm_external`'da `maven`, `rules_python`'da `pip`, `rules_swift_package_manager`'da `swift_deps`. Hammasi bir xil mexanizm — extension fayl o'qiydi, tashqi paket menejeri bilan gaplashadi, repo yaratadi. 17-darsda o'z rule'laringizni yozganimizda bu mexanizmni yana ko'ramiz.

---

## 10. Tayyor binary'lar: xcframework import {#xcframework}

Ba'zan sizga **manba kodi yo'q** — sotuvchi (vendor) sizga faqat tayyor, kompilyatsiya qilingan binary beradi: analitika SDK, to'lov SDK, ba'zan ichki jamoadagi boshqa bo'limning kutubxonasi. Apple'ning bu uchun formati — **`.xcframework`** (bir nechta platforma/arxitektura uchun framework'larni bitta paketga jamlaydi: iOS device, iOS simulator, macOS...).

Bazel bunday tayyor binary'ni ikki rule bilan import qiladi (`rules_apple`, `rules-apple.md`):

- **`apple_static_xcframework_import`** — statik kutubxonali xcframework (ilovaga linklanadi, alohida fayl qolmaydi);
- **`apple_dynamic_xcframework_import`** — dinamik framework (ilova ichida `.framework` sifatida qoladi).

### Avval bir xcframework yasaymiz (vendor tomoni)

Import qilish uchun bizga haqiqiy `.xcframework` kerak. Uni ham Bazel yasay oladi — `apple_static_xcframework` rule'i bilan (vendor sizga aynan shunday yasab beradi):

```swift
// MathKit/Sources/Math.swift
import Foundation

// "Sotuvchi" bizga shu kutubxonani yopiq binary sifatida yetkazadi.
public struct Valyuta {
    public init() {}
    public func qoshimcha(_ summa: Decimal, foiz: Decimal) -> Decimal {
        summa + (summa * foiz / 100)
    }
}
```

```starlark
# MathKit/BUILD.bazel
load("@rules_swift//swift:swift.bzl", "swift_library")
load("@rules_apple//apple:apple.bzl", "apple_static_xcframework")

swift_library(
    name = "MathKitLib",
    srcs = glob(["Sources/**/*.swift"]),
    module_name = "MathKit",
)

# Vendor tomoni: koddan tarqatish uchun .xcframework yasaydi
apple_static_xcframework(
    name = "MathKit",
    bundle_name = "MathKit",
    ios = {
        "simulator": ["arm64"],
    },
    minimum_os_versions = {"ios": "17.0"},
    deps = [":MathKitLib"],
)
```

```bash
bazel build //MathKit:MathKit
```

```text
Target //MathKit:MathKit up-to-date:
  bazel-bin/MathKit/MathKit.xcframework.zip
INFO: Elapsed time: 38.627s, Critical Path: 6.50s
```

Natija — `MathKit.xcframework.zip`. Uni ochib ko'rsak, ichida kutilgan struktura bor:

```text
MathKit.xcframework/
├── Info.plist                          (XCFrameworkFormatVersion 1.0)
└── ios-arm64-simulator/
    └── MathKit.framework/
        ├── MathKit                     (statik binary)
        └── Modules/
            └── MathKit.swiftmodule/
                ├── arm64.swiftmodule   (Swift interfeys)
                └── arm64.swiftdoc
```

> **⚠️ Diqqat:** Biz faqat `simulator` uchun yasadik (`ios = {"simulator": ["arm64"]}`), shuning uchun xcframework'da faqat `ios-arm64-simulator` slice bor. Haqiqiy vendor xcframework'ida odatda ikkala slice bo'ladi: `ios-arm64` (device) va `ios-arm64_x86_64-simulator`. Agar device uchun build qilmoqchi bo'lsangiz, lekin xcframework'da device slice bo'lmasa — build xato beradi. Vendor'dan har doim kerakli slice'larni so'rang.

### Endi uni import qilamiz (iste'molchi tomoni)

Faraz qilaylik, bu `MathKit.xcframework` bizga tashqaridan keldi va biz uni `thirdparty/` papkaga qo'ydik. Import shunday:

```starlark
# thirdparty/BUILD.bazel
load("@rules_apple//apple:apple.bzl", "apple_static_xcframework_import")

# Sotuvchidan kelgan tayyor binary. Biz uni kompilyatsiya qilmaymiz — faqat import qilamiz.
apple_static_xcframework_import(
    name = "MathKit",
    xcframework_imports = glob(["MathKit.xcframework/**"]),
    has_swift = True,   # Swift kodi bor — swiftmodule mavjud
    visibility = ["//visibility:public"],
)
```

`xcframework_imports = glob(["MathKit.xcframework/**"])` — xcframework ichidagi hamma faylni rule'ga beradi. `has_swift = True` — Bazel'ga "bu framework'da Swift interfeys fayllari bor" deb aytadi (Objective-C/C xcframework'da bu `False`).

Endi ilova uni oddiy `deps` sifatida ishlatadi:

```swift
// App/Sources/ContentView.swift
import SwiftUI
import MathKit   // tayyor xcframework'dan keladi

struct ContentView: View {
    private let valyuta = Valyuta()

    var body: some View {
        let natija = valyuta.qoshimcha(100_000, foiz: 15)
        return VStack(spacing: 12) {
            Text("Soliq kalkulyatori").font(.headline)
            Text("100 000 + 15% = \(natija.description)").font(.title3)
        }
        .padding()
    }
}
```

```starlark
# App/BUILD.bazel
load("@rules_swift//swift:swift.bzl", "swift_library")
load("@rules_apple//apple:ios.bzl", "ios_application")

swift_library(
    name = "AppLib",
    srcs = glob(["Sources/**/*.swift"]),
    module_name = "AppLib",
    deps = ["//thirdparty:MathKit"],   # xcframework import
)

ios_application(
    name = "Hisob",
    bundle_id = "uz.azimjondev.hisob",
    families = ["iphone"],
    infoplists = ["Info.plist"],
    minimum_os_version = "17.0",
    deps = [":AppLib"],
)
```

Xcframework'da faqat simulator slice bo'lgani uchun simulator arxitekturasi bilan build qilamiz:

```bash
bazel build //App:Hisob --ios_multi_cpus=sim_arm64
```

```text
INFO: Analyzed target //App:Hisob (199 packages loaded, 6820 targets configured).
[338 / 347] Compiling Swift module //App:AppLib; 1s disk-cache, worker
[340 / 347] Linking App/Hisob_bin; 1s disk-cache, darwin-sandbox
[345 / 347] Processing and signing Hisob
Target //App:Hisob up-to-date:
  bazel-bin/App/Hisob.ipa
INFO: Elapsed time: 11.355s, Critical Path: 7.72s
INFO: Build completed successfully, 47 total actions
```

Ilova tayyor binary'ni ichiga oldi — manba kodisiz. `AppLib` `import MathKit` qildi, `Valyuta` struct'ini xcframework ichidagi `arm64.swiftmodule`'dan topdi, va linklash paytida statik binary ilovaga qo'shildi. Uchinchi usulni ham o'rgandik.

---

## 11. `http_archive`, integrity va supply chain xavfsizligi {#supply}

Ba'zan dependency na BCR modul, na SPM paket, na xcframework bo'ladi — shunchaki URL'dagi arxiv (masalan, ba'zi C kutubxona yoki boshqa fayl). Buning uchun `http_archive` repo rule'i bor. Bzlmod'da uni `use_repo_rule` bilan to'g'ridan-to'g'ri `MODULE.bazel`'da chaqirasiz:

```starlark
# MODULE.bazel
http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "some_lib",
    urls = ["https://example.com/some_lib-1.2.3.tar.gz"],
    integrity = "sha256-c9526390a7cd420fdcec2988b4f3626fe9c5b51e2959f685e8f4d170d1a9bd96=",
    strip_prefix = "some_lib-1.2.3",
    build_file = "//third_party:some_lib.BUILD",   # arxivda BUILD yo'q bo'lsa, o'zimiz beramiz
)
```

Bu yerda eng muhim atribut — **`integrity`** (yoki eski `sha256`). Bu — yuklangan arxivning kriptografik hash'i. Agar arxiv bir baytga bo'lsa ham o'zgarsa (xaker URL'ni almashtirsa, server buzilsa, man-in-the-middle hujum bo'lsa), hash mos kelmaydi va **Bazel build'ni to'xtatadi.**

Bu — **supply chain xavfsizligi**ning asosi. Keling, nega muhimligini aniq ko'raylik. `bazel mod show_repo rules_swift` natijasini eslang (5-bo'lim):

```text
http_archive(
  name = "rules_swift+",
  urls = ["https://github.com/bazelbuild/rules_swift/releases/download/4.2.1/rules_swift.4.2.1.tar.gz"],
  integrity = "sha256-u86GfU3Hqj31vI/ECVjyxYQ5P/10x4IKBxRBXySGpag=",
  ...
)
```

Har bir modul — hatto BCR'dan kelganlar ham — aynan shu tarzda yuklanadi: URL + integrity. Ya'ni:

- **Hermetiklik:** build siz e'lon qilgan aniq fayllardan hosil bo'ladi, tasodifiy "eng yangi" versiyadan emas.
- **Buzilishni aniqlash:** agar GitHub Releases'dagi arxiv almashtirilsa, sizning build'ingiz darrov to'xtaydi.
- **Reproduksiya:** hash `MODULE.bazel.lock`'ga yoziladi, demak boshqa mashinada ham aynan shu fayl ishlatiladi.

> **🚀 Motivatsiya:** 2021-yildagi mashhur supply chain hujumlari (npm, PyPI'dagi zararli paketlar) ko'pincha "aynan shu versiyada aynan shu fayl ekanini hech kim tekshirmagani" tufayli yuz berdi. Bazel'da bu deyarli imkonsiz: har bir arxiv `sha256` bilan qulflangan, har bir versiya lock faylda. BCR yana oldinga boryapti — "Provenance Attestations" (yuklangan paketning haqiqiy manbadan kelganini kriptografik tasdiqlash) ustida ishlanmoqda (`external/overview`).

> **💡 Pro tip:** `integrity` qiymatini qayerdan olish kerak? Birinchi marta noto'g'ri (yoki bo'sh) qiymat bilan yozing — Bazel xatoda **to'g'ri** hash'ni ko'rsatadi, uni nusxalab qo'ying. Yoki: `shasum -a 256 fayl.tar.gz` va natijani `sha256-<base64>` formatiga o'tkazing. `bazel mod` buyruqlari BCR modullari uchun bu hash'ni avtomatik to'ldiradi.

---

## 12. Offline build: `bazel vendor` {#vendor}

Tasavvur qiling: internetsiz muhitda (xavfsiz CI, samolyotda, yoki tarmoq cheklangan korporativ server) build qilishingiz kerak. Yoki: dependency'ning manbasini aniq nazorat qilmoqchisiz — "GitHub o'chsa ham, bizning build'imiz ishlasin". Buning uchun **vendor mode** bor (`external/vendor`).

`bazel vendor` tashqi dependency'larni lokal papkaga nusxalaydi:

```bash
# Bitta repo'ni vendor qilish
bazel vendor --vendor_dir=vendor_src --repo=@bazel_skylib
```

```text
INFO: Vendoring repositories...
INFO: All requested repos vendored successfully.
```

Natijada `vendor_src/` papkasida (tekshirilgan):

```text
vendor_src/
├── _registries/
│   └── bcr.bazel.build/        (registry fayllari — offline resolution uchun)
├── bazel_skylib+/              (repo'ning o'zi: BUILD, lib/, rules/...)
├── @bazel_skylib+.marker       (yangilik belgisi)
├── bazel-external -> .../external   (symlink)
└── VENDOR.bazel                (vendor konfiguratsiyasi)
```

Endi offline build qila olasiz:

```bash
bazel build --vendor_dir=vendor_src //App:Vazifalar
```

Agar barcha dependency'larni vendor qilmoqchi bo'lsangiz — `bazel vendor --vendor_dir=vendor_src` (argumentsiz). Lekin ogohlantirish: bu uzoq davom etadi va papka juda kattalashadi (butun transitive graf). Shuning uchun avval kerakli target'lar uchun vendor qiling: `bazel vendor --vendor_dir=vendor_src //App:Vazifalar`.

`VENDOR.bazel` faylida alohida repo'larni boshqarasiz:

- `pin("@@bazel_skylib+")` — repo'ni vendored holatiga qotiradi (siz uni qo'lda tahrirlashingiz mumkin, Bazel ustiga yozmaydi);
- `ignore("@@rules_cc+")` — repo'ni vendor'dan butunlay chiqaradi.

> **⚠️ Diqqat:** `vendor_src/bazel-external` symlink'ini git'ga qo'shmang (`.gitignore`'ga qo'shing) — u lokal output base'ga ishora qiladi. Qolgan vendored manbani esa commit qilsangiz, boshqa mashinada internetsiz aynan shu build'ni olasiz.

---

## 13. Qaysi yo'lni qachon tanlash {#qaysi}

Uch usulni ko'rib chiqdik. Endi — qaysi birini qachon tanlash. Qoida sodda: **manbaning turi usulni belgilaydi.**

| Manba                                               | Usul                          | Misol                                                      |
| --------------------------------------------------- | ----------------------------- | ---------------------------------------------------------- |
| Bazel'ni biladigan ruleset / kutubxona (BCR'da bor) | `bazel_dep`                   | `rules_swift`, `rules_apple`, `bazel_skylib`, `googletest` |
| Ochiq kodli Swift/iOS paketi (SPM'da)               | `rules_swift_package_manager` | SnapKit, Alamofire, swift-collections, GRDB, Kingfisher    |
| Yopiq kodli, oldindan kompilyatsiya qilingan SDK    | `apple_*_xcframework_import`  | analitika SDK, to'lov SDK, vendor `.xcframework`           |
| URL'dagi oddiy arxiv (BUILD'siz)                    | `http_archive` + `build_file` | ba'zi C kutubxonalar                                       |

Amaliy qarorlar:

- **Birinchi tanlov — BCR moduli.** Agar kutubxona BCR'da bo'lsa (`registry.bazel.build`'da qidiring), `bazel_dep` eng sodda va eng yaxshi integratsiyalashgan yo'l. MVS, lock fayl, `bazel mod` — hammasi tekin.
- **iOS paketlarining aksariyati — SPM orqali.** Haqiqat shuki, iOS ekotizimining katta qismi BCR'da emas. Shuning uchun `rules_swift_package_manager` kundalik ishda eng ko'p ishlatiladigan yo'l bo'ladi. Halol narxi: har paket qo'shilganda uch fayl yangilanadi.
- **Faqat majbur bo'lsangiz — xcframework.** Yopiq kodli binary debug qilish qiyinroq (manba yo'q), platforma/arxitektura slice'lariga bog'liq, va yangilanishni qo'lda kuzatasiz. Lekin vendor faqat binary bersa, boshqa yo'l yo'q.

![Tashqi kodni kiritishning uchta yo'li va har birining mexanizmi, qachon ishlatilishi va misoli](/lessons/images/bazel/bazel_07_dependency_types.svg)

### Halol kamchiliklar

Har usulning o'z narxi bor — buni oldindan bilgan ma'qul:

| Usul              | Kamchilik                                                                                                                                                                    |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `bazel_dep` (BCR) | Kutubxona BCR'da bo'lishi shart; ko'p iOS paketlari yo'q                                                                                                                     |
| SPM (RSPM)        | Har paketda 3 fayl (`Package.swift` + `.resolved` + `MODULE.bazel`); `bazel mod tidy` qadami; ba'zan generatsiya qilingan target'ni `configure_package` bilan tuzatish kerak |
| xcframework       | Manba yo'q (debug qiyin); slice'larga bog'liq; yangilanish qo'lda; versiya qulfi qo'lda                                                                                      |

> **🏢 Real-world:** Rappi iOS jamoasi Bazel'ga o'tishda bitta uchinchi tomon dependency'sining **private header'lari** bir nechta CocoaPods pod orasida ulashilgani tufayli sandboxing'ni o'chirishga majbur bo'ldi (engineering.rappi.com). Bu — dependency bilan bog'liq real ishqalanish misoli: tashqi kod har doim ham Bazel'ning hermetiklik qoidalariga mos tushavermaydi, ba'zan patch yoki maxsus sozlama kerak bo'ladi. Shuning uchun dependency qo'shganda "ishladi" bilan to'xtamang — build hermetik va cache'ga yaroqli ekanini ham tekshiring.

> **⚠️ Diqqat:** Dependency qancha ko'p bo'lsa, build grafi shuncha katta va cache shuncha "mo'rt" bo'ladi. Katta jamoalar (Toss, ~1000 modul) uchinchi tomon dependency'larini alohida repoga ajratadi va grafni barqaror ushlaydi — chunki tez-tez o'zgaradigan dependency cache'ni buzadi. "Kerak bo'lgani uchun" emas, "chindan kerak bo'lgani uchun" dependency qo'shing (YAGNI).

---

## 14. Amaliy mashqlar {#mashqlar}

Bu mashqlarni `scratchpad/work/`'dagi kabi alohida ish papkasida bajaring (repoga tegmang).

1. **Ikkinchi SPM paketini qo'shing.** `spm_demo` ilovasiga yana bitta paket ulang — masalan `swift-argument-parser` yoki `Alamofire`. `Package.swift`'ga qo'shing → `swift package resolve` → `bazel mod tidy` → `bazel query '@swiftpkg_<nom>//:all'` bilan to'g'ri label'ni toping → `deps`'ga qo'shing → build. Qaysi uch fayl o'zgarganini tekshiring.

2. **Grafni tekshiring.** `bazel mod explain protobuf` ishga tushiring va `protobuf` grafingizga **qayerdan** kelganini aniqlang (kim uni so'raydi?). So'ng `bazel mod show_repo protobuf` bilan u qaysi URL'dan, qaysi `sha256` bilan yuklanishini toping.

3. **Lock faylni sinang.** `MODULE.bazel.lock`'ni ochib, `lockFileVersion` va `registryFileHashes`'dagi bir nechta qatorni ko'ring. So'ng `MODULE.bazel`'da bir `bazel_dep` versiyasini o'zgartiring va lock fayl qanday yangilanganini (`git diff`) kuzating.

4. **⭐ `local_path_override` bilan patch.** Kichik lokal modul yarating (`greet_rules` kabi), uni `local_path_override` bilan ulang, so'ng `.bzl` faylini tahrirlab, keyingi build darrov yangi kodni olishini ko'ring. `bazel mod show_repo` bilan canonical nom `@_` bilan tugaganini tasdiqlang.

5. **⭐ To'liq slice bilan xcframework.** `apple_static_xcframework`'ni **ham device, ham simulator** uchun yasang (`ios = {"simulator": ["arm64"], "device": ["arm64"]}`). Unzip qilib, `Info.plist`'da ikkala slice borligini tekshiring. So'ng uni import qilib, device uchun ham (`--ios_multi_cpus=arm64`), simulator uchun ham build qiling.

6. **⭐ Offline build.** `bazel vendor --vendor_dir=vendor_src //App:Vazifalar` bilan dependency'larni vendor qiling. So'ng tarmoqni o'chirib (yoki `--repository_cache=` bilan cache'ni ham o'chirib), `bazel build --vendor_dir=vendor_src //App:Vazifalar` ishlashini ko'ring.

---

## 15. O'zingizni tekshiring {#checklist}

- [ ] `MODULE.bazel`'da faqat **to'g'ridan-to'g'ri** bog'liqliklar yozilishini va transitive'lar avtomatik hal bo'lishini tushuntira olaman.
- [ ] MVS nima qilishini aytaman: har modul uchun eng yuqori so'ralgan versiya tanlanadi.
- [ ] `bazel mod graph` / `explain` / `show_repo` farqini bilaman va qaysi savolga qaysi biri javob berishini aytaman.
- [ ] `MODULE.bazel.lock` nega git'ga commit qilinishini va `--lockfile_mode=error` CI'da nega foydali ekanini bilaman.
- [ ] Beshta override turini sanay olaman va `local_path_override` qachon kerakligini aytaman.
- [ ] SPM paketini ulashning to'liq oqimini yoddan bilaman: `Package.swift` → `swift package resolve` → `bazel mod tidy` → `deps`.
- [ ] `@swiftpkg_<identity>` repo nomi qoidasini va product label'ini `bazel query` bilan topishni bilaman.
- [ ] `apple_static_xcframework_import` va `http_archive` + `integrity` qachon ishlatilishini va `sha256` nega supply chain xavfsizligi ekanini tushuntira olaman.

---

## 16. Xulosa {#xulosa}

- Bazel'da tashqi kod — bu "qaysidir versiya yuklanib qoldi" emas: har bir paket aniq versiya + `sha256` bilan e'lon qilinadi va `MODULE.bazel.lock`'da qulflanadi. Natija — qaytariladigan (reproducible) va hermetik build.
- **Bzlmod** modul va repo tushunchalariga quriladi; Bazel ildiz `MODULE.bazel`'dan boshlab BCR registry orqali butun grafni topadi va **MVS** bilan har modul uchun bitta (eng yuqori so'ralgan) versiyani tanlaydi.
- `bazel mod graph/explain/show_repo` grafni o'rganish uchun, `MODULE.bazel.lock` reproduksiya uchun, override'lar (ayniqsa `local_path_override`) dependency'ni nazorat qilish uchun.
- iOS ekotizimining aksariyati SPM'da — **`rules_swift_package_manager`** ularni `Package.swift`/`Package.resolved`'dan o'qib, `@swiftpkg_<identity>` repo'lariga aylantiradi; oqim: resolve → `bazel mod tidy` → `deps`.
- Yopiq binary'lar uchun **xcframework import** (`apple_static_xcframework_import`), oddiy arxivlar uchun **`http_archive` + integrity**.
- O'lchov (M4 Pro): dependency birinchi marta kompilyatsiya qilinadi (cold 73 s), keyin disk cache bilan 2 s; eng muhimi — o'z kodingizni o'zgartirganda dependency **qayta kompilyatsiya qilinmaydi** (incremental 5 s, atigi 2 action).
- Usulni manba belgilaydi: BCR → `bazel_dep`, SPM → RSPM, yopiq binary → xcframework. Har birining halol narxi bor; kerakdan ortiq dependency qo'shmang (YAGNI).

> **Keyingi dars:** [Bazel 8: Haqiqiy ilova anatomiyasi — resurslar, lokalizatsiya, widget extension, framework, entitlements va signing](/ios-lessons/bazel-08-ilova-anatomiyasi) — endi dependency'larni ula olganimizdan so'ng, haqiqiy ilovaning ichki tuzilishiga — resurslar, lokalizatsiya, widget va signing'ga — o'tamiz.

---

## 17. Manbalar {#manbalar}

1. [Bazel — External dependencies overview](https://bazel.build/external/overview) — modul, repo, registry, repo rule tushunchalari.
2. [Bazel — Bazel modules (MVS, overrides)](https://bazel.build/external/module) — versiya tanlash, `single_version_override`, `local_path_override`, `git_override`, `archive_override`.
3. [Bazel — Bazel registries (BCR)](https://bazel.build/external/registry) — index registry formati, `source.json`, `--registry`.
4. [Bazel — Bazel Lockfile](https://bazel.build/external/lockfile) — `MODULE.bazel.lock`, `--lockfile_mode`, merge conflict.
5. [Bazel — Module extensions](https://bazel.build/external/extension) — `use_extension`, `tag_class`, `use_repo`.
6. [Bazel — `mod` command](https://bazel.build/external/mod-command) — `graph`, `explain`, `show_repo`, `show_extension`.
7. [Bazel — Vendor mode](https://bazel.build/external/vendor) — `bazel vendor`, `VENDOR.bazel`, offline build.
8. [Minimal Version Selection (Russ Cox)](https://research.swtch.com/vgo-mvs) — MVS algoritmining asli (Go modullari).
9. [Bazel 9.0 release notes](https://github.com/bazelbuild/bazel/releases/tag/9.0.0) va [Bazel 9 blog](https://blog.bazel.build/2026/01/20/bazel-9.html) — WORKSPACE olib tashlanishi, Bzlmod default.
10. [rules_apple — `rules-apple.md` (xcframework import)](https://github.com/bazelbuild/rules_apple/blob/main/doc/rules-apple.md) — `apple_static_xcframework_import`, `apple_dynamic_xcframework_import`, `apple_static_xcframework`.
11. [rules_swift_package_manager (cgrindel)](https://github.com/cgrindel/rules_swift_package_manager) — `swift_deps` extension, `bazel mod tidy`, `swiftpkg_<identity>` nomlash, `@swift_package//:resolve`.
12. [Bazel Central Registry](https://registry.bazel.build/) — modullarni qidirish (`rules_apple`, `rules_swift`, `bazel_skylib`...).
13. [apple/swift-collections](https://github.com/apple/swift-collections) — `OrderedCollections`, `DequeModule` (darsdagi SPM misoli).
14. [BuildBuddy — Migrating an iOS app to Bazel (Brentley Jones, 2024)](https://www.buildbuddy.io/blog/how-to-migrate-an-ios-app-to-bazel/) — SPM deps + Gazelle bilan real migratsiya bosqichlari.
15. [Toss case study — "Building less to ship faster"](https://github.com/tuist/tuist/blob/main/server/priv/marketing/case_studies/toss.md) — katta loyihada dependency grafini cache'ga yaroqli ushlash.
