Bazel 9: Xcode bilan ishlash — rules_xcodeproj, indexing, debugging, SwiftUI Preview va VS Code
📦 Bazel iOS — Mukammal Qo‘llanma & Amaliyot
Bazel 9: Xcode bilan ishlash — rules_xcodeproj, indexing, debugging, SwiftUI Preview va VS Code
Holat: 2026-yil oktabr. Bu darsda Bazel bilan build qiladigan iOS loyihasini Xcode IDE ichida ochib, indexing, debugging va test navigator'dan foydalanamiz —
rules_xcodeprojorqali. Kod misollari Bazel 9.3.0, rules_apple 5.3.0, rules_swift 4.2.1, rules_xcodeproj 4.1.0 va Xcode 27.1 bilan Apple M4 Pro'da tekshirilgan.
Bu darsdan keyin siz: Bazel loyihasi uchun
bazel run //:xcodeprojbilan haqiqiy.xcodeprojyaratib, uni Xcode'da yoki VS Code'da ochib, kod yozish va debug qilishni biladigan bo'lasiz.
rules_xcodeprojnega kerakligini va Bazel'ni iOS'da qabul qilishdagi #1 to'siq aynan IDE/DX ekanini tushunasiz (Asana'ning real hikoyasi bilan).xcodeprojqoidasini (project_name,top_level_targets,top_level_target,focused_targets) yozib, loyihani generatsiya qilasiz.- Generatsiya qilingan loyihaning "Build with Bazel" (BwB) modeli qanday ishlashini —
BazelDependenciestarget va "Generate Bazel Dependencies" script phase'ni — ko'rasiz. - Indexing, breakpoint/LLDB va test navigator'dan foydalanasiz; SwiftUI Preview'ning 4.1.0 dagi real holatini (va cheklovini) bilasiz.
- Alternativa sifatida VS Code / Cursor'ni
sourcekit-lsp+ Build Server Protocol orqali Bazel loyihasiga ulashni ko'rasiz.
Mundarija
- Muammo: IDE yo'q bo'lsa, Bazel qabul qilinmaydi
- rules_xcodeproj nima qiladi: "Build with Bazel" modeli
- O'rnatish va birinchi loyiha generatsiyasi
- Generatsiya qilingan loyihani CLI'dan build qilish (BwB)
- Indexing, debugging va test navigator
- SwiftUI Preview: eng katta kamchilik (halol gap)
- .bazelrc config oilasi va command-line API
- Focused projects: katta repo uchun
- Katta loyihaga xos muammolar va signing
- Alternativa: VS Code / Cursor — sourcekit-lsp + BSP
- Amaliy mashqlar
- O'zingizni tekshiring
- Xulosa
- Manbalar
1. Muammo: IDE yo'q bo'lsa, Bazel qabul qilinmaydi {#muammo}
Oldingi darslarda (Bazel 5, Bazel 6, Bazel 8) biz hamma narsani terminaldan qildik: bazel build, bazel test, bazel run. Bu CI uchun ajoyib. Lekin kuniga 8 soat kod yozadigan iOS dasturchi uchun terminal yetarli emas. Unga kerak:
- Autocomplete va jump to definition —
BookCatalog.search(deb yozganda Xcode qaysi parametrlarni kutayotganini ko'rsatishi; - Breakpoint qo'yib,
po book.titledeb o'zgaruvchini tekshirish (LLDB); - Inline xatolar — kompilyatsiya xatosi aynan qaysi qatorda ekanini qizil chiziq bilan ko'rsatishi;
- Test navigator — testni bosib ishga tushirish, yashil/qizil belgilar;
- SwiftUI Preview —
#Previewbloki canvas'da jonli ko'rinishi.
Bu ro'yxat — Bazel'ning emas, Xcode'ning super-kuchlari. Bazel faqat build tizimi: u fayllarni kompilyatsiya qiladi, lekin IDE emas. Shuning uchun Bazel'ni iOS jamoasiga olib kirishdagi eng katta to'siq — tezlik emas, balki IDE/developer experience (DX).
🏢 Real-world: Asana muhandislik jamoasi (2023-yil 21-fevral, "Engineering Team" posti) ~10 muhandis va ~300 000 qator Swift kodini modullarga ajratishdan oldin build tizimini tanlagan. Ular Bazel'dan voz kechib, Tuist'ni tanlagan. Sababi — tezlik emas, DX edi: Bazel ular uchun "juda og'ir (very heavyweight) va yangi mental model talab qiladigan" vosita bo'lgan, eng muhimi — "breakpoint'lar bilan ish jarayonini buzadigan muammolar" bo'lgan. Modullarga ajratgandan keyin o'zgarishdan-simulyatorgacha vaqt odatdagi ~45 soniyadan Scalyr'dagi median ~15 soniyagacha tushgan, Inbox moduli esa 30–50 soniyadan ~4 soniyagacha. Manba: asana.com/inside-asana.
Bu hikoyaning darsimizga aloqasi aniq: agar Bazel loyihasini Xcode'da oddiy loyiha kabi ochib, breakpoint qo'yib, kod to'ldirib ishlata olsangiz — Bazel'ning asosiy kamchiligi yo'qoladi. Aynan shu muammoni rules_xcodeproj hal qiladi.
rules_xcodeproj — Bazel target'laridan haqiqiy .xcodeproj fayl generatsiya qiladigan qoidalar to'plami. U Mobile Native Foundation ostida yuritiladi (dastlab BuildBuddy tomonidan yaratilib, keyin MNF'ga topshirilgan), g'oyasi Google'ning Tulsi'si va Target/Lyft'ning ichki generatorlaridan kelib chiqqan. README'da foydalanuvchi sifatida 19 ta loyiha sanab o'tilgan: Cash App, Lyft, Reddit, Robinhood, Slack, Snap, Spotify, Square, Tinder, Gojek, Mercari, Faire, Envoy Mobile, SwiftLint, amo, BazelPods, Ergatta, Ten Ten, Tokopedia (manba: rules_xcodeproj README, 4.1.0).
🚀 Motivatsiya: Bir buyruq —
bazel run //:xcodeproj— va sizda Bazel build qiladigan, lekin Xcode'da xuddi oddiy loyihadek ochiladigan.apployihasi paydo bo'ladi. Dasturchi Bazel borligini deyarli sezmaydi: u Cmd+R bosadi, breakpoint qo'yadi, kodni to'ldiradi. Jamoangiz CI'da Bazel cache'dan foyda ko'radi, dasturchilar esa odatdagi Xcode'da qoladi.
2. rules_xcodeproj nima qiladi: "Build with Bazel" modeli {#model}
Oddiy Xcode loyihasida Xcode'ning o'z build tizimi (XCBBuildService) kodni kompilyatsiya qiladi. rules_xcodeproj generatsiya qilgan loyihada esa boshqacha: Xcode faqat muharrir va ishga tushiruvchi bo'lib qoladi, haqiqiy build'ni esa Bazel bajaradi. Bu model "Build with Bazel" (BwB) deb ataladi.
Mexanizm shunday ishlaydi: generatsiya qilingan loyihada BazelDependencies degan maxsus target va har bir build'da ishga tushadigan "Generate Bazel Dependencies" nomli Run Script build phase bo'ladi. Xcode "build" tugmasini bosganingizda, bu skript bazel buildni chaqiradi; Bazel haqiqiy ishni qiladi va natijani bazel-out/ga qo'yadi; keyin Xcode o'zining build qadamlarini "stub" qilib (bo'sh o'tkazib) natijani oladi. Xcode'ning serialized diagnostics (ogohlantirish/xato) ma'lumotlari qayta o'ynatiladi, shuning uchun inline xatolar va fix-it'lar ishlaydi.
rules_xcodeproj "Build with Bazel" oqimi: Xcode muharrir va BazelDependencies stub, haqiqiy build'ni Bazel bajaradi, natija bazel-out'dan keladi
Diagrammada: siz Xcode'da Cmd+B bosasiz → BazelDependencies script phase bazel buildni chaqiradi → Bazel action graph'ni hisoblab, faqat o'zgargan narsani kompilyatsiya qiladi (cache'dan foydalanib) → natija bazel-out/ga tushadi → Xcode uni DerivedData'ga nusxalaydi va ishga tushiradi. Indexing va debugging Xcode tomonda qoladi.
Nega bu yaxshi? Chunki Xcode ichidagi build ham, CI'dagi bazel build ham bir xil Bazel action'larini ishlatadi. Ya'ni ularning cache'i umumiy: CI "warm" qilgan cache'dan dasturchining Xcode'i ham foyda ko'rishi mumkin (buni Bazel 10 va Bazel 11 darslarida ko'ramiz). Oddiy Xcode build tizimi bunday umumiy cache'ni bermaydi.
🧠 Esda tuting: 4.x versiyada
xcodeprojqoidasidabuild_modeatributi yo'q. Eski versiyalarda "Build with Xcode" (BwX) — Bazel target'larini Xcode'ning o'z build tizimi orqali qurish — rejimi ham bor edi, lekin 3.0.0 (2025-06-13) "legacy generator" ni olib tashladi va 4.1.0 manba kodidabuild_modeso'zi faqatCHANGELOG.mdda uchraydi. Demak hozir BwB — yagona rejim. (docs/faq.mdda hali ham eski BwX haqida matn qolgan — bu eskirgan, unga ishonmang.)
⚠️ Diqqat:
rules_xcodeprojloyihangiz build qilish usulini o'zgartirmaydi. Uning falsafasi (design-goals.md): "Xcode xususiyatini yoqish uchun target build qilinishini o'zgartirmaymiz." Ya'ni u Bazel graph'ingiz ustiga Xcode qatlamini qo'yadi, xolos. Bu — kuch (barcha target'lar bir xil quriladi), lekin ayni paytda cheklov ham (Xcode'ning ba'zi avtomatik xususiyatlari, masalan SwiftUI Preview, oson ishlamaydi — 6-bo'limga qarang).
3. O'rnatish va birinchi loyiha generatsiyasi {#ornatish}
Biz Bazel 5 darsidagi "Kitoblar" ilovasini qayta ishlatamiz: Core moduli (kitob modeli + qidiruv mantig'i) va App moduli (SwiftUI). Loyiha tuzilishi:
kitoblar/
├── .bazelversion
├── .bazelrc
├── MODULE.bazel
├── BUILD.bazel ← xcodeproj target shu yerda
├── Core/
│ ├── BUILD.bazel
│ ├── Sources/
│ │ ├── Book.swift
│ │ └── BookCatalog.swift
│ └── Tests/
│ └── BookCatalogTests.swift
└── App/
├── BUILD.bazel
├── Info.plist
└── Sources/
├── KitoblarApp.swift
└── BookListView.swift
3.1. MODULE.bazel'ga rules_xcodeproj'ni qo'shish
rules_xcodeprojni boshqa dependency'lar qatorida bazel_dep bilan qo'shamiz. U faqat dasturchining mashinasida, loyiha generatsiya qilishda kerak — CI'dagi bazel buildga ta'sir qilmaydi.
# MODULE.bazel
module(name = "kitoblar", version = "1.0.0")
# apple_support rules_cc'dan yuqorida turishi kerak — birinchi ro'yxatdan
# o'tgan toolchain yutadi.
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")
# Xcode loyihasini generatsiya qilish uchun.
bazel_dep(name = "rules_xcodeproj", version = "4.1.0")
⚠️ Diqqat — mosligini o'zingiz tekshiring:
rules_xcodeproj4.1.0 — 2026-05-07 da chiqqan oxirgi relizi (o'shandan beri 5 oy yangilanish yo'q). Uning README'dagi "Compatibility" jadvali eskirgan: u hali ham Bazel 7.0–9.x, Xcode 13.3–16.x, macOS 13–15.x deb yozadi va "rasman faqat shular bilan sinaldi" deydi. 4.x CHANGELOG'da Xcode 26/27 umuman tilga olinmagan. Shuning uchun biz "4.1.0 Xcode 27.1 bilan rasman mos" deb da'vo qilmaymiz — buni o'zimiz tekshiramiz (quyida). Siz ham o'z Xcode versiyangizda tekshiring.
3.2. xcodeproj target'ini yozish
Ildiz BUILD.bazel fayliga xcodeproj qoidasini qo'shamiz. Eng kam konfiguratsiya — name, project_name va top_level_targets:
# BUILD.bazel
load("@rules_xcodeproj//xcodeproj:defs.bzl", "top_level_target", "xcodeproj")
xcodeproj(
name = "xcodeproj",
project_name = "Kitoblar",
# Bazel bu targetni "//..." ichida tasodifan build qilmasligi uchun.
tags = ["manual"],
top_level_targets = [
top_level_target("//App:Kitoblar", target_environments = ["simulator"]),
"//Core:CoreTests",
],
)
Bu yerda:
top_level_targets— Xcode'da "asosiy" bo'lib ko'rinadigan target'lar ro'yxati. Ularning barcha transitive dependency'lari ham loyihaga tushadi. Bizda ilova (//App:Kitoblar) va test (//Core:CoreTests).top_level_target(label, target_environments = [...])— target'ni qaysi muhit uchun sozlashni aytadi."simulator"yoki"device"(yoki ikkalasi). Agar["device", "simulator"]bersangiz, imkon bo'lsa bitta birlashgan Xcode target yaratiladi. Biz simulyator uchun quramiz.tags = ["manual"]—bazel build //...bu target'ni avtomatik qurmasligi uchun (u dasturchi qo'li bilan ishga tushiriladigan generator).
💡 Pro tip:
project_name = "Kitoblar"— hosil bo'ladigan fayl nomi (Kitoblar.xcodeproj). Agar bermasangiz,name(ya'nixcodeproj) ishlatiladi va faylxcodeproj.xcodeprojbo'lib ketadi — buni istamaysiz.
3.3. Haqiqiy xato: visibility
Agar xcodeproj target ildizda, //App:Kitoblar esa boshqa paketda bo'lsa, birinchi urinishda shunday xato chiqishi mumkin:
Error: target '//App:Kitoblar' is not visible from target
'@@rules_xcodeproj++...rules_xcodeproj_generated//generator/xcodeproj:xcodeproj'
Sabab — rules_xcodeproj ichki ravishda @rules_xcodeproj_generated repo'sida yangi paket yaratadi va sizning target'laringizga murojaat qiladi. FAQ aytganidek, siz murojaat qiladigan target'lar shu paketni ko'ra olishi kerak. Yechim — visibilityga maxsus guruhni qo'shish:
# Core/BUILD.bazel
ios_unit_test(
name = "CoreTests",
minimum_os_version = "17.0",
deps = [":CoreTestsLib"],
# xcodeproj generatsiya qilgan paket shu targetni ko'ra olishi uchun.
visibility = ["@rules_xcodeproj//xcodeproj:generated"],
)
# App/BUILD.bazel
ios_application(
name = "Kitoblar",
bundle_id = "uz.azimjondev.kitoblar",
families = ["iphone"],
infoplists = ["Info.plist"],
minimum_os_version = "17.0",
deps = [":AppLib"],
visibility = ["@rules_xcodeproj//xcodeproj:generated"],
)
🧠 Esda tuting:
"@rules_xcodeproj//xcodeproj:generated"— burules_xcodeprojning rasmiypackage_group'i. Agar barcha target'lar bittaBUILD.bazelda bo'lsa (README'dagi oddiy misoldagi kabi), bu kerak emas. Lekin haqiqiy loyihalar ko'p paketli, shuning uchun bu xatoga albatta duch kelasiz.
3.4. Generatsiya: bazel run //:xcodeproj
Endi loyihani generatsiya qilamiz:
bazel run //:xcodeproj
Birinchi marta bu buyruq uzoq ishlaydi — chunki Bazel rules_xcodeprojning generator vositasini (Swift'da yozilgan) va u bog'liq bo'lgan kutubxonalarni (jumladan, 4.1.0 bilan birga keladigan rsync'ni) noldan kompilyatsiya qiladi. Bizning o'lchovimiz:
INFO: Elapsed time: 181.209s, Critical Path: 11.49s
INFO: 1481 processes: 4 disk cache hit, 158 internal, 1319 local.
INFO: Build completed successfully, 1481 total action
INFO: Running command line: .../rules_xcodeproj.noindex/build_output_base/.../xcodeproj-installer.sh
Updated project at "Kitoblar.xcodeproj"
Natija: Updated project at "Kitoblar.xcodeproj" — loyiha hosil bo'ldi! (Apple M4 Pro, Xcode 27.1, bo'sh output base. Bu 181 soniya — bir martalik narx: generator keshga tushgach, keyingi generatsiyalar bir necha soniya.)
📊 Real raqamlar:
BUILD.bazelga bitta qator qo'shib (yangi fayl/target qo'shishni taqlid qilib) qayta generatsiya qilganda — generator allaqachon kompilyatsiya qilingani uchun — bizda 8.75 soniya (real 8.75) ketdi. Ya'ni kundalik "BUILD o'zgartirdim → qayta generatsiya" aylanmasi arzon.
3.5. Loyihada nimalar paydo bo'ldi
Generatsiyadan keyin ildizda Kitoblar.xcodeproj paydo bo'ladi. Uning ichida (eslatma: aksariyat fayllar rules_xcodeproj/ ichida — bu normal):
Kitoblar.xcodeproj/
├── project.pbxproj
├── project.xcworkspace/
├── xcshareddata/xcschemes/
│ ├── Core.xcscheme
│ ├── CoreTests.xcscheme
│ └── Kitoblar.xcscheme
├── rules_xcodeproj/
│ └── bazel/
│ ├── xcodeproj.bazelrc ← config oilasi shu yerda (7-bo'lim)
│ └── ... (BwB uchun skriptlar)
└── xcuserdata/
xcodebuild -list bilan tekshirsak (bizning haqiqiy natijamiz):
Targets:
BazelDependencies ← BwB "ko'prigi" (stub target)
Core
CoreTests
Kitoblar
Schemes:
Core
CoreTests
Kitoblar
BazelDependencies — biz 2-bo'limda aytgan BwB target. Qolgan uchtasi — sizning target'laringiz. Har bir "buildable" target uchun avtomatik scheme yaratildi (bu scheme_autogeneration_mode = "auto" standart xatti-harakati).
Loyihaning Swift kodi oddiy (bu Bazel 5dan):
// Core/Sources/BookCatalog.swift
public struct BookCatalog: Sendable {
public private(set) var books: [Book]
public init(books: [Book] = BookCatalog.sample) {
self.books = books
}
public func search(_ query: String) -> [Book] {
guard !query.isEmpty else { return books }
let q = query.lowercased()
return books.filter {
$0.title.lowercased().contains(q) || $0.author.lowercased().contains(q)
}
}
// ... (to'liq versiya loyihada)
}
Va swift_library BUILD bo'lagi:
# Core/BUILD.bazel
load("@rules_swift//swift:swift.bzl", "swift_library")
load("@rules_apple//apple:ios.bzl", "ios_unit_test")
swift_library(
name = "Core",
srcs = glob(["Sources/**/*.swift"]),
module_name = "Core",
visibility = ["//visibility:public"],
)
4. Generatsiya qilingan loyihani CLI'dan build qilish (BwB) {#build}
Odatda loyihani Xcode'da (open Kitoblar.xcodeproj) ochib, Cmd+B bosasiz. Lekin biz avval terminalda tekshiramiz — bu CI uchun ham muhim va "haqiqatan ishladi" degan dalil beradi. xcodebuildni ishlatamiz:
xcodebuild \
-project Kitoblar.xcodeproj \
-scheme Kitoblar \
-destination 'generic/platform=iOS Simulator' \
-derivedDataPath .dd \
build
Natijaning oxiri (bizning haqiqiy chiqishimiz, Xcode 27.1):
note: Run script build phase 'Generate Bazel Dependencies' will be run during
every build because the option to run the script phase "Based on dependency
analysis" is unchecked. (in target 'BazelDependencies' from project 'Kitoblar')
note: Run script build phase 'Copy Bazel Outputs / Generate Bazel Dependencies
(Index Build)' will be run during every build ... (in target 'Kitoblar' ...)
** BUILD SUCCEEDED **
**** BUILD SUCCEEDED **** — generatsiya qilingan loyiha Xcode 27.1 da muvaffaqiyatli quriladi! Chiqishda BwB mexanizmini aniq ko'ramiz:
'Generate Bazel Dependencies'script phase —BazelDependenciestarget ichida, har build'da ishlaydi (chunki "Based on dependency analysis" o'chirilgan — bu ataylab, Bazel o'zi qaror qiladi);'Copy Bazel Outputs ...'— Bazel natijalarini Xcode'ning DerivedData'siga ko'chiradi.
App bundle bazel-out/ios_sim_arm64-dbg-.../bin/App/Kitoblar.appda paydo bo'ladi — ya'ni haqiqiy ishni Bazel qilgan, Xcode faqat uni o'rab olgan.
📊 Real raqamlar (Apple M4 Pro, 12 core, 24 GB; Xcode 27.1; Bazel 9.3.0; rules_xcodeproj 4.1.0):
| Amal | Vaqt | Izoh | | -------------------------------------------------- | ------------------ | --------------------------------------------------------------- | |
bazel run //:xcodeproj(birinchi) | 181.2 s | generator + rsync'ni noldan kompilyatsiya qiladi (bir martalik) | | qayta generatsiya (BUILD o'zgardi) | 8.75 s | generator keshda | |xcodebuild ... build(birinchi, BwB) | ✅ BUILD SUCCEEDED | to'liq Bazel build | |xcodebuild ... build(o'zgarishsiz, incremental) | 1.99 s | BwB stub tez o'tadi | |xcodebuildqayta generatsiyadan keyin | 90.8 s | DerivedData bekor bo'ldi → to'liq qayta build |Oxirgi qator muhim: loyihani qayta generatsiya qilsangiz, Xcode'ning DerivedData'si bekor bo'ladi va keyingi build to'liq bo'ladi (quyida 9-bo'limga qarang).
**⚠️ Diqqat — har doim
-derivedDataPathbering:** biz-derivedDataPath .ddberdik, ya'ni DerivedData loyiha ichidagi.ddpapkaga tushadi. Bu — izolyatsiya uchun yaxshi odat (ayniqsa CI'da): umumiy~/Library/Developer/Xcode/DerivedDatani ifloslantirmaysiz.
5. Indexing, debugging va test navigator {#indexing}
Endi open Kitoblar.xcodeproj qilib Xcode'da ochamiz. rules_xcodeproj README'si va'da qiladigan xususiyatlar: indexing, debugging, runtime sanitizer'lar, inline ogohlantirish/xatolar, test tanlash va ishga tushirish, embedded target'lar (App Clip, extension, Watch), dynamic framework'lar va Xcode Previews. Qaysilari haqiqatan ishlaydi? Keling, mexanizmini ko'raylik.
5.1. Indexing (autocomplete, jump to definition)
Indexing — Xcode kodingizni "tushunishi": catalog. deb yozganingizda metodlar ro'yxati, BookCatalogni Cmd+bosib ta'rifiga o'tish, syntax rang berish. Buning uchun Xcode fayl bo'yicha kompilyatsiya qila olishi kerak.
rules_xcodeproj buni "Index Build" (Prepare for Indexing) orqali hal qiladi: Xcode fonda loyihani alohida output papkaga quradi, indexing uchun kerakli artefaktlarni tayyorlaydi. Generatsiya qilingan xcodeproj.bazelrcda buni ko'rsatuvchi feature'lar bor (bizning fayldan):
common:rules_xcodeproj --features=swift.index_while_building
common:rules_xcodeproj --features=swift.use_global_index_store
common:rules_xcodeproj_indexbuild --config=rules_xcodeproj
common:rules_xcodeproj_indexbuild --bes_backend= --bes_results_url=
swift.index_while_building— Swift kompilyatori build paytida index store yozib boradi;swift.use_global_index_store— index'ni umumiy joyda saqlaydi (qayta ishlatish uchun);rules_xcodeproj_indexbuildconfig — Index Build fonda tez-tez ishlagani uchun telemetriyani (BES upload'ni) o'chiradi.
xcodeproj qoidasida import_index_build_indexstores atributi standart holatda True — bu Index Build hosil qilgan index store'larni import qilib, Xcode'ning indekslashini tezlashtiradi. Agar disk IO ko'p bo'lsa va arzimasa, uni False qilishingiz mumkin.
💡 Pro tip: birinchi marta loyihani ochganingizda Xcode biroz "o'ylaydi" — bu Index Build. Bir marta tugagach, autocomplete va jump-to-definition oddiy Xcode kabi ishlaydi. Agar indexing "qotib qolsa", Xcode'ni yopib-ochish yoki loyihani qayta generatsiya qilish yordam beradi.
5.2. Debugging (breakpoint, LLDB)
rules_xcodeprojning asosiy maqsadi (design-goals.md so'zlari bilan) — "target'larni ishga tushirish va debug qilishni qo'llab-quvvatlash". Esingizda bo'lsa, Asana aynan breakpoint muammosi tufayli Bazel'dan voz kechgan edi — rules_xcodeproj esa shu muammoni hal qilish uchun yaratilgan.
Amalda: BookCatalog.searchga breakpoint qo'yasiz, Cmd+R bilan ilovani simulyatorda ishga tushirasiz, qidiruv maydoniga "kunlar" yozasiz — Xcode breakpoint'da to'xtaydi, siz po q yoki po books.count deb LLDB'da tekshirasiz. Bu oddiy Xcode debug tajribasi, farqi — binar'ni Bazel qurgan.
🧠 Esda tuting: BwB rejimida debug ma'lumotlari (
.dSYM, serialized diagnostics) Bazel tomonidan hosil qilinadi va Xcode'ga uzatiladi.xcodeproj.bazelrcdagi--features=oso_prefix_is_pwdva--features=relative_ast_path— aynan debugging/indexing yo'llarini to'g'ri xaritalash uchun.
5.3. Test navigator
//Core:CoreTests target uchun avtomatik CoreTests scheme yaratilgani uchun, Xcode'ning Test navigator'ida (Cmd+6) testlar ko'rinadi. Bizning testlar:
// Core/Tests/BookCatalogTests.swift
final class BookCatalogTests: XCTestCase {
func testSearchByTitle() {
let catalog = BookCatalog()
let results = catalog.search("kunlar")
XCTAssertEqual(results.count, 1)
XCTAssertEqual(results.first?.author, "Abdulla Qodiriy")
}
func testSortByYear() {
let catalog = BookCatalog()
XCTAssertEqual(catalog.sorted(by: \.year).first?.year, 1925)
}
}
Test yonidagi olmosni bosib bitta testni, yoki butun klassni ishga tushirasiz. Natija yashil/qizil belgi bilan ko'rinadi. Ichkarida bu bazel test bilan bir xil ishni qiladi (test cache haqida Bazel 6da).
⚠️ Diqqat — coverage va cache: agar Xcode'da "Gather coverage data" ni yoqsangiz,
rules_xcodeproj_coverageconfig ishga tushadi. Hujjat ogohlantiradi: coverage build'lari manba fayllarga mutlaq (absolute) yo'llar yozadi, bu esa hermetik emas va cache hit'larni kamaytiradi. Tavsiya: coverage'ni Xcode'da faqat faol ishlatganda yoqing; aks holda coverage'ni oddiybazel coverage(CLI) orqali oling.
6. SwiftUI Preview: eng katta kamchilik (halol gap) {#preview}
rules_xcodeproj README'si xususiyatlar ro'yxatida "Xcode Previews"ni sanaydi. Lekin 4.1.0 da SwiftUI Preview — eng katta DX kamchiligi. Buni ochiq aytamiz, chunki bu ko'p dasturchini hafsalasini pir qiladi.
Bizning BookListViewda #Preview bor:
// App/Sources/BookListView.swift
#Preview {
BookListView(catalog: BookCatalog())
}
Oddiy Xcode loyihasida bu canvas'da jonli ko'rinardi. rules_xcodeproj loyihasida esa — ishlamaydi. Sabab mexanizmda: Xcode 16+ SwiftUI Preview'lari ishlashi uchun ENABLE_DEBUG_DYLIB = YES build setting kerak. Lekin rules_xcodeproj buni NO qilib qo'yadi. Biz buni generatsiya qilingan project.pbxprojda o'z ko'zimiz bilan tekshirdik:
grep -o "ENABLE_DEBUG_DYLIB = [A-Z]*" Kitoblar.xcodeproj/project.pbxproj | sort | uniq -c
1 ENABLE_DEBUG_DYLIB = NO
Bu rules_xcodeprojda ataylab qo'yilgan (#3042 — "Xcode 16'ni to'g'ri qo'llab-quvvatlagunimizcha"). Natija: #Preview bloklari canvas'da render bo'lmaydi.
Holat (2026-oktabr, tekshirilgan):
- Issue #3201 "Feature Request: Xcode SwiftUI Preview Support" — 2025-06-20 da ochilgan, hali ham ochiq (oxirgi faollik 2026-09-17).
- Native preview'ni qo'shish uchun urinilgan PR'lar (
#3348"opt-in native Xcode Preview configurations" (draft),#3325) 2026-10-13 holatiga yopilgan, lekin merge qilinmagan. Ya'ni 4.1.0 da native Preview chiqmagan. xcodeproj.bazelrcdarules_xcodeproj_swiftuipreviewsconfig bor (u-enable-implicit-dynamic,-enable-private-imports,-enable-dynamic-replacement-chainingcopt'larini qo'shadi), lekinENABLE_DEBUG_DYLIB = NOtufayli Xcode 16+/27 da bu to'liq preview tajribasini bermaydi.
⚠️ Diqqat: Agar sizning ishingiz SwiftUI Preview'ga juda bog'liq bo'lsa (masalan, dizayn-og'ir ekranlar ustida ishlayotgan bo'lsangiz), Bazel + rules_xcodeproj 4.1.0 bu borada sizni cheklaydi. Amaldagi yechimlar: (1) ilovani simulyatorda tez-tez ishga tushirish (hot reload o'rniga); (2) preview-og'ir modullar uchun alohida kichik SwiftPM/Xcode loyihasi saqlash; (3)
rules_xcodeprojning yangi relizlarini kuzatib borish — Preview ustida ish ketyapti, lekin hali chiqmagan. Buni loyiha tanlashda hisobga oling (20-dars, Bazel vs Tuist).
🧠 Esda tuting — nega shunday:
rules_xcodeprojfalsafasi (design-goals.md) aniq aytadi: "Xcode xususiyatini yoqish uchun target build qilinishini o'zgartirmaymiz." SwiftUI Preview static kutubxonalar bilan ishlamaydi varules_xcodeprojsizning target'ingiz mahsulot turini o'zgartirib qo'ymaydi. Bu — printsipial tanlov: natijabazel buildbilan bir xil bo'lishi preview qulayligidan muhimroq deb hisoblanadi.
7. .bazelrc config oilasi va command-line API {#configlar}
7.1. Config oilasi
Generatsiya qilinganda Kitoblar.xcodeproj/rules_xcodeproj/bazel/xcodeproj.bazelrc fayli yaratiladi. Unda bir oila config bor — har biri --config= orqali chaqiriladi:
| Config | Qachon ishlaydi | Nima qiladi |
|---|---|---|
rules_xcodeproj | Xcode ichida har build | Asosiy config; qolganlari undan meros oladi |
rules_xcodeproj_generator | bazel run //:xcodeproj paytida | Generatsiya (build'ga ta'sir qilmaydigan sozlamalar) |
rules_xcodeproj_indexbuild | Xcode Index Build (fon) | Telemetriya/log'ni o'chiradi (tez-tez ishlaydi) |
rules_xcodeproj_swiftuipreviews | Xcode Preview build | Preview uchun maxsus copt'lar |
rules_xcodeproj_coverage | Coverage yoqilgan test build | Coverage ma'lumotini mutlaq yo'llar bilan yozadi |
Asosiy config'ning bir qismi (bizning generatsiya qilingan fayldan):
common:rules_xcodeproj --verbose_failures
common:rules_xcodeproj --cache_computed_file_digests=500000
common:rules_xcodeproj --compilation_mode=dbg
common:rules_xcodeproj --features=swift.index_while_building
common:rules_xcodeproj --features=swift.use_global_index_store
common:rules_xcodeproj --spawn_strategy=remote,worker,local
build:rules_xcodeproj --remote_download_outputs=toplevel
💡 Pro tip: biror build flag'ni Xcode ichidagi build uchun ham, generatsiya uchun ham qo'shmoqchi bo'lsangiz — uni
common:rules_xcodeproj(asosiy config) ga qo'ying, chunki qolganlari undan meros oladi. Hujjat ogohlantiradi: "build'ga ta'sir qiluvchi flag'lar barcharules_xcodeproj{_*}config'larda bir xil bo'lishi kerak", shuning uchun odatda asosiy config'ni o'zgartirasiz. O'zingizning sozlamalaringizni ildiz.bazelrcingizdagicommon:rules_xcodeproj --...qatorlariga yozishingiz mumkin.
7.2. rules_xcodeproj o'zining alohida output base'ida ishlaydi
Muhim nozik jihat: rules_xcodeproj Xcode ichida qurar ekan, u alohida output base ishlatadi. Buning sababi — Xcode build'lari sizning oddiy bazel buildlaringizning analysis cache'ini buzmasligi uchun. Buni command-line API bilan tekshirdik:
bazel run //:xcodeproj -- 'info output_path'
INFO: Elapsed time: 1.739s, Critical Path: 0.04s
/Users/.../Caches/bazel/_bazel_codingtech/<hash>/rules_xcodeproj.noindex/build_output_base/execroot/_main/bazel-out
E'tibor bering: yo'lda rules_xcodeproj.noindex/build_output_base bor — bu sizning oddiy bazel-outingiz emas, alohida muhit.
7.3. Command-line API
Shu alohida muhitda buyruq berish uchun maxsus API bor:
bazel run //:xcodeproj -- [variantlar] 'buyruq matni'
Foydali misollar:
# rules_xcodeproj muhitida output_path'ni ko'rsatish (yuqorida)
bazel run //:xcodeproj -- 'info output_path'
# rules_xcodeproj output base'ini tozalash (oddiy "bazel clean" buni tozalamaydi!)
bazel run //:xcodeproj -- clean
# CI'da cache'ni "warm" qilish uchun barcha target'larni qurish
bazel run //:xcodeproj -- --generator_output_groups=all_targets 'build --remote_download_minimal'
⚠️ Diqqat: oddiy
bazel cleanrules_xcodeprojning alohida output base'ini tozalamaydi. Agar Xcode ichidagi build'da g'alati muammo bo'lsa,bazel run //:xcodeproj -- cleanni ishlating (yoki butunlay hammasini tozalaydiganbazel clean --expunge). Bu — yangi boshlovchilar ko'p adashadigan joy.
💡 Pro tip (CI uchun):
--generator_output_groups=all_targetsbilan cache warming — Bazel 11 darsining muhim qismi. BuildBuddy'ning migratsiya qo'llanmasi (Brentley Jones, 2024) aytganidek: "rules_xcodeprojCLI'dan biroz boshqacha konfiguratsiya bilan quradi, shuning uchun CI cache'ini aynanrules_xcodeprojbuyrug'i orqali warm qilish kerak." Aks holda dasturchining Xcode'i cache'dan to'liq foyda ko'rmaydi.
8. Focused projects: katta repo uchun {#focused}
Katta monorepo'da (yuzlab target) hamma target'ni Xcode'ga tiqish — loyihani og'irlashtiradi va indexing'ni sekinlashtiradi. Yechim — Focused Projects: Xcode'ga faqat siz hozir ustida ishlayotgan target'larni qo'yish, qolganlarini Bazel binar sifatida qurish.
xcodeproj qoidasida ikkita atribut shu uchun:
focused_targets— faqat shu target'lar (va ularga kerakli narsalar) Xcode'ga tushadi; qolganlari "unfocused" bo'ladi.unfocused_targets— aksincha, faqat shu target'larni Xcode'dan chiqarib tashlaydi.
Masalan, agar siz faqat Appustida ishlayotgan bo'lsangiz, lekin Coreni Bazel qursin desangiz:
# BUILD.bazel
xcodeproj(
name = "xcodeproj",
project_name = "Kitoblar",
tags = ["manual"],
top_level_targets = [
top_level_target("//App:Kitoblar", target_environments = ["simulator"]),
"//Core:CoreTests",
],
# Core'ni Xcode'da ko'rsatmaymiz — u Bazel tomonidan binar sifatida quriladi.
unfocused_targets = ["//Core:Core"],
)
🧠 Esda tuting: "Unfocused" target'lar yo'qolmaydi — ular hamon Bazel tomonidan quriladi va ilovaga ulanadi. Shunchaki Xcode navigator'ida ularning manba fayllarini ko'rmaysiz. Bu Xcode loyihasini yengillashtiradi: kamroq fayl, tezroq indexing, kamroq scheme.
💡 Pro tip: katta jamoalarda
focused_targetsni dinamik qilib qo'yishadi — har dasturchi o'zi ishlayotgan modullarni environment variable yoki alohida.bzlfayl orqali ko'rsatadi.rules_xcodeprojdesign-goals.md aynan shuni tavsiya qiladi: "dinamik holatlar uchun.bzlfayllarni generatsiya qilib, ulardagi macro'lar orqali kerakli target'larni yarating." Shunda har kim o'ziga kerakli "kichik" loyiha oladi, lekin cache umumiy qoladi.
9. Katta loyihaga xos muammolar va signing {#muammolar}
rules_xcodeproj kuchli, lekin kamchiliksiz emas. Mana halol kamchiliklar ro'yxati (hammasi hujjat yoki bizning tajribamizdan):
9.1. Archive ishlamaydi — .ipa'ni Bazel bilan quring
Xcode'ning Product > Archive > Organizer oqimi rules_xcodeproj loyihalarida qo'llab-quvvatlanmaydi. FAQ ochiq aytadi: "Hozircha Archive action'ni to'g'ri ishlashiga kuch sarflanmagan" va optimizatsiyalar hosil bo'ladigan .xcarchiveni buzishi mumkin.
Yechim — App Store uchun .ipani to'g'ridan-to'g'ri bazel build bilan quring:
# Release build (device uchun, arm64)
bazel build //App:Kitoblar -c opt --ios_multi_cpus=arm64
Biz simulyator uchun .ipani allaqachon qurgandik (FACTS tasdiqlaydi):
Target //App:Kitoblar up-to-date:
bazel-bin/App/Kitoblar.ipa (149 KB)
⚠️ Diqqat — device signing: haqiqiy qurilma/App Store uchun kod imzolash kerak. Bu Apple Developer hisobini talab qiladi, shuning uchun biz uni bu yerda hujjat asosida tushuntiramiz (bizning muhitda device signing tekshirilmagan). Bazel 8da signing'ni ko'rgandik; releasi va Fastlane esa Bazel 11da.
9.2. Signing: xcode_provisioning_profile
Bazel'da signing Xcode'ning "Automatically manage signing"idan boshqacha ishlaydi. ios_applicationda provisioning_profile atributi bo'ladi (odatda local_provisioning_profile bilan to'ldiriladi). Agar Xcode boshqaradigan profilni ishlatmoqchi bo'lsangiz, rules_xcodeprojga buni aytish uchun uni xcode_provisioning_profile bilan o'raysiz:
ios_application(
name = "Kitoblar",
# ...
provisioning_profile = ":xcode_profile",
)
xcode_provisioning_profile(
name = "xcode_profile",
managed_by_xcode = True,
provisioning_profile = ":provisioning_profile",
)
local_provisioning_profile(
name = "provisioning_profile",
profile_name = "iOS Team Provisioning Profile: uz.azimjondev.kitoblar",
team_id = "A12B3CDEFG",
)
managed_by_xcode = True — Xcode'da "Automatic Code Signing" yoqiladi; team_id esa DEVELOPER_TEAM build setting'ini belgilaydi. FAQ eslatadi: profil ~/Library/MobileDevice/Provisioning Profilesga o'rnatilgan bo'lishi kerak, aks holda Xcode "couldn't find any provisioning profiles matching 'TEAM_ID/PROFILE_NAME'" deydi.
9.3. BUILD o'zgarsa — qayta generatsiya kerak
Bu — eng muhim kundalik cheklov. BUILD.bazelni o'zgartirsangiz (yangi fayl, yangi dependency, yangi target), Xcode loyihasi avtomatik yangilanmaydi — bazel run //:xcodeprojni qayta ishga tushirishingiz kerak. Bizning o'lchovimizda bu arzon (8.75 s), lekin qayta generatsiyadan keyin Xcode'ning DerivedData'si bekor bo'ladi va keyingi build to'liq bo'ladi (biz buni ko'rdik: o'zgarishsiz incremental 1.99 s edi, lekin qayta generatsiyadan keyin 90.8 s to'liq build).
⚠️ Diqqat: yangi Swift faylini modulning mavjud
Sources/papkasiga qo'shsangiz vaBUILD.bazeldaglob(["Sources/**/*.swift"])ishlatgan bo'lsangiz — target o'zgaradi, lekin Xcode uni ko'rishi uchun baribir qayta generatsiya kerak. (Tuist'ning "buildable folders" xususiyati bu muammoni yumshatadi — Tuist darslariga qarang. Bazel tomonda yangi "synchronized folders" ustida ish ketyapti, lekin 4.1.0 da chiqmagan.)
9.4. Stale fayllar va build mode
FAQ yana ikki nozik holatni aytadi:
- Stale fayllar: agar dependency o'chirsangiz yoki fayl yo'li o'zgarsa va loyihani yopib-ochmasdan qayta generatsiya qilsangiz, Xcode eski yo'llar haqida ogohlantirishi mumkin (bu Xcode'ning caching bug'i). Yechim — loyihani yopib-ochish yoki clean build.
- Har modulning manbasi o'z papkasida bo'lishi kerak (BuildBuddy qo'llanmasi):
glob()paket chegarasidan o'tmaydi, shuning uchun aralash tuzilishlar muammo beradi.
9.5. Kamchiliklar jadvali (halol xulosa)
| Kamchilik | Ta'siri | Nega |
|---|---|---|
| SwiftUI Preview ishlamaydi | Dizayn-og'ir ish qiyinlashadi | ENABLE_DEBUG_DYLIB = NO (PR #3042); #3201 ochiq |
| Archive yo'q | App Store'ga .ipani Bazel quradi | FAQ: Archive qo'llab-quvvatlanmaydi |
| BUILD o'zgarsa qayta generatsiya | Kichik ortiqcha qadam | loyiha BUILD fayllardan generatsiya qilinadi |
| Qayta generatsiya → DerivedData bekor | Keyingi build to'liq | Xcode caching |
| Coverage mutlaq yo'llar yozadi | Cache hit kamayadi | hermetik emas |
| Majorlar tez-tez buziladi | Yangilashda ehtiyot | 2.0→3.0→4.0 ~2 yilda |
| README jadvali eskirgan | Xcode 27 "rasman" sinalmagan | o'zingiz tekshiring |
🏢 Real-world:
rules_ios(muqobil iOS ruleset) ni Square tark etyapti: muhokama #952da (2025-11-07) aytilishicha, ular "faol hissa qo'shishni to'xtatadi", chunki "rules_ioskamroq maqsadga xizmat qilyapti va build'ga ortiqcha murakkablik qo'shyapti" — zero rules_apple va rules_swift kerakli funksiyalarni olgan.rules_xcodeproj4.0.0 ham o'ziningrules_iosmisolini olib tashlagan. Xulosa: bugun rules_apple + rules_swift + rules_xcodeproj — standart yo'l.
10. Alternativa: VS Code / Cursor — sourcekit-lsp + BSP {#vscode}
Hamma ham Xcode'ni yoqtirmaydi. Ba'zilar VS Code yoki Cursor'da (yoki AI agent, masalan Claude Code'da) ishlashni afzal ko'radi. Bu ham mumkin — sourcekit-lsp (Swift'ning rasmiy Language Server'i) orqali.
Muammo: sourcekit-lsp kodingiz qanday qurilishini bilishi kerak (qaysi flag'lar, qaysi modullar). Oddiy SwiftPM loyihada buni o'zi tushunadi, lekin Bazel loyihasida yo'q. Bu bo'shliqni Build Server Protocol (BSP) to'ldiradi: BSP server sourcekit-lspga "bu fayl shunday quriladi" deb aytadi.
Bazel uchun bunday BSP server bor: **spotify/sourcekit-bazel-bsp** (Apache-2.0, Spotify ochiq kodi, misol versiya 0.8.3). Zanjir shunday:
Cursor / VSCode / Claude Code
│
▼
sourcekit-lsp ──► sourcekit-bazel-bsp (BSP server) ──► Bazel
Uch xil IDE varianti: Xcode + rules_xcodeproj, VS Code/Cursor + sourcekit-bazel-bsp, oddiy Xcode loyihasi + xcode-build-server — har birining ishlaydigan va ishlamaydigan tomoni
10.1. Nima ishlaydi
sourcekit-bazel-bsp README'siga ko'ra:
- Barcha IDE + Claude: odatdagi indexing xususiyatlari — code completion, jump to definition (Swift, Obj-C, C++ uchun).
- Faqat Cursor / VSCode: build qilish, ishga tushirish, debug (
lldb-daporqali), test, hamda simulyator boshqaruvi — IDE ichidan (ixtiyoriy "companion extension" orqali).
10.2. Sozlash (qisqa)
MODULE.bazelga dependency qo'shiladi va BUILD'da setup_sourcekit_bsp qoidasi e'lon qilinadi:
# MODULE.bazel
bazel_dep(name = "sourcekit_bazel_bsp", version = "0.8.3")
# BUILD.bazel
load("@sourcekit_bazel_bsp//rules:setup_sourcekit_bsp.bzl", "setup_sourcekit_bsp")
setup_sourcekit_bsp(
name = "setup_sourcekit_bsp",
files_to_watch = ["App/**/*.swift", "Core/**/*.swift"],
targets = ["//App:Kitoblar"],
)
# BSP sozlamasini yaratish (qoida argumentlari o'zgarsa qayta ishga tushiring)
bazel run //:setup_sourcekit_bsp
Keyin VS Code / Cursor'da Swift extension o'rnatiladi va .vscode/settings.jsonda sourcekit-lsp binary yo'li ko'rsatiladi; "Swift: Restart LSP Server" bosiladi. Talablar: Swift 6.1+ toolchain (Xcode 16.4+ ekvivalenti), Xcode baribir o'rnatilgan bo'lishi kerak.
⚠️ Diqqat — bu tekshirilmagan: biz bu bo'limni
sourcekit-bazel-bspREADME'si va Swift forumlari asosida tushuntirdik; o'z muhitimizda sinab ko'rmadik (u alohida o'rnatish va toolchain talab qiladi). Shuning uchun aniq buyruqlar versiyaga qarab o'zgarishi mumkin — repo'ni tekshiring.
10.3. Cheklovlar (README + forum)
- Faqat Bazel loyihalari uchun — oddiy Xcode loyihalarida ishlamaydi (ular uchun
xcode-build-server). - WMO (Whole Module Optimization) ishlatmang — u indexing'ni buzadi.
- Birinchi indexing sekin — katta loyihada "to'liq indexing uzoq vaqt olishi mumkin".
//...kabi keng wildcard'lardan qoching. - SwiftPM va Swiftly integratsiyalarini o'chiring — ular BSP bilan to'qnashadi.
- Xcode'ning o'z
sourcekit-lspidan foydalaniladi — "Xcode bilan hali kelmagan LSP xususiyatlari" bo'lishi mumkin, ya'ni performans va qulaylikda murosalar. - Forumda xabar qilingan real muammo: Xcode 26.0.1 ga yangilangandan keyin har Swift faylda "Loading the standard library failed" xatosi (sourcekit-lsp issue #2328); katta iOS loyihada Bazel chaqiruvlari o'rtacha 30 soniya–1 daqiqa, completion shu vaqtda "qotadi".
10.4. Oddiy Xcode loyihasi + xcode-build-server (uchinchi variant)
Agar sizda Bazel generatsiya qilgan .xcodeproj bor bo'lsa-yu, lekin VS Code'da ishlamoqchi bo'lsangiz, uchinchi yo'l bor: xcode-build-server — har qanday Xcode loyihasidan (jumladan Bazel generatsiya qilgani) BSP orqali sourcekit-lspni ishlata oladi. sourcekit-bazel-bsp README'si oddiy Xcode loyihalari uchun aynan shuni tavsiya qiladi.
10.5. Taqqoslash jadvali
| Xcode + rules_xcodeproj | VS Code/Cursor + sourcekit-bazel-bsp | |
|---|---|---|
| Muharrir | Xcode (tanish) | VS Code / Cursor / Claude |
| Indexing | ✅ (Index Build) | ✅ (Swift/ObjC/C++) |
| Build/Run | ✅ Cmd+R | ✅ (Cursor/VSCode) |
| Debug | ✅ LLDB | ✅ lldb-dap (Cursor/VSCode) |
| Test navigator | ✅ | ✅ (Cursor/VSCode) |
| SwiftUI Preview | ❌ (4.1.0) | ❌ |
| Yetuklik | Yuqori (19 kompaniya) | Yangiroq (Spotify, 0.8.x) |
| Birinchi indexing | Index Build | sekin (katta loyihada) |
| AI agent (Claude) | — | ✅ indexing |
🚀 Motivatsiya: AI agent'lar davrida
sourcekit-bazel-bspning muhim yutug'i — u Claude kabi agent'larga LSP integratsiyasi orqali "kod aqlini" beradi. Ya'ni agent sizning Bazel loyihangizda jump-to-definition va completion'dan foydalanib, kodni to'g'riroq o'zgartiradi. Bu rules_xcodeproj (Xcode-markazli) bera olmaydigan narsa.
💡 Pro tip — qaysi birini tanlash: jamoangiz Xcode'ga o'rgangan bo'lsa va breakpoint/test navigator muhim bo'lsa — rules_xcodeproj (sinovdan o'tgan, keng tarqalgan). Dasturchilaringiz VS Code/Cursor/AI-agent'ni afzal ko'rsa va WMO'siz yashay olsangiz — sourcekit-bazel-bsp. Ko'pincha jamoalar ikkala yo'lni ham ochiq qoldiradi: bitta Bazel graph, ikki xil muharrir.
Amaliy mashqlar {#mashqlar}
- Loyihani generatsiya qiling. Bazel 5dagi "Kitoblar" ilovangizga
rules_xcodeproj4.1.0 ni qo'shing, ildizBUILD.bazelgaxcodeprojtarget yozing vabazel run //:xcodeprojbilan loyihani yarating.open Kitoblar.xcodeprojqilib, ilovani simulyatorda (Cmd+R) ishga tushiring. - Visibility xatosini ataylab keltirib chiqaring.
//App:Kitoblartarget'idanvisibility = ["@rules_xcodeproj//xcodeproj:generated"]ni olib tashlang va qayta generatsiya qiling. Xatoni o'qing, keyin visibility'ni qaytaring. Maqsad: xatoni tanish. - Breakpoint va LLDB.
BookCatalog.searchmetodiga breakpoint qo'ying, ilovani ishga tushirib qidiruvda biror so'z yozing. To'xtaganda LLDB konsolidapo qvapo books.countni sinang. Natijani yozib qo'ying. - Command-line API.
bazel run //:xcodeproj -- 'info output_path'vabazel run //:xcodeproj -- cleanni ishlating. Birinchisi ko'rsatgan yo'ldarules_xcodeproj.noindexborligini tasdiqlang. Nega oddiybazel-outdan farq qilishini bir jumlada tushuntiring. - ⭐ Focused project.
unfocused_targets = ["//Core:Core"]qo'shib qayta generatsiya qiling. Xcode navigator'idaCoremodulining manba fayllari yo'qolganini, lekin ilova baribir qurilib ishlashini tekshiring. Qachon bu foydali ekanini yozing. - ⭐ SwiftUI Preview holatini tekshiring.
grep -o "ENABLE_DEBUG_DYLIB = [A-Z]*" Kitoblar.xcodeproj/project.pbxproj | sort | uniq -cni ishlating. Qiymatni toping. Xcode'da#Previewni ochib, canvas'da nima bo'lishini (yoki bo'lmasligni) yozing. - ⭐⭐ O'lchang.
bazel run //:xcodeprojni birinchi marta (bo'sh output base) vaBUILD.bazelga bir qator qo'shgandan keyin (qayta) o'lchang (/usr/bin/time -pbilan). Keyinxcodebuild ... buildni ikki marta ketma-ket qiling va ikkinchisini o'lchang. O'z raqamlaringizni bizning jadvalimiz bilan solishtiring — mashinangiz sekinroq/tezroq bo'lishi mumkin.
O'zingizni tekshiring {#checklist}
- [ ]
rules_xcodeprojnega kerakligini va Bazel'ni iOS'da qabul qilishdagi #1 to'siq IDE/DX ekanini tushuntira olaman (Asana misoli). - [ ]
xcodeprojqoidasidagiproject_name,top_level_targets,top_level_target(... target_environments=...)nima qilishini bilaman. - [ ] Ko'p paketli loyihada
@rules_xcodeproj//xcodeproj:generatedvisibility nega kerakligini ayta olaman. - [ ] "Build with Bazel" (BwB) modelini —
BazelDependenciestarget va "Generate Bazel Dependencies" script phase'ni — tushuntira olaman. - [ ] 4.1.0 da
build_modeatributi yo'q va BwB — yagona rejim ekanini bilaman. - [ ] SwiftUI Preview 4.1.0 da nega ishlamasligini (
ENABLE_DEBUG_DYLIB = NO, #3201) va yechimlarni bilaman. - [ ] Archive qo'llab-quvvatlanmasligini va
.ipanibazel buildbilan qurishni bilaman. - [ ]
bazel run //:xcodeproj -- cleanoddiybazel cleandan nega farq qilishini tushunaman. - [ ] VS Code/Cursor'ni
sourcekit-bazel-bsporqali Bazel'ga ulash mumkinligini va uning cheklovlarini bilaman.
Xulosa {#xulosa}
- IDE integratsiyasi — Bazel'ni iOS'da qabul qilishdagi asosiy to'siq.
rules_xcodeprojaynan shu muammoni hal qiladi: Bazel target'laridan haqiqiy.xcodeprojgeneratsiya qiladi (bazel run //:xcodeproj). - Model — "Build with Bazel" (BwB): Xcode muharrir, Bazel esa haqiqiy build'ni bajaradi (
BazelDependenciestarget orqali). 4.1.0 da bu — yagona rejim (build_modeatributi yo'q). - Biz tekshirdik (Xcode 27.1 + rules_xcodeproj 4.1.0): loyiha generatsiya qilindi (181 s birinchi marta, keyin ~9 s),
xcodebuildbilan BUILD SUCCEEDED, incremental build 1.99 s. README jadvali eskirgan bo'lsa ham, 4.1.0 bu yerda ishladi. - Ishlaydi: indexing, debugging (LLDB), test navigator, inline xatolar. Ishlamaydi/cheklangan: SwiftUI Preview (
ENABLE_DEBUG_DYLIB = NO, #3201 ochiq), Archive (.ipani Bazel quradi), coverage cache'ni buzadi. - Katta repo uchun:
focused_targets/unfocused_targetsbilan Xcode'ni yengillashtiring; CI cache'ni--generator_output_groups=all_targetsbilan warm qiling. - Alternativa: VS Code/Cursor/Claude —
sourcekit-lsp+sourcekit-bazel-bsp(Spotify) orqali; indexing hamma joyda, build/debug Cursor/VSCode'da; lekin WMO'siz va sekinroq birinchi indexing bilan. - Keyingi dars: Bazel 10: Cache — action key, disk cache, remote cache, Build without the Bytes va cache-miss detektivligi — Xcode ichidagi build ham, CI ham bir xil cache'ni bo'lishishi sirini ochamiz.
Manbalar {#manbalar}
- rules_xcodeproj — GitHub (Mobile Native Foundation) — README, xususiyatlar ro'yxati, foydalanuvchi loyihalar.
- rules_xcodeproj — Usage docs — config oilasi, command-line API, output base.
- rules_xcodeproj — Bazel rules reference —
xcodeproj,top_level_target,xcode_provisioning_profileatributlari. - rules_xcodeproj — FAQ — Archive, visibility, stale fayllar, signing.
- rules_xcodeproj — Design goals — BwB/BwX falsafasi, SwiftUI Preview non-goal.
- rules_xcodeproj — CHANGELOG — 4.0.0/4.1.0 o'zgarishlar, legacy generator olib tashlanishi.
- Issue #3201 — Xcode SwiftUI Preview Support — Preview bo'shlig'i (ochiq).
- Asana — Scaling a mature iOS codebase with Tuist — nega Bazel'dan voz kechildi (breakpoint/DX), 2023-02-21.
- spotify/sourcekit-bazel-bsp — VS Code/Cursor/Claude + sourcekit-lsp + Bazel (Apache-2.0).
- sourcekit-lsp — issue #2328 — "Loading the standard library failed" (BSP bilan).
- rules_ios — discussion #952 — Square'ning rules_ios'dan chiqishi (2025-11-07).
- BuildBuddy — How to migrate an iOS app to Bazel — Brentley Jones, 2024; Archive/cache warming caveat'lari.