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

รายงานปัญหา ดูแหล่งที่มา /3} /4} {3/4} {3/4} {3/4} {3/4} /4.

การจัดรูปแบบไฟล์ 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 1 รายการ นั่นหมายถึงการใช้ชื่อที่ไม่เหมือนกับชื่อไฟล์ที่ไม่มีนามสกุล
    • สำหรับกฎ 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 ที่ไม่ได้ใช้ได้

ลูกโลก

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

เกิดซ้ำ

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

glob ที่เกิดซ้ำทำให้ไฟล์ BUILD เข้าใจยากเนื่องจากข้ามไดเรกทอรีย่อยที่มีไฟล์ BUILD

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

คุณควรเขียนไฟล์ BUILD ในแต่ละไดเรกทอรีและกำหนดกราฟการขึ้นต่อกันระหว่างไดเรกทอรีดังกล่าว

ไม่เกิดซ้ำ

โดยทั่วไปเรายอมรับ glob ที่ไม่เกิดซ้ำ

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

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

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

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

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

ความแตกต่างกับคู่มือรูปแบบ Python

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

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

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

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

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

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