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

รายงานปัญหา ดูแหล่งที่มา Nightly · 8.4 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

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()

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

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

# 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 ให้ทำดังนี้
    • proto_library เป้าหมายควรมีชื่อที่ลงท้ายด้วย _proto
    • ภาษาที่เฉพาะเจาะจง*_proto_libraryควรตรงกับโปรโตที่เกี่ยวข้อง แต่ให้แทนที่ _proto ด้วยคำต่อท้ายที่เฉพาะเจาะจงภาษา เช่น
      • cc_proto_library: _cc_proto
      • java_proto_library: _java_proto
      • java_lite_proto_library: _java_proto_lite

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

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

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

แท็กเริ่มการทำงาน

ควรจำกัดทรัพยากร Dependency ไว้ที่ทรัพยากร Dependency โดยตรง (ทรัพยากร Dependency ที่แหล่งข้อมูลที่ระบุในกฎต้องใช้) อย่าแสดงทรัพยากร Dependency แบบทรานซิทีฟ

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

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

Globs

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

แบบเรียกซ้ำ

อย่าใช้ Glob แบบเรียกซ้ำเพื่อจับคู่ไฟล์ต้นฉบับ (เช่น glob(["**/*.java"]))

Glob แบบเรียกซ้ำทำให้ไฟล์ BUILD จัดการได้ยากเนื่องจากจะข้ามไดเรกทอรีย่อยที่มีไฟล์ BUILD

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

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

แบบไม่เกิดซ้ำ

โดยทั่วไปแล้ว ระบบจะยอมรับ Glob ที่ไม่ใช่แบบเรียกซ้ำ

รูปแบบอื่นๆ

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

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

  • ค่าของแอตทริบิวต์ชื่อควรเป็นสตริงค่าคงที่ตามตัวอักษร (ยกเว้นในมาโคร) เหตุผล: เครื่องมือภายนอกใช้แอตทริบิวต์ชื่อเพื่ออ้างอิงกฎ โดยผู้ใช้ต้องค้นหากฎได้โดยไม่ต้องตีความโค้ด

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

ความแตกต่างกับคำแนะนำด้านรูปแบบของ Python

แม้ว่าเป้าหมายของเราคือการทำให้เข้ากันได้กับ คำแนะนำเกี่ยวกับรูปแบบของ Python แต่ก็มีความแตกต่างกันอยู่บ้าง ดังนี้

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

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

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

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

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