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

การจัดรูปแบบไฟล์ 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 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 ด้วยคำต่อท้ายเฉพาะภาษา เช่น
      • 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 ที่ไม่ได้ใช้

กล๊อบ

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

เวียนเกิด

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

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

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

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

ไม่เกิดซ้ำ

โดยทั่วไปแล้วเรายอมรับบอลลูนที่ไม่เวียนเกิด

ข้อบัญญัติอื่นๆ

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

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

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

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

ความแตกต่างด้วยคู่มือสไตล์ Python

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

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

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

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

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

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