คู่มือแนะนำรูปแบบการสร้าง

รายงานปัญหา ดูแหล่งที่มา

การจัดรูปแบบไฟล์ BUILD เป็นไปตามแนวทางเดียวกับ Go ซึ่งเครื่องมือมาตรฐานจะจัดการกับปัญหาเกี่ยวกับการจัดรูปแบบส่วนใหญ่ Buildifier เป็นเครื่องมือที่แยกวิเคราะห์และปล่อยซอร์สโค้ดในรูปแบบมาตรฐาน ดังนั้นไฟล์ BUILD ทุกไฟล์จะได้รับการจัดรูปแบบด้วยวิธีเดียวกัน ซึ่งทําให้การจัดรูปแบบไม่ใช่ปัญหาในระหว่างการตรวจสอบโค้ด นอกจากนี้ยังช่วยให้เครื่องมือทําความเข้าใจ แก้ไข และสร้างไฟล์ BUILD ได้ง่ายขึ้น

การจัดรูปแบบไฟล์ BUILD ต้องตรงกับเอาต์พุตของ buildifier

ตัวอย่างการจัดรูปแบบ

# Test code implementing the Foo controller.
package(default_testonly = True)

py_test(
    name = "foo_test",
    srcs = glob(["*.py"]),
    data = [
        "//data/production/foo:startfoo",
        "//foo",
        "//third_party/java/jdk:jdk-k8",
    ],
    flaky = True,
    deps = [
        ":check_bar_lib",
        ":foo_data_check",
        ":pick_foo_port",
        "//pyglib",
        "//testing/pybase",
    ],
)

โครงสร้างไฟล์

คําแนะนํา: ใช้ลําดับต่อไปนี้ (มีองค์ประกอบทั้งหมดที่ไม่บังคับ)

  • คําอธิบายแพ็กเกจ (ความคิดเห็น)

  • ใบแจ้งยอด load() ทั้งหมด

  • ฟังก์ชัน package()

  • การเรียกใช้กฎและมาโคร

ตัวสร้างความแตกต่างระหว่างความคิดเห็นแบบสแตนด์อโลนกับความคิดเห็นที่แนบอยู่กับองค์ประกอบ หากไม่ได้แนบความคิดเห็นไว้ในองค์ประกอบเฉพาะ ให้ใช้บรรทัดว่างหลังจากความคิดเห็นนั้น ความแตกต่างนี้สําคัญเมื่อทําการเปลี่ยนแปลงอัตโนมัติ (เช่น เก็บหรือนําความคิดเห็นออกเมื่อลบกฎ)

# Standalone comment (such as to make a section in a file)

# Comment for the cc_library below
cc_library(name = "cc")

การอ้างอิงไปยังเป้าหมายในแพ็กเกจปัจจุบัน

ไฟล์ควรอ้างอิงด้วยเส้นทางที่สัมพันธ์กับไดเรกทอรีของแพ็กเกจ (โดยไม่ใช้การอ้างอิงเลย เช่น ..) ไฟล์ที่สร้างควรมี ":" นําหน้า เพื่อบ่งชี้ว่าไม่ใช่แหล่งที่มา ไฟล์ต้นฉบับไม่ควรขึ้นต้นด้วย : กฎควรขึ้นต้นด้วย : เช่น สมมติว่า x.cc เป็นไฟล์ต้นฉบับ

cc_library(
    name = "lib",
    srcs = ["x.cc"],
    hdrs = [":gen_header"],
)

genrule(
    name = "gen_header",
    srcs = [],
    outs = ["x.h"],
    cmd = "echo 'int x();' > $@",
)

การตั้งชื่อเป้าหมาย

ชื่อเป้าหมายควรสื่อความหมาย หากเป้าหมายมีไฟล์ต้นฉบับ 1 ไฟล์ โดยทั่วไปเป้าหมายควรมีชื่อที่มาจากแหล่งที่มานั้น (เช่น cc_library สําหรับ chat.cc อาจมีชื่อเป็น chat หรือ java_library สําหรับ DirectMessage.java อาจมีชื่อว่า direct_message)

เป้าหมายที่มีชื่อเดียวกันของแพ็กเกจ (เป้าหมายที่มีชื่อเดียวกับไดเรกทอรีที่มี) ควรให้ฟังก์ชันการทํางานที่อธิบายโดยชื่อไดเรกทอรี หากไม่มีเป้าหมายดังกล่าว อย่าสร้างเป้าหมายที่มีชื่อเดียวกัน

ต้องการใช้ชื่อย่อเมื่อกล่าวถึงเป้าหมายที่ไม่ระบุชื่อ (//x แทนที่จะเป็น //x:x) หากคุณอยู่ในแพ็กเกจเดียวกัน ให้ใช้การอ้างอิงในพื้นที่ (:x แทน //x)

หลีกเลี่ยงการใช้ชื่อเป้าหมายที่ "จองแล้ว" ซึ่งมีความหมายพิเศษ ซึ่งรวมถึง all, __pkg__ และ __subpackages__ ชื่อเหล่านี้มีความหมายพิเศษและอาจทําให้เกิดความสับสนและลักษณะการทํางานที่ไม่คาดคิดเมื่อนํามาใช้

ในกรณีที่ไม่มีรูปแบบการประชุมที่ใกล้เคียงกัน คําแนะนําบางส่วนที่ Google ใช้กันอย่างแพร่หลายมีดังนี้

  • โดยทั่วไป ให้ใช้ "snake_case"
    • สําหรับ java_library ที่มี src จะหมายถึงการใช้ชื่อที่ไม่เหมือนกับชื่อไฟล์ที่ไม่มีนามสกุล
    • สําหรับกฎ Java *_binary และ *_test ให้ใช้ "Upper CamelCase" ซึ่งจะทําให้ชื่อเป้าหมายตรงกับหนึ่งใน src ได้ สําหรับ java_test อาจทําให้แอตทริบิวต์ test_class อนุมานจากชื่อเป้าหมายได้
  • หากมีตัวแปรหลายรายการของเป้าหมายหนึ่งๆ ให้เพิ่มคําต่อท้ายที่ให้คําอธิบาย (เช่น :foo_dev, :foo_prod หรือ :bar_x86, :bar_x64)
  • กําหนดเป้าหมาย _test ด้วย _test, _unittest, Test หรือ Tests
  • หลีกเลี่ยงคําต่อท้ายที่ไม่มีความหมาย เช่น _lib หรือ _library (เว้นแต่จะต้องหลีกเลี่ยงความขัดแย้งระหว่างเป้าหมาย _library กับ _binary ที่เกี่ยวข้อง)
  • สําหรับเป้าหมายที่เกี่ยวข้องกับต้นแบบ ให้ทําดังนี้
    • เป้าหมาย proto_library รายการควรมีชื่อที่ลงท้ายด้วย _proto
    • กฎ *_proto_library ภาษาที่เจาะจงควรตรงกับโปรโตพื้นฐาน แต่แทนที่ _proto ด้วยคําต่อท้ายภาษาที่เจาะจง เช่น
      • cc_proto_library: _cc_proto
      • java_proto_library: _java_proto
      • java_lite_proto_library: _java_proto_lite

ระดับการแชร์

ควรกําหนดขอบเขตระดับการเข้าถึงให้มากที่สุดเท่าที่จะเป็นไปได้ ขณะที่ยังอนุญาตการเข้าถึงด้วยการทดสอบและทรัพยากร Dependency แบบย้อนกลับ ใช้ __pkg__ และ __subpackages__ ตามความเหมาะสม

หลีกเลี่ยงการตั้งค่าแพ็กเกจ default_visibility เป็น //visibility:public ควรตั้งค่า //visibility:public แต่ละรายการสําหรับเป้าหมายใน API สาธารณะของโปรเจ็กต์เท่านั้น ซึ่งอาจเป็นไลบรารีที่ออกแบบมาเพื่อใช้โปรเจ็กต์ภายนอกหรือไบนารีที่กระบวนการสร้างของโปรเจ็กต์ภายนอกใช้ได้

การอ้างอิง

ทรัพยากร Dependency ต้องจํากัดตามทรัพยากร Dependency โดยตรง (ทรัพยากร Dependency ที่จําเป็นโดยแหล่งที่มาที่ระบุไว้ในกฎ) ไม่ต้องระบุทรัพยากร Dependency ชั่วคราว

ควรแสดงทรัพยากร Dependency ในแพ็กเกจก่อน และอ้างอิงด้วยวิธีที่ใช้ได้กับส่วนการอ้างอิงถึงเป้าหมายในแพ็กเกจปัจจุบันด้านบน (ไม่ใช่ชื่อแพ็กเกจสัมบูรณ์)

ระบุรายการทรัพยากร Dependency โดยตรงเป็นรายการเดียว การทําให้ทรัพยากร Dependency "ทั่วไป" ของตัวแปรหลายรายการกลายเป็นตัวแปรจะช่วยลดการดูแลรักษา และทําให้เครื่องมือไม่สามารถเปลี่ยนแปลงทรัพยากร Dependency ของเป้าหมายได้ และอาจทําให้ทรัพยากร Dependency ที่ไม่ได้ใช้อยู่ในนั้น

แสงสะท้อน

ระบุว่า "ไม่มีเป้าหมาย" ด้วย [] อย่าใช้ Glob ที่ตรงกับของแถม ข้อผิดพลาดมักเกิดข้อผิดพลาดและเห็นได้ชัดน้อยกว่ารายการที่ว่างเปล่า

เกิดซ้ํา

อย่าใช้ Glop ที่เกิดซ้ําเพื่อจับคู่กับไฟล์แหล่งที่มา (เช่น glob(["**/*.java"]))

การเกิด GLOB ซ้ําทําให้ไฟล์ BUILD ไม่ทราบสาเหตุเนื่องจากข้ามไดเรกทอรีย่อยที่มี BUILD ไฟล์

โดยทั่วไปแล้ว GLOB ที่เกิดซ้ําจะมีประสิทธิภาพน้อยกว่าการมีไฟล์ BUILD ต่อไดเรกทอรีที่มีการกําหนดทรัพยากร Dependency ไว้ เนื่องจากทําให้การแคชและการโหลดพร้อมกันทําได้ดีขึ้น

แนวทางปฏิบัติที่ดีคือการเขียนไฟล์ BUILD ในแต่ละไดเรกทอรีและกําหนดกราฟ Dependency ระหว่างไฟล์เหล่านั้น

ไม่เกิดซ้ํา

โดยทั่วไปจะใช้ GLOB ที่ไม่เกิดซ้ําได้

การประชุมอื่นๆ

  • ใช้ตัวพิมพ์ใหญ่และขีดล่างเพื่อประกาศค่าคงที่ (เช่น GLOBAL_CONSTANT) ใช้ตัวพิมพ์เล็กและขีดล่างเพื่อประกาศตัวแปร (เช่น my_variable)

  • คุณไม่ควรแยกป้ายกํากับออก แม้ว่าป้ายกํากับจะยาวกว่า 79 อักขระก็ตาม ป้ายกํากับควรเป็นสัญพจน์ของสตริงทุกครั้งที่ทําได้ ความสําคัญและเหตุผล: ช่วยให้คุณค้นหาและแทนที่ได้อย่างง่ายดาย และยังช่วยปรับปรุงให้อ่านง่ายขึ้น

  • ค่าของแอตทริบิวต์ชื่อควรเป็นสตริงค่าคงที่ตามจริง (ยกเว้นมาโคร) ความสําคัญ: เครื่องมือภายนอกใช้แอตทริบิวต์ชื่อเพื่ออ้างถึงกฎ พวกเขาจําเป็นต้องค้นหากฎโดยไม่ต้องตีความโค้ด

  • เมื่อตั้งค่าแอตทริบิวต์ประเภทบูลีน ให้ใช้ค่าบูลีน ไม่ใช่ค่าจํานวนเต็ม สําหรับเหตุผลเดิม กฎยังคงแปลงจํานวนเต็มเป็นบูลีนตามที่จําเป็น แต่เราไม่แนะนําให้ทําเช่นนั้น ความสําคัญ: flaky = 1 อาจทําให้เข้าใจผิดว่า "ทําให้เป้าหมายนี้ลดลงโดยการเรียกใช้อีกครั้งครั้งเดียว" flaky = True บอกว่า "การทดสอบนี้ไม่น่าเชื่อถือ"

ความแตกต่างกับคําแนะนําเกี่ยวกับสไตล์ Python

แม้ว่าความเข้ากันได้กับคําแนะนําเกี่ยวกับสไตล์ Python จะเป็นเป้าหมาย แต่ก็มีความแตกต่างบางประการดังนี้

  • ไม่จํากัดความยาวของบรรทัด ความคิดเห็นแบบยาวและสตริงแบบยาวมักจะแบ่งออกเป็น 79 คอลัมน์ แต่ไม่จําเป็น ไม่ควรบังคับใช้ในการตรวจสอบโค้ดหรือส่งสคริปต์ล่วงหน้า เหตุผล: ป้ายกํากับอาจยาวและเกินขีดจํากัดนี้ เป็นเรื่องปกติที่ไฟล์ BUILD จะถูกสร้างหรือแก้ไขโดยเครื่องมือ ซึ่งมีประสิทธิภาพไม่ดีหากมีขีดจํากัดความยาวบรรทัด

  • ระบบไม่รองรับการเชื่อมโยงสตริงแบบโดยนัย ใช้โอเปอเรเตอร์ + ความสําคัญและที่มาของปัญหา: BUILD ไฟล์มีรายการสตริงจํานวนมาก ลืมเครื่องหมายจุลภาคได้ง่ายๆ ซึ่งนําไปสู่ผลลัพธ์ที่ต่างกันโดยสิ้นเชิง สิ่งนี้เคยสร้างข้อบกพร่องจํานวนมาก ดูการสนทนานี้ด้วย

  • ใช้การเว้นวรรครอบๆ เครื่องหมาย = เพื่อดูอาร์กิวเมนต์ของคีย์เวิร์ดในกฎ เหตุผล: อาร์กิวเมนต์ที่มีชื่อใช้บ่อยกว่าใน Python มากและอยู่ในบรรทัดแยกต่างหากเสมอ พื้นที่ทํางานจะช่วยให้อ่านง่ายขึ้น การประชุมนี้ดําเนินมาเป็นเวลานานแล้ว จึงไม่ควรแก้ไขไฟล์ BUILD ที่มีอยู่ทั้งหมด

  • โดยค่าเริ่มต้น ให้ใช้เครื่องหมายคําพูดคู่สําหรับสตริง ความสําคัญ: ส่วนนี้ไม่ได้ระบุในคู่มือสไตล์ Python แต่แนะนําให้ใช้ความสอดคล้อง เราจึงตัดสินใจใช้เฉพาะสตริงที่ใส่เครื่องหมายคําพูดคู่เท่านั้น หลายภาษาใช้เครื่องหมายคําพูดคู่ สําหรับสัญพจน์ของสตริง

  • ใช้บรรทัดว่างบรรทัดเดียวระหว่างคําจํากัดความระดับบนสุด 2 รายการ เหตุผล: โครงสร้างของไฟล์ BUILD ไม่เหมือนไฟล์ Python ทั่วไป มีเฉพาะข้อความระดับบนสุดเท่านั้น การใช้บรรทัดว่างบรรทัดเดียวจะทําให้ไฟล์ BUILD รายการสั้นลง