หน้านี้ครอบคลุมหลักเกณฑ์ด้านรูปแบบพื้นฐานสำหรับ Starlark รวมถึง ข้อมูลเกี่ยวกับมาโครและกฎ
Starlark เป็นภาษาที่กำหนดวิธีสร้างซอฟต์แวร์ จึงเป็นทั้งภาษาโปรแกรมและภาษากำหนดค่า
คุณจะใช้ Starlark เพื่อเขียนไฟล์ BUILD
มาโคร และกฎการสร้าง มาโครและ
กฎเป็นภาษาเมตาโดยพื้นฐาน ซึ่งจะกำหนดวิธีเขียนไฟล์ BUILD
BUILD
ไฟล์มีจุดประสงค์เพื่อให้เรียบง่ายและทำซ้ำได้
โดยปกติแล้วเราจะอ่านซอฟต์แวร์บ่อยกว่าเขียน โดยเฉพาะอย่างยิ่งสำหรับ Starlark เนื่องจากวิศวกรจะอ่านไฟล์ BUILD
เพื่อทำความเข้าใจการขึ้นต่อกันของเป้าหมายและรายละเอียดของการสร้าง การอ่านมักเกิดขึ้นอย่างรวดเร็ว
เร่งรีบ หรือควบคู่ไปกับการทำงานอื่นๆ ดังนั้น ความเรียบง่ายและความสามารถในการอ่านจึงมีความสำคัญอย่างยิ่งเพื่อให้ผู้ใช้สามารถแยกวิเคราะห์และทำความเข้าใจไฟล์ BUILD
ได้อย่างรวดเร็ว
เมื่อผู้ใช้เปิดBUILD
ไฟล์ ผู้ใช้จะต้องการทราบรายการเป้าหมายใน
ไฟล์อย่างรวดเร็ว หรือตรวจสอบรายการแหล่งที่มาของไลบรารี C++ นั้น หรือนำ
การอ้างอิงออกจากไบนารี Java นั้น ทุกครั้งที่คุณเพิ่มเลเยอร์ของนามธรรม คุณจะ
ทำให้ผู้ใช้ทำสิ่งเหล่านี้ได้ยากขึ้น
BUILD
ไฟล์ยังได้รับการวิเคราะห์และอัปเดตโดยเครื่องมือต่างๆ มากมายด้วย เครื่องมืออาจแก้ไขไฟล์ BUILD
ไม่ได้หากใช้การแยกส่วน การทำให้BUILD
ไฟล์เรียบง่ายจะช่วยให้คุณได้รับเครื่องมือที่ดีขึ้น เมื่อโค้ดเบสเติบโตขึ้น การเปลี่ยนแปลงในBUILD
ไฟล์จำนวนมากเพื่ออัปเดตไลบรารีหรือล้างข้อมูลจะเกิดขึ้นบ่อยขึ้นเรื่อยๆ
คำแนะนำทั่วไป
- ใช้ Buildifier เป็นตัวจัดรูปแบบและตัวตรวจสอบ
- ปฏิบัติตามหลักเกณฑ์การทดสอบ
รูปแบบ
รูปแบบ Python
หากไม่แน่ใจ ให้ทำตามคำแนะนำด้านรูปแบบ PEP 8 เมื่อเป็นไปได้ โดยเฉพาะอย่างยิ่ง ให้ใช้ 4 ช่องว่างแทน 2 ช่องว่างสำหรับการเยื้องเพื่อให้เป็นไปตาม รูปแบบของ Python
เนื่องจาก
Starlark ไม่ใช่ Python
ลักษณะบางอย่างของสไตล์ Python จึงไม่มีผล ตัวอย่างเช่น PEP 8 แนะนำว่าการเปรียบเทียบกับ Singleton ควรทำด้วย is
ซึ่งไม่ใช่โอเปอเรเตอร์ใน Starlark
Docstring
จัดทำเอกสารไฟล์และฟังก์ชันโดยใช้สตริงเอกสาร
ใช้สตริงเอกสารที่ด้านบนของไฟล์ .bzl
แต่ละไฟล์ และสตริงเอกสารสำหรับฟังก์ชันสาธารณะแต่ละฟังก์ชัน
กฎและลักษณะของเอกสาร
ควรอธิบายกฎและแง่มุมต่างๆ พร้อมกับแอตทริบิวต์ รวมถึงผู้ให้บริการและฟิลด์ของกฎและแง่มุมเหล่านั้นโดยใช้อาร์กิวเมนต์ 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
ยังตีความได้ยากเนื่องจากเป้าหมายที่แสดงในผลลัพธ์
มาจากการขยายมาโคร สุดท้ายนี้ Aspect ไม่รู้จักมาโคร ดังนั้นเครื่องมือ
ที่ขึ้นอยู่กับ Aspect (IDE และอื่นๆ) อาจทำงานไม่สำเร็จ
การใช้มาโครอย่างปลอดภัยคือการกำหนดเป้าหมายเพิ่มเติมที่ต้องการอ้างอิงโดยตรงใน Bazel CLI หรือในไฟล์ BUILD ในกรณีดังกล่าว มีเพียงผู้ใช้ปลายทางของเป้าหมายเหล่านั้นเท่านั้นที่ต้องทราบเกี่ยวกับเป้าหมายเหล่านั้น และปัญหาการบิลด์ที่เกิดจากมาโครจะอยู่ใกล้กับการใช้งานเสมอ
สำหรับมาโครที่กำหนดเป้าหมายที่สร้างขึ้น (รายละเอียดการติดตั้งใช้งานของมาโคร ซึ่งไม่ควรมีการอ้างอิงที่ CLI หรือขึ้นอยู่กับเป้าหมาย ที่ไม่ได้สร้างอินสแตนซ์โดยมาโครนั้น) ให้ทำตามแนวทางปฏิบัติแนะนำต่อไปนี้
- มาโครควรรับอาร์กิวเมนต์
name
และกำหนดเป้าหมายที่มีชื่อนั้น เป้าหมายนั้นจะกลายเป็นเป้าหมายหลักของมาโครนั้น - เป้าหมายที่สร้างขึ้น ซึ่งก็คือเป้าหมายอื่นๆ ทั้งหมดที่กำหนดโดยมาโคร ควรมีลักษณะดังนี้
- มีคำนำหน้าชื่อเป็น
<name>
หรือ_<name>
เช่น ใช้name = '%s_bar' % (name)
- มีการแสดงผลที่จำกัด (
//visibility:private
) และ - มีแท็ก
manual
เพื่อหลีกเลี่ยงการขยายในเป้าหมายไวลด์การ์ด (:all
,...
,:*
ฯลฯ)
- มีคำนำหน้าชื่อเป็น
name
ควรใช้เพื่อดึงชื่อของเป้าหมายที่กำหนดโดย มาโครเท่านั้น และไม่ควรใช้เพื่อวัตถุประสงค์อื่น เช่น อย่าใช้ชื่อเพื่อสร้าง ไฟล์อินพุตหรือการอ้างอิงที่ไม่ได้สร้างโดยมาโครเอง- เป้าหมายทั้งหมดที่สร้างในมาโครควรเชื่อมโยงกับเป้าหมายหลักในลักษณะใดลักษณะหนึ่ง
- โดยปกติแล้ว
name
ควรเป็นอาร์กิวเมนต์แรกเมื่อกำหนดมาโคร - รักษาชื่อพารามิเตอร์ในมาโครให้สอดคล้องกัน หากส่งพารามิเตอร์
เป็นค่าแอตทริบิวต์ไปยังเป้าหมายหลัก ให้คงชื่อพารามิเตอร์ไว้เหมือนเดิม หากพารามิเตอร์มาโคร
มีวัตถุประสงค์เดียวกันกับแอตทริบิวต์กฎทั่วไป เช่น
deps
ให้ตั้งชื่อตามแอตทริบิวต์ (ดูด้านล่าง) - เมื่อเรียกใช้มาโคร ให้ใช้เฉพาะอาร์กิวเมนต์คีย์เวิร์ด ซึ่งสอดคล้องกับ กฎและช่วยให้อ่านได้ง่ายขึ้นมาก
วิศวกรมักจะเขียนมาโครเมื่อ API ของ Starlark ของกฎที่เกี่ยวข้องไม่เพียงพอสำหรับ Use Case เฉพาะของตน ไม่ว่ากฎจะกำหนดภายใน Bazel ในโค้ดดั้งเดิมหรือใน Starlark ก็ตาม หากคุณพบปัญหานี้ โปรดสอบถามผู้เขียนกฎว่าสามารถขยาย API เพื่อให้บรรลุเป้าหมายของคุณได้หรือไม่
โดยหลักการแล้ว ยิ่งมาโครคล้ายกับกฎมากเท่าใด ก็จะยิ่งดีเท่านั้น
ดูมาโครด้วย
กฎ
- กฎ ลักษณะ และแอตทริบิวต์ของกฎและลักษณะควรใช้ชื่อที่เป็นตัวพิมพ์เล็ก ("snake case")
- ชื่อกฎเป็นคำนามที่อธิบายอาร์ติแฟกต์ประเภทหลักที่สร้างขึ้นโดยกฎจากมุมมองของทรัพยากร Dependency (หรือสำหรับกฎใบไม้ ผู้ใช้) ซึ่งไม่จำเป็นต้องเป็นคำต่อท้ายของไฟล์ เช่น กฎที่สร้างอาร์ติแฟกต์ C++ ที่มีไว้เพื่อใช้เป็นส่วนขยาย Python อาจเรียกว่า
py_extension
สำหรับภาษาส่วนใหญ่ กฎทั่วไปมีดังนี้*_library
- หน่วยการรวบรวมหรือ "โมดูล"*_binary
- เป้าหมายที่สร้างไฟล์ที่เรียกใช้งานได้หรือหน่วยการติดตั้งใช้งาน*_test
- เป้าหมายการทดสอบ ซึ่งอาจรวมถึงการทดสอบหลายครั้ง คาดหวังว่าการทดสอบทั้งหมดใน*_test
เป้าหมายจะเป็นรูปแบบต่างๆ ของธีมเดียวกัน เช่น การทดสอบไลบรารีเดียว*_import
: เป้าหมายที่ห่อหุ้มอาร์ติแฟกต์ที่คอมไพล์ไว้ล่วงหน้า เช่น.jar
หรือ.dll
ที่ใช้ระหว่างการคอมไพล์
- ใช้ชื่อและประเภทที่สอดคล้องกันสำหรับแอตทริบิวต์ ตัวอย่างแอตทริบิวต์ที่ใช้ได้โดยทั่วไปมีดังนี้
srcs
:label_list
ซึ่งอนุญาตไฟล์: ไฟล์ต้นฉบับ ซึ่งโดยปกติแล้วจะ เขียนโดยมนุษย์deps
:label_list
โดยปกติไม่อนุญาตไฟล์: การรวบรวม การขึ้นต่อกันdata
:label_list
อนุญาตไฟล์: ไฟล์ข้อมูล เช่น ข้อมูลการทดสอบ เป็นต้นruntime_deps
:label_list
: การขึ้นต่อกันขณะรันไทม์ที่ไม่จำเป็น สำหรับการคอมไพล์
- สำหรับแอตทริบิวต์ที่มีลักษณะการทำงานที่ไม่ชัดเจน (เช่น เทมเพลตสตริง
ที่มีการแทนที่พิเศษ หรือเครื่องมือที่เรียกใช้ด้วยข้อกำหนดเฉพาะ
) ให้จัดทำเอกสารโดยใช้อาร์กิวเมนต์คีย์เวิร์ด
doc
ในการประกาศแอตทริบิวต์ (attr.label_list()
หรือคล้ายกัน) - ฟังก์ชันการใช้งานกฎควรเป็นฟังก์ชันส่วนตัวเสมอ
(ตั้งชื่อโดยมีขีดล่างนำหน้า) รูปแบบที่ใช้กันทั่วไปคือการตั้งชื่อฟังก์ชันการใช้งานสำหรับ
myrule
_myrule_impl
- ส่งข้อมูลระหว่างกฎโดยใช้อินเทอร์เฟซผู้ให้บริการที่กำหนดไว้อย่างดี ประกาศและจัดทำเอกสารฟิลด์ผู้ให้บริการ
- ออกแบบกฎโดยคำนึงถึงความสามารถในการขยาย โปรดพิจารณาว่ากฎอื่นๆ อาจต้องการโต้ตอบกับกฎของคุณ เข้าถึงผู้ให้บริการ และนำการดำเนินการที่คุณสร้างขึ้นมาใช้ซ้ำ
- ปฏิบัติตามหลักเกณฑ์ด้านประสิทธิภาพในกฎ