หน้านี้ครอบคลุมหลักเกณฑ์รูปแบบพื้นฐานสำหรับ Starlark รวมถึงข้อมูลเกี่ยวกับมาโครและกฎด้วย
Starlark เป็น ภาษาที่กำหนดวิธีสร้างซอฟต์แวร์ จึงเป็นทั้ง ภาษาโปรแกรมและภาษาการกำหนดค่า
คุณจะใช้ Starlark เพื่อเขียนไฟล์ BUILD มาโคร และกฎการสร้าง มาโครและกฎเป็นภาษาเมตาโดยพื้นฐาน ซึ่งจะกำหนดวิธีเขียนไฟล์ BUILD
เราออกแบบไฟล์ BUILD ให้เรียบง่ายและทำซ้ำได้
ผู้คนมักจะอ่านซอฟต์แวร์มากกว่าเขียน โดยเฉพาะอย่างยิ่งกับ Starlark เนื่องจากวิศวกรจะอ่านไฟล์ BUILD เพื่อทำความเข้าใจทรัพยากร Dependency ของเป้าหมายและรายละเอียดของการสร้าง การอ่านนี้มักจะเกิดขึ้นอย่างรวดเร็ว รีบร้อน หรือทำควบคู่ไปกับการทำงานอื่นๆ ดังนั้น ความเรียบง่ายและความสามารถในการอ่านจึงมีความสำคัญมากเพื่อให้ผู้ใช้แยกวิเคราะห์และทำความเข้าใจไฟล์ BUILD ได้อย่างรวดเร็ว
เมื่อผู้ใช้เปิดไฟล์ BUILD สิ่งที่ต้องการทราบอย่างรวดเร็วคือรายการเป้าหมายในไฟล์ หรือตรวจสอบรายการแหล่งที่มาของไลบรารี C++ นั้น หรือนำทรัพยากร Dependency ออกจากไบนารี Java นั้น ทุกครั้งที่คุณเพิ่มเลเยอร์การแยกย่อย คุณจะทำให้ผู้ใช้ทำงานเหล่านี้ได้ยากขึ้น
นอกจากนี้ เครื่องมือต่างๆ มากมายยังวิเคราะห์และอัปเดตไฟล์ BUILD ด้วย เครื่องมืออาจแก้ไขไฟล์ BUILD ไม่ได้หากใช้การแยกย่อย การทำให้ไฟล์ BUILD เรียบง่ายจะช่วยให้คุณได้รับเครื่องมือที่ดีขึ้น เมื่อฐานของโค้ดมีขนาดใหญ่ขึ้น การเปลี่ยนแปลงไฟล์ BUILD หลายไฟล์เพื่ออัปเดตไลบรารีหรือล้างข้อมูลก็จะเกิดขึ้นบ่อยขึ้น
คำแนะนำทั่วไป
- ใช้ Buildifier เป็นตัวจัดรูปแบบและตัวตรวจสอบโค้ด
- ปฏิบัติตามหลักเกณฑ์การทดสอบ
รูปแบบ
รูปแบบ Python
หากไม่แน่ใจ ให้ปฏิบัติตาม คู่มือรูปแบบ PEP 8 หากเป็นไปได้ โดยเฉพาะอย่างยิ่ง ให้ใช้ 4 ช่องว่างแทน 2 ช่องว่างสำหรับการเยื้องเพื่อให้เป็นไปตามข้อกำหนดของ Python
เนื่องจาก
Starlark ไม่ใช่ Python,
จึงไม่มีผลกับรูปแบบ Python บางอย่าง ตัวอย่างเช่น PEP 8 แนะนำให้เปรียบเทียบกับ Singleton โดยใช้ is ซึ่งไม่ใช่โอเปอเรเตอร์ใน Starlark
Docstring
จัดทำเอกสารไฟล์และฟังก์ชันโดยใช้ Docstring
ใช้ Docstring ที่ด้านบนของไฟล์ .bzl แต่ละไฟล์ และ Docstring สำหรับฟังก์ชันสาธารณะแต่ละฟังก์ชัน
จัดทำเอกสารกฎและแง่มุมต่างๆ
กฎและแง่มุมต่างๆ รวมถึงแอตทริบิวต์ของกฎและแง่มุม ตลอดจนผู้ให้บริการและฟิลด์ของผู้ให้บริการ ควรจัดทำเอกสารโดยใช้อาร์กิวเมนต์ doc
รูปแบบการตั้งชื่อ
- ตัวแปรและชื่อฟังก์ชันใช้ตัวอักษรพิมพ์เล็กโดยคั่นคำด้วยขีดล่าง (
[a-z][a-z0-9_]*) เช่นcc_library - ค่าส่วนตัวระดับบนสุดขึ้นต้นด้วยขีดล่าง 1 ตัว Bazel กำหนดให้ค่าส่วนตัวใช้จากไฟล์อื่นไม่ได้ ตัวแปรภายในไม่ควรใช้คำนำหน้าขีดล่าง
ความยาวบรรทัด
เช่นเดียวกับไฟล์ BUILD ไม่มีการจำกัดความยาวบรรทัดที่เข้มงวดเนื่องจากป้ายกำกับอาจยาวได้
หากเป็นไปได้ ให้พยายามใช้อักขระไม่เกิน 79 ตัวต่อบรรทัด (ตามคู่มือรูปแบบของ Python's
PEP 8) ไม่ควรบังคับใช้หลักเกณฑ์นี้อย่างเข้มงวด เนื่องจากโปรแกรมแก้ไขควรแสดงคอลัมน์มากกว่า 80 คอลัมน์ การเปลี่ยนแปลงอัตโนมัติมักจะทำให้บรรทัดยาวขึ้น และผู้ใช้ไม่ควรเสียเวลาในการแยกบรรทัดที่อ่านได้อยู่แล้ว
อาร์กิวเมนต์คีย์เวิร์ด
ในอาร์กิวเมนต์คีย์เวิร์ด เราแนะนำให้ใส่ช่องว่างรอบๆ เครื่องหมายเท่ากับ
def fct(name, srcs):
filtered_srcs = my_filter(source = srcs)
native.cc_library(
name = name,
srcs = filtered_srcs,
testonly = True,
)
ค่าบูลีน
เราแนะนำให้ใช้ค่า True และ False (แทน 1 และ 0) สำหรับค่าบูลีน (เช่น เมื่อใช้แอตทริบิวต์บูลีนในกฎ)
ใช้ฟังก์ชัน Print สำหรับการแก้ไขข้อบกพร่องเท่านั้น
อย่าใช้ฟังก์ชัน print() ในโค้ดเวอร์ชันที่ใช้งานจริง โดยฟังก์ชันนี้มีไว้สำหรับการแก้ไขข้อบกพร่องเท่านั้น และจะส่งสแปมไปยังผู้ใช้ไฟล์ .bzl ทั้งทางตรงและทางอ้อมทั้งหมด ข้อยกเว้น
เพียงอย่างเดียวคือคุณอาจส่งโค้ดที่ใช้ print() หากโค้ดดังกล่าวปิดใช้งาน
โดยค่าเริ่มต้นและเปิดใช้งานได้โดยการแก้ไขแหล่งที่มาเท่านั้น เช่น หากการใช้
print() ทั้งหมดได้รับการป้องกันโดย if DEBUG: โดยที่ DEBUG มีการฮาร์ดโค้ดเป็น
False โปรดพิจารณาว่าข้อความเหล่านี้มีประโยชน์มากพอที่จะชดเชยผลกระทบต่อความสามารถในการอ่านได้หรือไม่
มาโคร
มาโครคือฟังก์ชันที่สร้างอินสแตนซ์ของกฎอย่างน้อย 1 ข้อในระหว่างระยะการโหลด โดยทั่วไป ให้ใช้กฎแทนมาโครทุกครั้งที่ทำได้ กราฟการสร้างที่ผู้ใช้เห็นจะไม่เหมือนกับกราฟที่ Bazel ใช้ในระหว่างการสร้าง เนื่องจากระบบจะขยายมาโคร ก่อนที่ Bazel จะวิเคราะห์กราฟการสร้าง
ด้วยเหตุนี้ เมื่อเกิดข้อผิดพลาด ผู้ใช้จะต้องทำความเข้าใจการใช้งานมาโครเพื่อแก้ปัญหาการสร้าง นอกจากนี้ ผลการค้นหา bazel
query อาจตีความได้ยากเนื่องจากเป้าหมายที่แสดงในผลการค้นหา
มาจากการขยายมาโคร สุดท้ายนี้ แง่มุมต่างๆ จะไม่รู้จักมาโคร ดังนั้นเครื่องมือที่ขึ้นอยู่กับแง่มุมต่างๆ (IDE และอื่นๆ) อาจทำงานล้มเหลว
การใช้มาโครอย่างปลอดภัยคือการกำหนดเป้าหมายเพิ่มเติมที่มีไว้เพื่ออ้างอิงโดยตรงที่ Bazel CLI หรือในไฟล์ BUILD ในกรณีนี้ เฉพาะ ผู้ใช้ปลายทาง ของเป้าหมายเหล่านั้นเท่านั้นที่จำเป็นต้องทราบเกี่ยวกับเป้าหมาย และปัญหาการสร้างที่เกิดจากมาโครจะอยู่ใกล้กับการใช้งานเสมอ
สำหรับมาโครที่กำหนดเป้าหมายที่สร้างขึ้น (รายละเอียดการใช้งานมาโครซึ่งไม่ควรมีการอ้างอิงที่ CLI หรือเป้าหมายที่ไม่ได้สร้างอินสแตนซ์โดยมาโครนั้นขึ้นอยู่กับ) ให้ทำตามแนวทางปฏิบัติแนะนำต่อไปนี้
- มาโครควรใช้อาร์กิวเมนต์
nameและกำหนดเป้าหมายด้วยชื่อนั้น เป้าหมายนั้นจะกลายเป็น เป้าหมายหลัก ของมาโคร - เป้าหมายที่สร้างขึ้น ซึ่งก็คือเป้าหมายอื่นๆ ทั้งหมดที่กำหนดโดยมาโคร ควรมีลักษณะดังนี้
- มีคำนำหน้าชื่อเป็น
<name>หรือ_<name>เช่น ใช้name = '%s_bar' % (name) - มีการมองเห็นที่จำกัด (
//visibility:private) และ - มีแท็ก
manualเพื่อหลีกเลี่ยงการขยายในเป้าหมายที่มีไวลด์การ์ด (:all,...,:*ฯลฯ)
- มีคำนำหน้าชื่อเป็น
- ควรใช้
nameเพื่อสร้างชื่อเป้าหมายที่กำหนดโดยมาโครเท่านั้น และไม่ควรใช้เพื่อวัตถุประสงค์อื่น เช่น อย่าใช้ชื่อเพื่อสร้างทรัพยากร Dependency หรือไฟล์อินพุตที่ไม่ได้สร้างโดยมาโครเอง - เป้าหมายทั้งหมดที่สร้างขึ้นในมาโครควรเชื่อมโยงกับเป้าหมายหลักในลักษณะใดลักษณะหนึ่ง
- ตามธรรมเนียมแล้ว
nameควรเป็นอาร์กิวเมนต์แรกเมื่อกำหนดมาโคร - ตั้งชื่อพารามิเตอร์ในมาโครให้สอดคล้องกัน หากมีการส่งพารามิเตอร์เป็นค่าแอตทริบิวต์ไปยังเป้าหมายหลัก ให้ใช้ชื่อเดิม หากพารามิเตอร์มาโครมีวัตถุประสงค์เดียวกับแอตทริบิวต์กฎทั่วไป เช่น
depsให้ตั้งชื่อตามแอตทริบิวต์ (ดูด้านล่าง) - เมื่อเรียกมาโคร ให้ใช้อาร์กิวเมนต์คีย์เวิร์ดเท่านั้น ซึ่งสอดคล้องกับกฎและช่วยให้โค้ดอ่านง่ายขึ้นมาก
วิศวกรมักจะเขียนมาโครเมื่อ Starlark API ของกฎที่เกี่ยวข้องไม่เพียงพอสำหรับกรณีการใช้งานเฉพาะของตน ไม่ว่ากฎจะกำหนดไว้ใน Bazel ในโค้ดแบบเนทีฟ หรือใน Starlark หากคุณพบปัญหานี้ โปรดสอบถามผู้เขียนกฎว่าสามารถขยาย API เพื่อให้บรรลุเป้าหมายของคุณได้หรือไม่
โดยหลักการแล้ว ยิ่งมาโครคล้ายกับกฎมากเท่าใดก็ยิ่งดี
ดูมาโครด้วย
กฎ
- กฎ แง่มุมต่างๆ และแอตทริบิวต์ของกฎและแง่มุมควรใช้ชื่อตัวพิมพ์เล็ก ("snake case")
- ชื่อกฎเป็นคำนามที่อธิบายสิ่งประดิษฐ์หลักที่กฎสร้างขึ้นจากมุมมองของทรัพยากร Dependency (หรือสำหรับกฎใบไม้ ผู้ใช้) ซึ่งไม่จำเป็นต้องเป็นส่วนต่อท้ายของไฟล์ ตัวอย่างเช่น กฎที่สร้างอาร์ติแฟกต์ C++ ที่มีไว้เพื่อใช้เป็นส่วนขยาย Python อาจเรียกว่า
py_extensionกฎทั่วไปสำหรับภาษาส่วนใหญ่ ได้แก่*_library- หน่วยการคอมไพล์หรือ "โมดูล"*_binary- เป้าหมายที่สร้างไฟล์ที่เรียกใช้งานได้หรือหน่วยการติดตั้งใช้งาน*_test- เป้าหมายการทดสอบ ซึ่งอาจรวมถึงการทดสอบหลายรายการ คาดว่าการทดสอบทั้งหมดในเป้าหมาย*_testจะเป็นการทดสอบรูปแบบต่างๆ ในธีมเดียวกัน เช่น การทดสอบไลบรารีเดียว*_import: เป้าหมายที่ห่อหุ้มอาร์ติแฟกต์ที่คอมไพล์ไว้ล่วงหน้า เช่น.jarหรือ.dllที่ใช้ระหว่างการคอมไพล์
- ใช้ชื่อและประเภทแอตทริบิวต์ที่สอดคล้องกัน แอตทริบิวต์ที่ใช้ได้โดยทั่วไป ได้แก่
srcs:label_listซึ่งอนุญาตไฟล์ ได้แก่ ไฟล์ต้นฉบับที่โดยทั่วไปเขียนโดยผู้ใช้deps:label_listซึ่งโดยทั่วไป ไม่อนุญาต ไฟล์ ได้แก่ ทรัพยากร Dependency ในการคอมไพล์data:label_listซึ่งอนุญาตไฟล์ ได้แก่ ไฟล์ข้อมูล เช่น ข้อมูลการทดสอบ เป็นต้นruntime_deps:label_list: ทรัพยากร Dependency รันไทม์ที่ไม่จำเป็นสำหรับการคอมไพล์
- สำหรับแอตทริบิวต์ที่มีลักษณะการทำงานที่ไม่ชัดเจน (เช่น เทมเพลตสตริงที่มีการแทนที่พิเศษ หรือเครื่องมือที่เรียกใช้ตามข้อกำหนดเฉพาะ) ให้จัดทำเอกสารโดยใช้อาร์กิวเมนต์คีย์เวิร์ด
docในการประกาศแอตทริบิวต์ (attr.label_list()หรือคล้ายกัน) - ฟังก์ชันการใช้งานกฎควรเป็นฟังก์ชันส่วนตัว (ตั้งชื่อด้วยขีดล่างนำหน้า) เกือบทั้งหมด รูปแบบทั่วไปคือการตั้งชื่อฟังก์ชันการใช้งานสำหรับ
myruleว่า_myrule_impl - ส่งข้อมูลระหว่างกฎโดยใช้อินเทอร์เฟซ ผู้ให้บริการที่กำหนดไว้อย่างดี ประกาศและจัดทำเอกสารฟิลด์ผู้ให้บริการ
- ออกแบบกฎโดยคำนึงถึงความสามารถในการขยาย โปรดพิจารณาว่ากฎอื่นๆ อาจต้องการโต้ตอบกับกฎของคุณ เข้าถึงผู้ให้บริการของคุณ และใช้ซ้ำการดำเนินการที่คุณสร้างขึ้น
- ปฏิบัติตามหลักเกณฑ์ด้านประสิทธิภาพในกฎ