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

รายงานปัญหา ดูซอร์สโค้ด รุ่น Nightly · 8.0 7.4 7.3 · 7.2 · 7.1 · 7.0 · 6.5

การจัดรูปแบบไฟล์ 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();' > $@",
)

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

ชื่อเป้าหมายควรสื่อความหมาย หากเป้าหมายมีไฟล์ต้นทางไฟล์เดียว โดยทั่วไปเป้าหมายควรมีชื่อที่มาจากแหล่งที่มานั้น (เช่น 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 แบบทรานซิทีฟ

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

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

Globs

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

เกิดซ้ำ

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

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

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

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

ไม่ใช้การเรียกซ้ำ

โดยทั่วไประบบจะยอมรับรูปแบบทั่วไปแบบไม่ซ้ำ

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

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

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

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

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

ความแตกต่างกับคู่มือสไตล์ Python

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

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

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

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

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

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