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

รายงานปัญหา ดูแหล่งที่มา รุ่น Nightly · 7.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 ตัว หมายความว่าใช้ชื่อที่ไม่ใช่ชื่อไฟล์ที่ไม่มีนามสกุล
    • สำหรับกฎ *_binary และ *_test ของ Java ให้ใช้"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 พื้นฐาน แต่แทนที่ _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 ที่ไม่ได้ใช้ได้

Globs

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

เกิดซ้ำ

อย่าใช้ 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 ไฟล์สั้นลง