หน้านี้ครอบคลุมหลักเกณฑ์ด้านสไตล์พื้นฐานสำหรับ 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 แนะนำให้ใช้ 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
เพื่อรับชื่อเป้าหมายที่มาโครกำหนดเท่านั้น ไม่ใช่สำหรับอย่างอื่น เช่น อย่าใช้ชื่อเพื่อดึงทรัพยากร Dependency หรือไฟล์อินพุตที่ไม่ได้สร้างขึ้นโดยมาโครเอง - เป้าหมายทั้งหมดที่สร้างในมาโครควรเชื่อมโยงกับเป้าหมายหลักด้วยวิธีใดวิธีหนึ่ง
- ตามธรรมเนียมแล้ว
name
ควรเป็นอาร์กิวเมนต์แรกเมื่อกำหนดมาโคร - ตั้งชื่อพารามิเตอร์ในมาโครให้สอดคล้องกัน หากส่งพารามิเตอร์เป็นค่าแอตทริบิวต์ไปยังเป้าหมายหลัก ให้ใช้ชื่อเดิม หากพารามิเตอร์มาโครมีจุดประสงค์เดียวกับแอตทริบิวต์กฎทั่วไป เช่น
deps
ให้ตั้งชื่อเช่นเดียวกับแอตทริบิวต์ (ดูด้านล่าง) - เมื่อเรียกใช้มาโคร ให้ใช้เฉพาะอาร์กิวเมนต์คีย์เวิร์ด วิธีนี้สอดคล้องกับกฎและช่วยให้อ่านได้ง่ายขึ้นมาก
วิศวกรมักเขียนมาโครเมื่อ Starlark API ของกฎที่เกี่ยวข้องไม่เพียงพอสำหรับกรณีการใช้งานที่เฉพาะเจาะจง ไม่ว่าจะมีการกำหนดกฎภายใน Bazel ในโค้ดแบบเนทีฟหรือใน Starlark หากคุณพบปัญหานี้ โปรดสอบถามผู้เขียนกฎว่าสามารถขยาย API เพื่อให้บรรลุเป้าหมายของคุณได้หรือไม่
ตามหลักการทั่วไป ยิ่งมาโครมีลักษณะคล้ายกฎมากเท่าใดก็ยิ่งดีเท่านั้น
ดูมาโครเพิ่มเติม
กฎ
- กฎ ลักษณะ และแอตทริบิวต์ควรใช้ชื่อตัวพิมพ์เล็ก ("งูเล็ก")
- ชื่อกฎคือคำนามที่อธิบายถึงประเภทหลักของอาร์ติแฟกต์ที่กฎสร้างขึ้นจากมุมมองของข้อกำหนด (หรือผู้ใช้สำหรับกฎระดับล่าง) ไม่จำเป็นต้องเป็นคำต่อท้ายไฟล์ เช่น กฎที่ผลิตอาร์ติแฟกต์ 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
- ส่งข้อมูลระหว่างกฎโดยใช้อินเทอร์เฟซ provider ที่กําหนดไว้อย่างดี ประกาศและจัดทำเอกสารเกี่ยวกับช่องผู้ให้บริการ
- ออกแบบกฎโดยคำนึงถึงความยืดหยุ่น พิจารณาว่ากฎอื่นๆ อาจต้องการโต้ตอบกับกฎ เข้าถึงผู้ให้บริการ และนำการดำเนินการที่คุณสร้างมาใช้ซ้ำ
- ปฏิบัติตามหลักเกณฑ์ด้านประสิทธิภาพในกฎ