หน้านี้ครอบคลุมหลักเกณฑ์ด้านสไตล์พื้นฐานสำหรับ Starlark รวมถึงข้อมูลเกี่ยวกับมาโครและกฎ
Starlark คือภาษาที่กำหนดวิธีการสร้างซอฟต์แวร์ ดังนั้นจึงเป็นทั้งภาษาโปรแกรมและการกำหนดค่า
คุณจะใช้ Starlark เพื่อเขียนไฟล์ มาโคร และสร้างกฎของ BUILD
มาโครและกฎเป็นภาษาเมตา ซึ่งกำหนดวิธีเขียนไฟล์ BUILD
BUILD
ไฟล์มีวัตถุประสงค์เพื่อให้เรียบง่ายและซ้ำซ้อน
จะมีการอ่านซอฟต์แวร์ทั้งหมดบ่อยกว่าการเขียน โดยเฉพาะอย่างยิ่งสำหรับ Starlark ขณะที่วิศวกรอ่านไฟล์ BUILD
เพื่อทำความเข้าใจทรัพยากร Dependency ของเป้าหมายและรายละเอียดของบิลด์ การอ่านนี้มักจะเกิดขึ้นโดยไม่ได้ตั้งใจ รีบร้อน หรือทําควบคู่ไปกับงานอื่นๆ ดังนั้น ความเรียบง่ายและความสามารถในการอ่านจึงเป็นสิ่งสำคัญอย่างยิ่งเพื่อให้ผู้ใช้สามารถแยกวิเคราะห์และทำความเข้าใจไฟล์ BUILD
ได้อย่างรวดเร็ว
เมื่อผู้ใช้เปิดไฟล์ BUILD
ผู้ใช้ต้องการทราบรายการเป้าหมายในไฟล์อย่างรวดเร็ว หรือตรวจสอบรายการแหล่งที่มาของไลบรารี C++ นั้น หรือนําข้อกําหนดในการพึ่งพาออกจากไบนารี Java นั้น ทุกครั้งที่คุณเพิ่มชั้นการแยกแยะ ผู้ใช้จะทํางานเหล่านี้ได้ยากขึ้น
นอกจากนี้ ไฟล์ BUILD
รายการยังได้รับการวิเคราะห์และอัปเดตโดยเครื่องมือต่างๆ อีกด้วย เครื่องมืออาจแก้ไขไฟล์ BUILD
ไม่ได้หากเครื่องมือดังกล่าวใช้นามธรรม การใช้BUILD
ไฟล์ที่เรียบง่ายจะช่วยให้คุณได้รับเครื่องมือที่ดีขึ้น เมื่อฐานของโค้ดเติบโตขึ้น ก็เกิดการเปลี่ยนแปลงในไฟล์ BUILD
หลายไฟล์อัปเดตไลบรารีหรือล้างข้อมูลบ่อยมากขึ้นเรื่อยๆ
คำแนะนำทั่วไป
- ใช้ Buildifier เป็นตัวจัดรูปแบบและโปรแกรมตรวจไวยากรณ์
- ปฏิบัติตามหลักเกณฑ์การทดสอบ
รูปแบบ
รูปแบบ Python
หากไม่แน่ใจ ให้ทำตามคู่มือสไตล์ PEP 8 หากเป็นไปได้ โดยเฉพาะอย่างยิ่ง ให้ใช้การเยื้อง 4 ช่องแทน 2 ช่องเพื่อให้เป็นไปตามรูปแบบของ Python
เนื่องจากStarlark ไม่ใช่ Python จึงใช้รูปแบบบางอย่างของ Python ไม่ได้ ตัวอย่างเช่น PEP 8 แนะนำให้ใช้ is
ในการเปรียบเทียบกับรายการเดี่ยว ซึ่งไม่ใช่โอเปอเรเตอร์ใน Starlark
การสร้างเอกสาร
อธิบายไฟล์และฟังก์ชันโดยใช้ docstring
ใช้ docstring ที่ด้านบนของไฟล์ .bzl
แต่ละไฟล์ และใช้ docstring สำหรับฟังก์ชันสาธารณะแต่ละรายการ
กฎและลักษณะของเอกสาร
กฎและมุมมอง รวมถึงแอตทริบิวต์ของกฎและมุมมองนั้นๆ รวมถึงผู้ให้บริการและช่องของผู้ให้บริการ ควรบันทึกโดยใช้อาร์กิวเมนต์ doc
รูปแบบการตั้งชื่อ
- ตัวแปรและชื่อฟังก์ชันใช้ตัวพิมพ์เล็กโดยคั่นคำด้วยขีดล่าง (
[a-z][a-z0-9_]*
) เช่นcc_library
- ค่าส่วนตัวระดับบนสุดจะเริ่มต้นด้วยขีดล่าง 1 ขีด Bazel บังคับว่าไม่สามารถใช้ค่าส่วนตัวจากไฟล์อื่นๆ ตัวแปรภายในไม่ควรใช้ขีดล่างเป็นคำนำหน้า
ความยาวของบรรทัด
ไม่มีการจำกัดความยาวของบรรทัดแบบเข้มงวดในไฟล์ BUILD
เนื่องจากป้ายกำกับมีความยาวได้
หากเป็นไปได้ ให้พยายามใช้อักขระไม่เกิน 79 ตัวต่อบรรทัด (ตามคำแนะนำเกี่ยวกับรูปแบบของ Python 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()
ในโค้ดเวอร์ชันที่ใช้งานจริง เพราะฟังก์ชันนี้มีไว้เพื่อแก้ไขข้อบกพร่องเท่านั้น และจะสแปมผู้ใช้โดยตรงและโดยอ้อมทั้งหมดของไฟล์ .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
เพื่อดึงข้อมูลชื่อของเป้าหมายที่แมโครกำหนดเท่านั้น และไม่ใช้กับอย่างอื่น เช่น อย่าใช้ชื่อเพื่อดึงข้อมูลไฟล์ที่ต้องพึ่งพาหรือไฟล์อินพุตที่ไม่ได้สร้างโดยมาโครเอง - เป้าหมายทั้งหมดที่สร้างในมาโครควรเชื่อมโยงกับเป้าหมายหลักด้วยวิธีใดวิธีหนึ่ง
- ตามธรรมเนียมแล้ว
name
ควรเป็นอาร์กิวเมนต์แรกเมื่อกำหนดมาโคร - ตั้งชื่อพารามิเตอร์ในมาโครให้สอดคล้องกัน หากส่งพารามิเตอร์เป็นค่าแอตทริบิวต์ไปยังเป้าหมายหลัก ให้ใช้ชื่อเดิม หากพารามิเตอร์มาโครมีวัตถุประสงค์เดียวกับแอตทริบิวต์กฎทั่วไป เช่น
deps
ให้ตั้งชื่อตามแอตทริบิวต์ (ดูด้านล่าง) - เมื่อเรียกใช้มาโคร ให้ใช้เฉพาะอาร์กิวเมนต์คีย์เวิร์ด วิธีการนี้สอดคล้องกับกฎต่างๆ และช่วยให้อ่านได้ง่ายขึ้นมาก
วิศวกรมักจะเขียนมาโครเมื่อ Starlark API ของกฎที่เกี่ยวข้องไม่เพียงพอสำหรับ Use Case ที่เฉพาะเจาะจง ไม่ว่ากฎจะกำหนดภายใน Bazel ในโค้ดเนทีฟหรือใน Starlark ก็ตาม หากคุณพบปัญหานี้ โปรดสอบถามผู้เขียนกฎว่าสามารถขยาย API เพื่อให้บรรลุเป้าหมายของคุณได้หรือไม่
โดยทั่วไปแล้ว ยิ่งมาโครคล้ายกับกฎมากเท่าใด ก็ยิ่งดีเท่านั้น
โปรดดูมาโครด้วย
กฎ
- กฎ แง่มุม และแอตทริบิวต์ของกฎและแง่มุมควรใช้ชื่อแบบพิมพ์เล็ก ("snake case")
- ชื่อกฎคือคำนามที่อธิบายถึงประเภทหลักของอาร์ติแฟกต์ที่กฎสร้างขึ้นจากมุมมองของข้อกำหนด (หรือผู้ใช้สำหรับกฎระดับล่าง) ซึ่งไม่จำเป็นต้องเป็นคำต่อท้ายไฟล์ เช่น กฎที่สร้างอาร์ติแฟกต์ 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
: ไลบรารีรันไทม์ที่ไม่จําเป็นสําหรับการคอมไพล์
- สำหรับแอตทริบิวต์ที่มีลักษณะการทำงานที่ไม่ชัดเจน (เช่น เทมเพลตสตริงที่มีการแทนที่พิเศษ หรือเครื่องมือที่เรียกใช้โดยมีข้อกำหนดเฉพาะ) ให้ระบุเอกสารประกอบโดยใช้อาร์กิวเมนต์คีย์เวิร์ด
doc
ในการประกาศแอตทริบิวต์ (attr.label_list()
หรือคล้ายกัน) - ฟังก์ชันการใช้งานกฎควรเป็นฟังก์ชันส่วนตัวเกือบทุกครั้ง (ตั้งชื่อโดยนำหน้าด้วยเครื่องหมายขีดล่าง) รูปแบบที่พบบ่อยคือการตั้งชื่อฟังก์ชันการใช้งานของ
myrule
เป็น_myrule_impl
- ส่งข้อมูลระหว่างกฎของคุณโดยใช้อินเทอร์เฟซผู้ให้บริการที่กำหนดมาอย่างดี ประกาศและจัดทำเอกสารเกี่ยวกับช่องผู้ให้บริการ
- ออกแบบกฎโดยคำนึงถึงความยืดหยุ่น โปรดทราบว่ากฎอื่นๆ อาจต้องการโต้ตอบกับกฎของคุณ เข้าถึงผู้ให้บริการ และนําการดำเนินการที่คุณสร้างขึ้นมาใช้ซ้ำ
- ปฏิบัติตามหลักเกณฑ์ด้านประสิทธิภาพในกฎ