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