เกริ่นนำ
หากเพิ่งเริ่มใช้ Bazel คุณมาถูกที่แล้ว ทำตามบทแนะนำการสร้างครั้งแรกนี้เพื่อดูบทแนะนำง่ายๆ ในการใช้ Bazel บทแนะนำนี้จะให้คำจำกัดความคำสำคัญเนื่องจากเป็นคำที่ใช้ในบริบทของ Bazel และจะแนะนำพื้นฐานต่างๆ เกี่ยวกับเวิร์กโฟลว์ของ Bazel เริ่มต้นด้วยเครื่องมือที่จำเป็นต้องใช้ คุณจะสร้างและเรียกใช้โครงการ 3 โครงการที่มีความซับซ้อนเพิ่มขึ้นและเรียนรู้ว่าโครงการเหล่านั้นซับซ้อนขึ้นได้อย่างไรและเพราะอะไร
แม้ว่า Bazel จะเป็นระบบการสร้างที่รองรับบิลด์หลายภาษา แต่บทแนะนำนี้ใช้โปรเจ็กต์ C++ เป็นตัวอย่าง และให้หลักเกณฑ์และขั้นตอนทั่วไปที่ใช้กับภาษาส่วนใหญ่
เวลาที่ใช้ดำเนินการจนเสร็จโดยประมาณ 30 นาที
ข้อกำหนดเบื้องต้น
เริ่มต้นด้วยการติดตั้ง Bazel หากยังไม่ได้ติดตั้ง บทแนะนำนี้ใช้ Git สำหรับการควบคุมแหล่งที่มา ดังนั้น เพื่อผลลัพธ์ที่ดีที่สุด ให้ติดตั้ง Git ด้วย
ถัดไป ให้เรียกข้อมูลโปรเจ็กต์ตัวอย่างจากที่เก็บ GitHub ของ Bazel โดยเรียกใช้รายการต่อไปนี้ในเครื่องมือบรรทัดคำสั่งที่ต้องการ
git clone https://github.com/bazelbuild/examples
โปรเจ็กต์ตัวอย่างสำหรับบทแนะนำนี้อยู่ในไดเรกทอรี examples/cpp-tutorial
ดูโครงสร้างได้ที่ด้านล่าง
examples
└── cpp-tutorial
├──stage1
│ ├── main
│ │ ├── BUILD
│ │ └── hello-world.cc
│ └── WORKSPACE
├──stage2
│ ├── main
│ │ ├── BUILD
│ │ ├── hello-world.cc
│ │ ├── hello-greet.cc
│ │ └── hello-greet.h
│ └── WORKSPACE
└──stage3
├── main
│ ├── BUILD
│ ├── hello-world.cc
│ ├── hello-greet.cc
│ └── hello-greet.h
├── lib
│ ├── BUILD
│ ├── hello-time.cc
│ └── hello-time.h
└── WORKSPACE
ไฟล์มีอยู่ด้วยกัน 3 ชุด แต่ละชุดแสดงถึงขั้นตอนในบทแนะนำนี้ ในระยะแรก คุณจะสร้างเป้าหมายเดียวที่อยู่ในแพ็กเกจเดียว ในขั้นตอนที่ 2 คุณจะสร้างทั้งไบนารีและไลบรารีจากแพ็กเกจเดียว ในขั้นตอนที่ 3 ซึ่งเป็นระยะสุดท้าย คุณจะสร้างโปรเจ็กต์ที่มีแพ็กเกจหลายรายการและสร้างโดยมีเป้าหมายหลายรายการ
สรุป: บทนำ
การติดตั้ง Bazel (และ Git) และโคลนที่เก็บสำหรับบทแนะนำนี้ คุณได้วางรากฐานให้งานสร้างแรกของคุณด้วย Bazel ไปยังส่วนถัดไปเพื่อระบุข้อกำหนดบางอย่างและตั้งค่าพื้นที่ทำงาน
เริ่มต้นใช้งาน
ตั้งค่าพื้นที่ทำงาน
คุณต้องตั้งค่าพื้นที่ทำงานของโปรเจ็กต์ก่อนจึงจะสร้างโปรเจ็กต์ได้ พื้นที่ทำงานคือไดเรกทอรีที่เก็บไฟล์ต้นฉบับของโปรเจ็กต์และเอาต์พุตบิลด์ของ Bazel นอกจากนี้ยังมีไฟล์สำคัญต่อไปนี้ด้วย
ซึ่งระบุว่าไดเรกทอรีและเนื้อหาในไดเรกทอรีเป็นพื้นที่ทำงานของ Bazel และใช้อยู่ในรูทของโครงสร้างไดเรกทอรีของโปรเจ็กต์WORKSPACE
file
อย่างน้อย 1 รายการ ซึ่งบอกวิธีสร้างส่วนต่างๆ ของโปรเจ็กต์ ไดเรกทอรีภายในพื้นที่ทำงานที่มีไฟล์BUILD
filesBUILD
จะเป็นแพ็กเกจ (ดูข้อมูลเพิ่มเติมเกี่ยวกับแพ็กเกจได้ ภายหลังในบทแนะนำนี้)
ในโปรเจ็กต์ในอนาคต หากต้องการกำหนดไดเรกทอรีเป็นพื้นที่ทำงาน Bazel ให้สร้างไฟล์เปล่าชื่อ WORKSPACE
ในไดเรกทอรีนั้น เพื่อให้เป็นไปตามจุดประสงค์ของบทแนะนำนี้ มีไฟล์ WORKSPACE
อยู่แล้วในแต่ละระยะ
หมายเหตุ: เมื่อ Bazel สร้างโปรเจ็กต์ อินพุตทั้งหมดต้องอยู่ในพื้นที่ทำงานเดียวกัน ไฟล์ที่อยู่ในพื้นที่ทำงานต่างๆ จะไม่เป็นอิสระจากกัน เว้นแต่จะมีการลิงก์ ดูข้อมูลโดยละเอียดเพิ่มเติมเกี่ยวกับกฎพื้นที่ทำงานได้ในคู่มือนี้
ทำความเข้าใจไฟล์ BUILD
ไฟล์ BUILD
ประกอบด้วยวิธีการประเภทต่างๆ สำหรับ Bazel ไฟล์ BUILD
แต่ละไฟล์ต้องมีกฎอย่างน้อย 1 ชุดต่อชุดคำสั่ง ซึ่งจะบอกให้ Bazel ทราบถึงวิธีสร้างเอาต์พุตที่ต้องการ เช่น ไบนารีหรือไลบรารีที่สั่งการได้ แต่ละอินสแตนซ์ของกฎการสร้างในไฟล์ BUILD
จะเรียกว่าเป้าหมาย และชี้ไปที่ชุดไฟล์ต้นฉบับและทรัพยากร Dependency
เป้าหมายยังชี้ไปยังเป้าหมายอื่นๆ ได้ด้วย
ดูไฟล์ BUILD
ในไดเรกทอรี cpp-tutorial/stage1/main
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
)
ในตัวอย่างของเรา เป้าหมาย hello-world
สร้างอินสแตนซ์ cc_binary rule
ของ Bazel
กฎนี้จะบอกให้ Bazel สร้างไบนารีสั่งการแบบในตัวจากไฟล์ต้นทาง hello-world.cc
ที่ไม่มีทรัพยากร Dependency
สรุป: การเริ่มต้นใช้งาน
ตอนนี้คุณก็คุ้นเคยกับคำศัพท์สำคัญและความหมายของคำเหล่านั้นในบริบทของโปรเจ็กต์นี้และ Bazel โดยทั่วไปแล้ว ในหัวข้อถัดไป คุณจะได้สร้างและทดสอบ ระยะที่ 1 ของโปรเจ็กต์
ขั้นที่ 1: เป้าหมายเดียว แพ็กเกจเดียว
ถึงเวลาสร้างส่วนแรกของโครงการแล้ว เพื่อให้เห็นภาพ โครงสร้างของส่วนระยะที่ 1 ของโปรเจ็กต์คือ
examples
└── cpp-tutorial
└──stage1
├── main
│ ├── BUILD
│ └── hello-world.cc
└── WORKSPACE
เรียกใช้คำสั่งต่อไปนี้เพื่อย้ายไปยังไดเรกทอรี cpp-tutorial/stage1
cd cpp-tutorial/stage1
ต่อไป ให้เรียกใช้
bazel build //main:hello-world
ในป้ายกำกับเป้าหมาย ส่วน //main:
คือตำแหน่งของไฟล์ BUILD
ที่สัมพันธ์กับรูทของพื้นที่ทำงาน และ hello-world
เป็นชื่อเป้าหมายในไฟล์ BUILD
Bazel สร้างเนื้อหาที่มีลักษณะดังนี้
INFO: Found 1 target...
Target //main:hello-world up-to-date:
bazel-bin/main/hello-world
INFO: Elapsed time: 2.267s, Critical Path: 0.25s
คุณเพิ่งสร้างเป้าหมาย Bazel อันแรก Bazel จะวางเอาต์พุตของบิลด์ในไดเรกทอรี bazel-bin
ที่รูทของพื้นที่ทำงาน
ต่อไปให้ทดสอบไบนารีที่สร้างใหม่ซึ่งได้แก่
bazel-bin/main/hello-world
ซึ่งจะส่งผลให้เกิดข้อความ "Hello world
" ที่พิมพ์ออกมา
กราฟการอ้างอิงของระยะที่ 1 มีดังนี้
สรุป: ขั้นที่ 1
ตอนนี้คุณสร้างบิลด์แรกเสร็จแล้ว คุณพอจะมีแนวคิดเบื้องต้นบ้างว่าบิลด์นั้นมีโครงสร้างอย่างไร ในขั้นตอนถัดไป คุณจะเพิ่มความซับซ้อนโดยการเพิ่มเป้าหมายอื่น
ขั้นที่ 2: เป้าหมายบิลด์หลายรายการ
แม้ว่าเป้าหมายเดียวก็เพียงพอแล้วสำหรับโปรเจ็กต์ขนาดเล็ก แต่คุณอาจต้องแบ่งโปรเจ็กต์ขนาดใหญ่ออกเป็นหลายเป้าหมายและแพ็กเกจ วิธีนี้ทำให้งานสร้างเพิ่มขึ้นอย่างรวดเร็ว กล่าวคือ Bazel จะสร้างเฉพาะสิ่งที่เปลี่ยนแปลงเท่านั้น ซึ่งช่วยให้งานสร้างของคุณเร็วขึ้นด้วยการสร้างหลายๆ ส่วนของโปรเจ็กต์พร้อมกัน ขั้นตอนนี้ของบทแนะนำจะเพิ่มเป้าหมาย และถัดไปจะเพิ่มแพ็กเกจ
นี่คือไดเรกทอรีที่คุณทำงานด้วยระยะที่ 2:
├──stage2
│ ├── main
│ │ ├── BUILD
│ │ ├── hello-world.cc
│ │ ├── hello-greet.cc
│ │ └── hello-greet.h
│ └── WORKSPACE
ดูไฟล์ BUILD
ในไดเรกทอรี cpp-tutorial/stage2/main
ด้านล่าง
cc_library(
name = "hello-greet",
srcs = ["hello-greet.cc"],
hdrs = ["hello-greet.h"],
)
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
deps = [
":hello-greet",
],
)
ด้วยไฟล์ BUILD
นี้ Bazel จะสร้างไลบรารี hello-greet
ขึ้นมาก่อน (โดยใช้ cc_library rule
ในตัวของ Bazel) จากนั้นจึงสร้างไบนารี hello-world
แอตทริบิวต์ deps
ในเป้าหมาย hello-world
จะบอกบาเซลว่าต้องมีไลบรารี hello-greet
เพื่อสร้างไบนารี hello-world
คุณต้องเปลี่ยนไดเรกทอรีก่อนที่จะสร้างโปรเจ็กต์เวอร์ชันใหม่นี้ โดยเปลี่ยนไปใช้ไดเรกทอรี cpp-tutorial/stage2
โดยเรียกใช้
cd ../stage2
ตอนนี้คุณสามารถสร้างไบนารีใหม่โดยใช้คำสั่งที่คุ้นเคยต่อไปนี้
bazel build //main:hello-world
ขอย้ำอีกครั้งว่า Bazel สร้างผลงานที่มีลักษณะดังนี้
INFO: Found 1 target...
Target //main:hello-world up-to-date:
bazel-bin/main/hello-world
INFO: Elapsed time: 2.399s, Critical Path: 0.30s
ตอนนี้คุณสามารถทดสอบไบนารีที่สร้างใหม่ซึ่งแสดงผล "Hello world
" อีกรายการได้:
bazel-bin/main/hello-world
หากแก้ไข hello-greet.cc
และสร้างโปรเจ็กต์ใหม่ Bazel จะคอมไพล์ไฟล์นั้นซ้ำเท่านั้น
เมื่อดูกราฟการใช้ทรัพยากร Dependency แล้ว คุณจะเห็นว่า hello-world
อ้างอิงรายการเพิ่มเติมชื่อ hello-greet
ดังนี้
สรุป: ขั้นที่ 2
ตอนนี้คุณได้สร้างโปรเจ็กต์ที่มี 2 เป้าหมายแล้ว เป้าหมาย hello-world
จะสร้างไฟล์ต้นทาง 1 ไฟล์และขึ้นอยู่กับเป้าหมายอีก 1 เป้าหมาย (//main:hello-greet
) ซึ่งจะสร้างไฟล์ต้นทางเพิ่มเติม 2 ไฟล์ ในส่วนถัดไป ให้ก้าวไปอีกขั้น
และเพิ่มแพ็กเกจอีก 1 แพ็กเกจ
ขั้นที่ 3: แพ็กเกจหลายชิ้น
ขั้นตอนถัดไปนี้จะเพิ่มข้อมูลแทรกอีกชั้นหนึ่งและสร้างโปรเจ็กต์ที่มีแพ็กเกจหลายรายการ มาดูโครงสร้างและเนื้อหาของไดเรกทอรี cpp-tutorial/stage3
ที่ด้านล่าง
└──stage3
├── main
│ ├── BUILD
│ ├── hello-world.cc
│ ├── hello-greet.cc
│ └── hello-greet.h
├── lib
│ ├── BUILD
│ ├── hello-time.cc
│ └── hello-time.h
└── WORKSPACE
คุณจะเห็นว่าตอนนี้มีไดเรกทอรีย่อย 2 รายการ และแต่ละไดเรกทอรีมีไฟล์ BUILD
ดังนั้น สำหรับ Bazel แล้วตอนนี้ พื้นที่ทำงานจะมี 2 แพ็กเกจ ได้แก่ lib
และ main
ดูไฟล์ lib/BUILD
รายการนี้
cc_library(
name = "hello-time",
srcs = ["hello-time.cc"],
hdrs = ["hello-time.h"],
visibility = ["//main:__pkg__"],
)
และที่ไฟล์ main/BUILD
:
cc_library(
name = "hello-greet",
srcs = ["hello-greet.cc"],
hdrs = ["hello-greet.h"],
)
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
deps = [
":hello-greet",
"//lib:hello-time",
],
)
เป้าหมาย hello-world
ในแพ็กเกจหลักขึ้นอยู่กับเป้าหมาย hello-time
ในแพ็กเกจ lib
(ดังนั้นจึงมีป้ายกำกับเป้าหมาย //lib:hello-time
) โดย Bazel รู้เรื่องนี้ผ่านแอตทริบิวต์ deps
ข้อมูลนี้จะแสดงในกราฟทรัพยากร Dependency
เพื่อให้บิลด์ประสบความสำเร็จ คุณต้องกำหนดให้เป้าหมาย //lib:hello-time
ใน lib/BUILD
แสดงต่อเป้าหมายใน main/BUILD
อย่างชัดแจ้งโดยใช้แอตทริบิวต์ระดับการเข้าถึง
ทั้งนี้เนื่องจากโดยค่าเริ่มต้น เป้าหมายอื่นจะมองเห็นได้เฉพาะเป้าหมายอื่นๆ ในไฟล์ BUILD
เดียวกันเท่านั้น Bazel ใช้ระดับการเข้าถึงเป้าหมายเพื่อป้องกันปัญหาต่างๆ เช่น ไลบรารีที่มีรายละเอียดการใช้งานรั่วไหลเข้าสู่ API สาธารณะ
ต่อไปให้สร้างโปรเจ็กต์เวอร์ชันสุดท้ายนี้ เปลี่ยนไปใช้ไดเรกทอรี cpp-tutorial/stage3
โดยเรียกใช้
cd ../stage3
เรียกใช้คำสั่งต่อไปนี้อีกครั้ง
bazel build //main:hello-world
Bazel สร้างเนื้อหาที่มีลักษณะดังนี้
INFO: Found 1 target...
Target //main:hello-world up-to-date:
bazel-bin/main/hello-world
INFO: Elapsed time: 0.167s, Critical Path: 0.00s
จากนั้นทดสอบไบนารีสุดท้ายของบทแนะนำนี้สำหรับข้อความ Hello world
สุดท้าย
bazel-bin/main/hello-world
สรุป: ขั้นที่ 3
ตอนนี้คุณได้สร้างโปรเจ็กต์เป็น 2 แพ็กเกจที่มี 3 เป้าหมายและเข้าใจทรัพยากร Dependency แล้ว ซึ่งจะช่วยให้คุณก้าวไปข้างหน้าและสร้างโปรเจ็กต์ในอนาคตกับ Bazel ในส่วนถัดไป เราจะมาดูวิธีกันต่อ ใน Bazel
ขั้นตอนถัดไป
คุณสร้างงานสร้างพื้นฐานชิ้นแรกกับ Bazel เสร็จแล้ว แต่นี่เป็นเพียงจุดเริ่มต้นเท่านั้น ต่อไปนี้เป็นแหล่งข้อมูลเพิ่มเติมเพื่อการเรียนรู้อย่างต่อเนื่องกับ Bazel
- หากต้องการมุ่งเน้นไปที่ C++ ต่อไป โปรดอ่านกรณีการใช้งานทั่วไปของบิลด์ C++
- หากต้องการเริ่มต้นสร้างแอปพลิเคชันอื่นๆ ด้วย Bazel ให้ดูบทแนะนำสำหรับ Java, แอปพลิเคชัน Android หรือแอปพลิเคชัน iOS)
- หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับการทำงานกับที่เก็บในเครื่องและระยะไกล โปรดอ่านเกี่ยวกับทรัพยากร Dependency ภายนอก
- ดูข้อมูลเพิ่มเติมเกี่ยวกับกฎอื่นๆ ของ Bazel ได้ที่คู่มืออ้างอิงนี้
ขอให้สนุกกับการสร้าง