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

รายงานปัญหา ดูแหล่งที่มา

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  1. สร้างไฟล์ WORKSPACE

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

  3. สร้างไฟล์ BUILD:

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

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

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

  4. (ไม่บังคับ) อธิบายบิลด์อย่างละเอียด

  5. เรียกใช้บิลด์

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

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

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

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

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

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

เมื่อกำหนดพื้นที่ทำงานและการอ้างอิงภายนอกแล้ว คุณต้องสร้างไฟล์ 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 รองรับการเรียกใช้การทดสอบหน่วยตามไลบรารีใน iOS และ macOS รวมถึงการทดสอบตามแอปพลิเคชันบน macOS สำหรับการทดสอบตามแอปพลิเคชันบนการทดสอบ iOS หรือ UI บนแพลตฟอร์มทั้งสอง Bazel จะสร้างเอาต์พุตทดสอบ แต่การทดสอบต้องทำงานภายใน Xcode ผ่านโปรเจ็กต์ที่สร้างด้วย rules_xcodeproj เพิ่มเป้าหมายทดสอบดังนี้

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

  • ios_unit_test เพื่อทำการทดสอบ 1 หน่วยตามไลบรารีใน iOS สำหรับการทดสอบที่ต้องใช้เครื่องจำลองของ iOS นั้น Bazel จะสร้างเอาต์พุตทดสอบแต่ไม่เรียกใช้การทดสอบ คุณต้องสร้างโปรเจ็กต์ Xcode ด้วย rules_xcodeproj และทำการทดสอบจากภายใน Xcode

  • ios_ui_test เพื่อสร้างเอาต์พุตที่จำเป็นต่อการเรียกใช้การทดสอบอินเทอร์เฟซผู้ใช้ในเครื่องจำลอง iOS โดยใช้ Xcode คุณต้องสร้างโปรเจ็กต์ Xcode ด้วย rules_xcodeproj และทำการทดสอบจากภายใน Xcode Bazel เรียกใช้การทดสอบ UI แบบดั้งเดิมไม่ได้

และระบุค่าสำหรับแอตทริบิวต์ 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 ไฟล์ WORKSPACE และ BUILD จะกลายเป็นแหล่งข้อมูลที่แท้จริงเกี่ยวกับบิลด์ หากต้องการให้ Xcode ทราบถึงเรื่องนี้ คุณต้องสร้างโปรเจ็กต์ Xcode ที่เข้ากันได้กับ Bazel โดยใช้ rules_xcodeproj

การแก้ปัญหา

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

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

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

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