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