การย้ายข้อมูลจาก Xcode ไปยัง Bazel

หน้านี้อธิบายวิธีสร้างหรือทดสอบโปรเจ็กต์ Xcode ด้วย Bazel โดยจะอธิบายความแตกต่างระหว่าง Xcode กับ Bazel และแสดงขั้นตอนในการแปลงโปรเจ็กต์ Xcode เป็นโปรเจ็กต์ Bazel นอกจากนี้ยังแสดงวิธีแก้ปัญหาเพื่อแก้ไขข้อผิดพลาดที่พบบ่อย

ความแตกต่างระหว่าง Xcode กับ Bazel

  • Bazel กำหนดให้คุณต้องระบุเป้าหมายการสร้างแต่ละรายการและทรัพยากร Dependency อย่างชัดเจน รวมถึงการตั้งค่าการสร้างที่เกี่ยวข้องผ่านกฎการสร้าง

  • Bazel กำหนดให้ไฟล์ทั้งหมดที่โปรเจ็กต์ขึ้นต่อกันต้องอยู่ในไดเรกทอรีพื้นที่ทำงานหรือระบุเป็นทรัพยากร Dependency ในไฟล์ MODULE.bazel

  • เมื่อสร้างโปรเจ็กต์ Xcode ด้วย Bazel ไฟล์ BUILD จะกลายเป็นแหล่งข้อมูลที่เชื่อถือได้ หากคุณทำงานในโปรเจ็กต์ใน Xcode คุณต้องสร้าง โปรเจ็กต์ Xcode เวอร์ชันใหม่ที่ตรงกับไฟล์ BUILD โดยใช้ rules_xcodeproj ทุกครั้งที่อัปเดตไฟล์ BUILD การเปลี่ยนแปลงบางอย่างในไฟล์ BUILD เช่น การเพิ่มทรัพยากร Dependency ลงในเป้าหมาย ไม่จำเป็นต้องสร้างโปรเจ็กต์ใหม่ ซึ่งจะช่วยเร่งการพัฒนา หากคุณไม่ได้ใช้ Xcode คำสั่ง bazel build และ bazel test จะมีฟังก์ชันการสร้างและการทดสอบโดยมีข้อจำกัดบางอย่างที่อธิบายไว้ในส่วนท้ายของคู่มือนี้

ก่อนเริ่มต้น

ก่อนเริ่มต้น ให้ทำดังนี้

  1. ติดตั้ง Bazel หากยังไม่ได้ติดตั้ง

  2. หากคุณไม่คุ้นเคยกับ Bazel และแนวคิดของ Bazel ให้ทำบทแนะนำแอป iOS ให้เสร็จสมบูรณ์) คุณควรทำความเข้าใจพื้นที่ทำงานของ Bazel ซึ่งรวมถึงไฟล์ MODULE.bazel และ BUILD รวมถึงแนวคิดของเป้าหมาย กฎการสร้าง และแพ็กเกจ Bazel

  3. วิเคราะห์และทำความเข้าใจทรัพยากร Dependency ของโปรเจ็กต์

วิเคราะห์ทรัพยากร Dependency ของโปรเจ็กต์

Bazel กำหนดให้คุณต้องประกาศทรัพยากร Dependency ทั้งหมดสำหรับทุกเป้าหมายในไฟล์ BUILD อย่างชัดเจน ซึ่งแตกต่างจาก Xcode

ดูข้อมูลเพิ่มเติมเกี่ยวกับทรัพยากร Dependency ภายนอกได้ที่หัวข้อ การทำงานกับทรัพยากร Dependency ภายนอก

สร้างหรือทดสอบโปรเจ็กต์ Xcode ด้วย Bazel

หากต้องการสร้างหรือทดสอบโปรเจ็กต์ Xcode ด้วย Bazel ให้ทำดังนี้

  1. สร้างไฟล์ MODULE.bazel

  2. (ทดลองใช้) ผสานรวมทรัพยากร Dependency ของ SwiftPM

  3. สร้างไฟล์ BUILD โดยทำดังนี้

    ก. เพิ่มเป้าหมายของแอปพลิเคชัน

    ข. (ไม่บังคับ) เพิ่มเป้าหมายการทดสอบ

    ค. เพิ่มเป้าหมายของไลบรารี

  4. (ไม่บังคับ) แบ่งบิลด์ออกเป็นส่วนๆ

  5. เรียกใช้การสร้าง

  6. สร้างโปรเจ็กต์ Xcode ด้วย rules_xcodeproj

ขั้นตอนที่ 1: สร้างไฟล์ MODULE.bazel

สร้างไฟล์ MODULE.bazel ในไดเรกทอรีใหม่ ไดเรกทอรีนี้จะกลายเป็นรูทของพื้นที่ทำงาน Bazel หากโปรเจ็กต์ไม่มีทรัพยากร Dependency ภายนอก ไฟล์นี้จะว่างเปล่าได้ หากโปรเจ็กต์ขึ้นต่อกันกับไฟล์หรือแพ็กเกจที่ไม่ได้อยู่ในไดเรกทอรีใดไดเรกทอรีหนึ่งของโปรเจ็กต์ ให้ระบุทรัพยากร Dependency ภายนอกเหล่านี้ในไฟล์ MODULE.bazel

ขั้นตอนที่ 2: (ทดลองใช้) ผสานรวมทรัพยากร Dependency ของ SwiftPM

หากต้องการผสานรวมทรัพยากร Dependency ของ SwiftPM เข้ากับพื้นที่ทำงาน Bazel ด้วย swift_bazel คุณต้อง แปลงทรัพยากร Dependency เหล่านั้นเป็นแพ็กเกจ Bazel ตามที่อธิบายไว้ในบทแนะนำ ต่อไปนี้

ขั้นตอนที่ 3: สร้างไฟล์ BUILD

เมื่อกำหนดพื้นที่ทำงานและทรัพยากร Dependency ภายนอกแล้ว คุณต้องสร้างไฟล์ BUILD ที่จะบอก Bazel ว่าโปรเจ็กต์มีโครงสร้างอย่างไร สร้างไฟล์ BUILD ที่รูทของพื้นที่ทำงาน Bazel และกำหนดค่าให้สร้างบิลด์เริ่มต้นของโปรเจ็กต์ดังนี้

เคล็ดลับ: ดูข้อมูลเพิ่มเติมเกี่ยวกับแพ็กเกจและแนวคิดอื่นๆ ของ Bazel ได้ที่หัวข้อ พื้นที่ทำงาน แพ็กเกจ และเป้าหมาย

ขั้นตอนที่ 3ก: เพิ่มเป้าหมายของแอปพลิเคชัน

เพิ่มเป้าหมายกฎ macos_application หรือ ios_application เป้าหมายนี้จะสร้างชุดแอปพลิเคชัน macOS หรือ iOS ตามลำดับ ในเป้าหมาย ให้ระบุข้อมูลต่อไปนี้อย่างน้อย

  • bundle_id - รหัสชุด (เส้นทาง DNS แบบย้อนกลับตามด้วยชื่อแอป) ของ ไบนารี

  • provisioning_profile - โปรไฟล์การจัดสรรจากบัญชีนักพัฒนาแอป Apple (หากสร้างสำหรับอุปกรณ์ iOS)

  • families (iOS เท่านั้น) - เลือกว่าจะสร้างแอปพลิเคชันสำหรับ iPhone, iPad หรือทั้ง 2 อย่าง

  • infoplists - รายการไฟล์ .plist ที่จะผสานรวมเข้ากับไฟล์ Info.plist สุดท้าย

  • minimum_os_version - macOS หรือ iOS เวอร์ชันต่ำสุดที่ แอปพลิเคชันรองรับ ซึ่งจะช่วยให้ Bazel สร้างแอปพลิเคชันด้วยระดับ API ที่ถูกต้อง

ขั้นตอนที่ 3ข: (ไม่บังคับ) เพิ่มเป้าหมายการทดสอบ

กฎการสร้าง Apple ของ Bazel รองรับการเรียกใช้ การทดสอบหน่วยและการทดสอบ UI ในแพลตฟอร์ม Apple ทั้งหมด เพิ่มเป้าหมายการทดสอบดังนี้

  • macos_unit_test เพื่อเรียกใช้การทดสอบหน่วยที่อิงตามไลบรารีและแอปพลิเคชันใน macOS

  • ios_unit_test เพื่อสร้างและเรียกใช้การทำ Unit Test ที่อิงตามไลบรารีใน iOS

  • ios_ui_test เพื่อสร้างและเรียกใช้การทดสอบอินเทอร์เฟซผู้ใช้ในโปรแกรมจำลอง iOS

  • กฎการทดสอบที่คล้ายกันมีไว้สำหรับ tvOS, watchOS และ visionOS

ระบุค่าสำหรับแอตทริบิวต์ minimum_os_version อย่างน้อย แม้ว่าแอตทริบิวต์การจัดแพ็กเกจอื่นๆ เช่น bundle_identifier และ infoplists จะใช้ค่าเริ่มต้นที่ใช้กันโดยทั่วไป แต่โปรดตรวจสอบว่าค่าเริ่มต้นเหล่านั้นเข้ากันได้กับโปรเจ็กต์และปรับค่าตามความจำเป็น สำหรับการทดสอบที่ต้องใช้โปรแกรมจำลอง iOS ให้ระบุชื่อเป้าหมาย ios_application เป็นค่าของแอตทริบิวต์ test_host ด้วย

ขั้นตอนที่ 3ค: เพิ่มเป้าหมายของไลบรารี

เพิ่มเป้าหมาย objc_library สำหรับไลบรารี Objective-C แต่ละรายการ และเป้าหมาย swift_library สำหรับไลบรารี Swift แต่ละรายการที่แอปพลิเคชันและ/หรือการทดสอบขึ้นต่อกัน

เพิ่มเป้าหมายของไลบรารีดังนี้

  • เพิ่มเป้าหมายของไลบรารีแอปพลิเคชันเป็นทรัพยากร Dependency ให้กับเป้าหมายของแอปพลิเคชัน

  • เพิ่มเป้าหมายของไลบรารีการทดสอบเป็นทรัพยากร Dependency ให้กับเป้าหมายการทดสอบ

  • แสดงรายการแหล่งที่มาของการติดตั้งใช้งานในแอตทริบิวต์ srcs

  • แสดงรายการส่วนหัวในแอตทริบิวต์ hdrs

คุณสามารถเรียกดูตัวอย่างที่มีอยู่สำหรับแอปพลิเคชันประเภทต่างๆ ได้โดยตรงใน ไดเรกทอรีตัวอย่าง rules_apple เช่น

ดูข้อมูลเพิ่มเติมเกี่ยวกับกฎการสร้างได้ที่หัวข้อ กฎของ Apple สำหรับ Bazel

ตอนนี้เป็นเวลาที่เหมาะสมที่จะทดสอบบิลด์ โดยทำดังนี้

bazel build //:<application_target>

ขั้นตอนที่ 4: (ไม่บังคับ) แบ่งบิลด์ออกเป็นส่วนๆ

หากโปรเจ็กต์มีขนาดใหญ่หรือมีขนาดใหญ่ขึ้น ให้พิจารณาแบ่งโปรเจ็กต์ออกเป็นแพ็กเกจ Bazel หลายรายการ การแบ่งออกเป็นส่วนๆ นี้จะช่วยให้ได้สิ่งต่อไปนี้

  • การสร้างแบบเพิ่มขึ้น

  • การทำงานแบบขนานของงานการสร้าง

  • การดูแลรักษาที่ดีขึ้นสำหรับผู้ใช้ในอนาคต

  • ควบคุมการแสดงผลซอร์สโค้ดในเป้าหมายและแพ็กเกจได้ดีขึ้น ซึ่งจะป้องกันปัญหาต่างๆ เช่น ไลบรารีที่มีรายละเอียดการติดตั้งใช้งานรั่วไหลไปยัง API สาธารณะ

เคล็ดลับในการแบ่งโปรเจ็กต์ออกเป็นส่วนๆ

  • ใส่ไลบรารีแต่ละรายการไว้ในแพ็กเกจ Bazel ของตัวเอง เริ่มจากไลบรารีที่ต้องใช้ทรัพยากร Dependency น้อยที่สุด แล้วค่อยๆ ไล่ขึ้นไปตามโครงสร้างทรัพยากร Dependency

  • เมื่อเพิ่มไฟล์ BUILD และระบุเป้าหมาย ให้เพิ่มเป้าหมายใหม่เหล่านี้ลงในแอตทริบิวต์ deps ของเป้าหมายที่ขึ้นต่อกัน

  • ฟังก์ชัน glob() จะไม่ข้ามขอบเขตของแพ็กเกจ ดังนั้นเมื่อจำนวนแพ็กเกจเพิ่มขึ้น ไฟล์ที่ตรงกับ glob() จะลดลง

  • เมื่อเพิ่มไฟล์ BUILD ลงในไดเรกทอรี main ให้เพิ่มไฟล์ BUILD ลงในไดเรกทอรี test ที่เกี่ยวข้องด้วย

  • บังคับใช้ขีดจำกัดการแสดงผลที่เหมาะสมในแพ็กเกจ

  • สร้างโปรเจ็กต์หลังจากการเปลี่ยนแปลงที่สำคัญแต่ละครั้งในไฟล์ BUILD และแก้ไขข้อผิดพลาดในการสร้างเมื่อพบ

ขั้นตอนที่ 5: เรียกใช้การสร้าง

เรียกใช้บิลด์ที่ย้ายข้อมูลเสร็จสมบูรณ์แล้วเพื่อให้แน่ใจว่าบิลด์เสร็จสมบูรณ์โดยไม่มีข้อผิดพลาดหรือประกาศเตือน เรียกใช้เป้าหมายของแอปพลิเคชันและการทดสอบแต่ละรายการแยกกันเพื่อให้ค้นหาแหล่งที่มาของข้อผิดพลาดที่เกิดขึ้นได้ง่ายขึ้น

เช่น

bazel build //:my-target

ขั้นตอนที่ 6: สร้างโปรเจ็กต์ Xcode ด้วย rules_xcodeproj

เมื่อสร้างด้วย Bazel ไฟล์ MODULE.bazel และ BUILD จะกลายเป็นแหล่งข้อมูลที่เชื่อถือได้เกี่ยวกับการสร้าง หากต้องการให้ Xcode ทราบถึงเรื่องนี้ คุณต้องสร้างโปรเจ็กต์ Xcode ที่เข้ากันได้กับ Bazel โดยใช้ rules_xcodeproj

การแก้ปัญหา

ข้อผิดพลาดของ Bazel อาจเกิดขึ้นเมื่อ Bazel ไม่ซิงค์กับ Xcode เวอร์ชันที่เลือก เช่น เมื่อคุณใช้การอัปเดต ต่อไปนี้คือสิ่งที่ควรลองทำหากคุณพบข้อผิดพลาดเกี่ยวกับ Xcode เช่น "ต้องระบุเวอร์ชัน Xcode เพื่อใช้ Apple CROSSTOOL"

  • เรียกใช้ Xcode ด้วยตนเองและยอมรับข้อกำหนดและเงื่อนไข

  • ใช้ Xcode select เพื่อระบุเวอร์ชันที่ถูกต้อง ยอมรับใบอนุญาต และล้างสถานะของ Bazel

  sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
  sudo xcodebuild -license
  bazel sync --configure
  • หากวิธีนี้ไม่ได้ผล คุณอาจลองเรียกใช้ bazel clean --expunge