บทแนะนำนี้ครอบคลุมพื้นฐานการสร้างแอปพลิเคชัน Java ด้วย
Bazel คุณจะตั้งค่าพื้นที่ทำงานและสร้างโปรเจ็กต์ Java แบบง่ายๆ ที่
แสดงแนวคิดหลักของ Bazel เช่น เป้าหมายและไฟล์ BUILD
เวลาที่ใช้ดำเนินการจนเสร็จสิ้นโดยประมาณ: 30 นาที
สิ่งที่คุณจะได้เรียนรู้
ในบทแนะนำนี้ คุณจะได้เรียนรู้วิธีต่อไปนี้
- สร้างเป้าหมาย
- แสดงภาพทรัพยากร Dependency ของโปรเจ็กต์
- แบ่งโปรเจ็กต์ออกเป็นหลายเป้าหมายและแพ็กเกจ
- ควบคุมระดับการเข้าถึงเป้าหมายในแพ็กเกจต่างๆ
- อ้างอิงเป้าหมายผ่านป้ายกำกับ
- ทำให้เป้าหมายใช้งานได้
ก่อนเริ่มต้น
ติดตั้ง Bazel
หากต้องการเตรียมพร้อมสําหรับบทแนะนำ ให้ติดตั้ง Bazel ก่อนหาก คุณยังไม่ได้ติดตั้ง
ติดตั้ง JDK
ติดตั้ง Java JDK (เวอร์ชันที่ต้องการคือ 11 แต่รองรับเวอร์ชัน 8 ถึง 15)
ตั้งค่าตัวแปรสภาพแวดล้อม JAVA_HOME ให้ชี้ไปที่ JDK
ใน Linux/macOS:
export JAVA_HOME="$(dirname $(dirname $(realpath $(which javac))))"
บน Windows:
- เปิดแผงควบคุม
- ไปที่ "ระบบและความปลอดภัย" "ระบบ" "การตั้งค่าระบบขั้นสูง" "ขั้นสูง" แท็บ > "ตัวแปรสภาพแวดล้อม..."
- ใต้ "ตัวแปรผู้ใช้" รายการ (รายการด้านบนสุด) ให้คลิก "ใหม่..."
- ใน "ชื่อตัวแปร" ให้ป้อน
JAVA_HOME
- คลิก "เรียกดูไดเรกทอรี..."
- ไปที่ไดเรกทอรี JDK (เช่น
C:\Program Files\Java\jdk1.8.0_152
) - คลิก "ตกลง" ในหน้าต่างกล่องโต้ตอบทั้งหมด
รับโปรเจ็กต์ตัวอย่าง
เรียกข้อมูลโปรเจ็กต์ตัวอย่างจากที่เก็บ GitHub ของ Bazel:
git clone https://github.com/bazelbuild/examples
โปรเจ็กต์ตัวอย่างสำหรับบทแนะนำนี้อยู่ใน examples/java-tutorial
และมีโครงสร้างดังนี้
java-tutorial
├── BUILD
├── src
│ └── main
│ └── java
│ └── com
│ └── example
│ ├── cmdline
│ │ ├── BUILD
│ │ └── Runner.java
│ ├── Greeting.java
│ └── ProjectRunner.java
└── WORKSPACE
สร้างด้วย Bazel
ตั้งค่าพื้นที่ทำงาน
คุณต้องตั้งค่าพื้นที่ทำงานของโปรเจ็กต์ก่อนจึงจะสร้างโปรเจ็กต์ได้ พื้นที่ทำงาน ไดเรกทอรีที่เก็บไฟล์ต้นฉบับของโปรเจ็กต์และเอาต์พุตบิลด์ของ Bazel ทั้งนี้ ยังมีไฟล์ที่ Bazel เห็นว่าพิเศษด้วย ดังนี้
ไฟล์
WORKSPACE
ซึ่งระบุไดเรกทอรีและเนื้อหาในไดเรกทอรีเป็น Bazel Workspace และอยู่ที่รูทของโครงสร้างไดเรกทอรีของโปรเจ็กต์ไฟล์
BUILD
อย่างน้อย 1 ไฟล์ ซึ่งบอก Bazel ถึงวิธีสร้างส่วนต่างๆ ของ ให้กับโครงการ (ไดเรกทอรีภายในพื้นที่ทํางานที่มีไฟล์BUILD
เป็นแพ็กเกจ คุณจะได้เรียนรู้เกี่ยวกับแพ็กเกจภายหลังในบทแนะนำนี้)
หากต้องการกำหนดไดเรกทอรีเป็นพื้นที่ทำงาน Bazel ให้สร้างไฟล์เปล่าชื่อ
WORKSPACE
ในไดเรกทอรีนั้น
เมื่อ Bazel สร้างโปรเจ็กต์ อินพุตและการอ้างอิงทั้งหมดต้องเหมือนกัน Google Workspace ได้อย่างเต็มประสิทธิภาพ ไฟล์ที่อยู่ในพื้นที่ทำงานที่ต่างกันจะแยกออกจากกันเป็น 1 ไฟล์ วิดีโออื่นเว้นแต่จะมีการลิงก์ไว้ ซึ่งเป็นสิ่งที่อยู่นอกเหนือขอบเขตของบทแนะนำนี้
ทำความเข้าใจไฟล์ BUILD
ไฟล์ BUILD
มีวิธีการหลายประเภทสำหรับ Bazel
ประเภทที่สำคัญที่สุดคือกฎการสร้าง ซึ่งบอก Bazel ถึงวิธีสร้าง
เอาต์พุตที่ต้องการ เช่น ไบนารีหรือไลบรารีสั่งการ แต่ละอินสแตนซ์
ของกฎบิลด์ในไฟล์ BUILD
จะเรียกว่าเป้าหมาย และชี้ไปยัง
ชุดของไฟล์ต้นฉบับและทรัพยากร Dependency ที่ระบุ เป้าหมายยังสามารถชี้ไปยัง
เป้าหมาย
ดูไฟล์ java-tutorial/BUILD
:
java_binary(
name = "ProjectRunner",
srcs = glob(["src/main/java/com/example/*.java"]),
)
ในตัวอย่าง เป้าหมาย ProjectRunner
จะสร้างอินสแตนซ์ในตัวของ Bazel
java_binary
กฎ กฎบอก Bazel
สร้างไฟล์ .jar
และสคริปต์ Wrapper ของ Shell (ซึ่งทั้งคู่ตั้งชื่อตามเป้าหมาย)
แอตทริบิวต์ในเป้าหมายระบุทรัพยากร Dependency และตัวเลือกอย่างชัดเจน
แม้ว่าแอตทริบิวต์ name
จะเป็นแอตทริบิวต์ที่บังคับ แต่ก็มีแอตทริบิวต์หลายรายการที่ไม่บังคับ ตัวอย่างเช่น ใน
เป้าหมายกฎ ProjectRunner
, name
คือชื่อของเป้าหมาย, srcs
ระบุ
ไฟล์ต้นฉบับที่ Bazel ใช้ในการสร้างเป้าหมาย และ main_class
ระบุ
ที่มีเมธอดหลัก (คุณอาจสังเกตเห็นว่าตัวอย่างของเรา
ใช้ glob เพื่อส่งชุดไฟล์ต้นฉบับไปยัง Bazel
แทนที่จะแสดงทีละรายการ)
สร้างโปรเจ็กต์
หากต้องการสร้างโปรเจ็กต์ตัวอย่าง ให้ไปที่ไดเรกทอรี java-tutorial
และเรียกใช้
bazel build //:ProjectRunner
ในป้ายกำกับเป้าหมาย ส่วน //
คือตำแหน่งของไฟล์ BUILD
สัมพัทธ์กับรูทของพื้นที่ทำงาน (ในกรณีนี้คือรูทเอง)
และ ProjectRunner
คือชื่อเป้าหมายในไฟล์ BUILD
(คุณจะ
ดูข้อมูลเกี่ยวกับป้ายกำกับเป้าหมายโดยละเอียดยิ่งขึ้นที่ส่วนท้ายของบทแนะนำนี้)
Bazel จะสร้างเอาต์พุตที่คล้ายกับตัวอย่างต่อไปนี้
INFO: Found 1 target...
Target //:ProjectRunner up-to-date:
bazel-bin/ProjectRunner.jar
bazel-bin/ProjectRunner
INFO: Elapsed time: 1.021s, Critical Path: 0.83s
ยินดีด้วย คุณเพิ่งสร้างเป้าหมาย Bazel แรก งานสร้าง Bazel
เอาต์พุตในไดเรกทอรี bazel-bin
ที่รูทของพื้นที่ทำงาน เรียกดู
ผ่านเนื้อหาเพื่อให้ได้แนวคิดสำหรับโครงสร้างเอาต์พุตของ Bazel
ตอนนี้ให้ทดสอบไบนารีที่สร้างใหม่ โดยทำดังนี้
bazel-bin/ProjectRunner
ตรวจสอบกราฟทรัพยากร Dependency
Bazel กำหนดให้ต้องประกาศทรัพยากร Dependency ของบิลด์อย่างชัดเจนในไฟล์ BUILD Bazel จะใช้ข้อความเหล่านั้นเพื่อสร้างกราฟทรัพยากร Dependency ของโครงการ ช่วยให้มีบิลด์เพิ่มขึ้นที่แม่นยำ
คุณสามารถสร้างข้อความเพื่อดูทรัพยากร Dependency ของโปรเจ็กต์ตัวอย่างได้ การแสดงกราฟทรัพยากร Dependency ด้วยการเรียกใช้คำสั่งนี้ที่ รูทของพื้นที่ทำงาน:
bazel query --notool_deps --noimplicit_deps "deps(//:ProjectRunner)" --output graph
คำสั่งด้านบนจะบอกให้ Bazel มองหาทรัพยากร Dependency ทั้งหมดสำหรับเป้าหมาย
//:ProjectRunner
(ยกเว้นทรัพยากร Dependency ของโฮสต์และโดยนัย) และจัดรูปแบบ
เป็นกราฟ
จากนั้นวางข้อความใน GraphViz
คุณจะเห็นได้ว่า โปรเจ็กต์นี้มีเป้าหมายเดียวที่สร้างไฟล์ต้นฉบับ 2 ไฟล์ด้วย ไม่มีการอ้างอิงเพิ่มเติม:
หลังจากตั้งค่าพื้นที่ทำงานแล้ว ให้สร้างโปรเจ็กต์และตรวจสอบ ทรัพยากร Dependency เพิ่มเติม คุณก็จะเพิ่มความซับซ้อนได้
ปรับแต่งงานสร้าง Bazel
แม้ว่าเป้าหมายเดียวจะเพียงพอแล้วสำหรับโปรเจ็กต์ขนาดเล็ก แต่คุณอาจต้องการแยกเป้าหมาย ทำโครงการใหญ่ๆ เป็นเป้าหมายและแพ็กเกจที่หลากหลาย เพื่อให้เพิ่มความเร็ว (กล่าวคือ สร้างเฉพาะสิ่งที่เปลี่ยนแปลงไปเท่านั้น) และทำให้การสร้างของคุณเร็วขึ้นโดย ในการสร้างส่วนต่างๆ ของโครงการได้พร้อมกัน
ระบุเป้าหมายของบิลด์หลายรายการ
คุณแบ่งโปรเจ็กต์ตัวอย่างที่สร้างออกเป็น 2 เป้าหมายได้ แทนที่เนื้อหาของ
ไฟล์ java-tutorial/BUILD
ที่มีข้อมูลดังต่อไปนี้
java_binary(
name = "ProjectRunner",
srcs = ["src/main/java/com/example/ProjectRunner.java"],
main_class = "com.example.ProjectRunner",
deps = [":greeter"],
)
java_library(
name = "greeter",
srcs = ["src/main/java/com/example/Greeting.java"],
)
ด้วยการกำหนดค่านี้ Bazel จะสร้างไลบรารี greeter
ก่อน จากนั้น
เลขฐานสอง ProjectRunner
แอตทริบิวต์ deps
ใน java_binary
บอก Bazel ว่า
ต้องมีไลบรารี greeter
เพื่อสร้างไบนารี ProjectRunner
หากต้องการสร้างโปรเจ็กต์เวอร์ชันใหม่นี้ ให้เรียกใช้คำสั่งต่อไปนี้
bazel build //:ProjectRunner
Bazel จะสร้างเอาต์พุตที่คล้ายกับตัวอย่างต่อไปนี้
INFO: Found 1 target...
Target //:ProjectRunner up-to-date:
bazel-bin/ProjectRunner.jar
bazel-bin/ProjectRunner
INFO: Elapsed time: 2.454s, Critical Path: 1.58s
ตอนนี้ให้ทดสอบไบนารีที่สร้างใหม่ โดยทำดังนี้
bazel-bin/ProjectRunner
หากตอนนี้คุณแก้ไข ProjectRunner.java
และสร้างโปรเจ็กต์ใหม่ Bazel เท่านั้น
คอมไพล์ไฟล์นั้นซ้ำ
เมื่อดูกราฟทรัพยากร Dependency แล้ว คุณจะเห็นได้ว่า ProjectRunner
ขึ้นอยู่กับ
ป้อนข้อมูลเหมือนเดิม แต่โครงสร้างของบิลด์จะแตกต่างออกไป
ตอนนี้คุณได้สร้างโปรเจ็กต์ที่มีเป้าหมาย 2 รายการแล้ว บิลด์ ProjectRunner
เป้าหมาย
ไฟล์ต้นฉบับ 2 ไฟล์และขึ้นอยู่กับเป้าหมายอื่นอีก 1 รายการ (:greeter
) ซึ่งสร้าง
ไฟล์ต้นฉบับเพิ่มเติมอีก 1 ไฟล์
ใช้หลายแพ็กเกจ
ตอนนี้เราจะมาแบ่งโปรเจ็กต์ออกเป็นหลายๆ แพ็กเกจ หากคุณดูที่
src/main/java/com/example/cmdline
คุณจะเห็นว่ามี
ไฟล์ BUILD
และอีกไฟล์ต้นฉบับบางไฟล์ ดังนั้น สำหรับ Bazel พื้นที่ทำงาน
มี 2 แพ็กเกจคือ //src/main/java/com/example/cmdline
และ //
(ตั้งแต่
มีไฟล์ BUILD
อยู่ที่รูทของพื้นที่ทำงาน)
ดูไฟล์ src/main/java/com/example/cmdline/BUILD
:
java_binary(
name = "runner",
srcs = ["Runner.java"],
main_class = "com.example.cmdline.Runner",
deps = ["//:greeter"],
)
เป้าหมาย runner
ขึ้นอยู่กับเป้าหมาย greeter
ในแพ็กเกจ //
(ดังนั้น
ป้ายกำกับเป้าหมาย //:greeter
) - Bazel ทราบเรื่องนี้ผ่านแอตทริบิวต์ deps
ลองดูกราฟทรัพยากร Dependency ต่อไปนี้
อย่างไรก็ตาม คุณต้องให้เป้าหมาย runner
อย่างชัดเจนเพื่อให้บิลด์ประสบความสำเร็จ
การแสดงผล //src/main/java/com/example/cmdline/BUILD
เป้าหมายไปยังเป้าหมายใน
//BUILD
ที่ใช้แอตทริบิวต์ visibility
เนื่องจากโดยค่าเริ่มต้น
จะแสดงให้เป้าหมายอื่นในไฟล์ BUILD
เดียวกันเท่านั้น (Bazel ใช้เป้าหมาย
การมองเห็นเพื่อป้องกันปัญหาต่างๆ เช่น ไลบรารีที่มีรายละเอียดการใช้งาน
รั่วไหลไปยัง API สาธารณะ)
โดยเพิ่มแอตทริบิวต์ visibility
ลงในเป้าหมาย greeter
ใน
java-tutorial/BUILD
ตามที่แสดงด้านล่าง:
java_library(
name = "greeter",
srcs = ["src/main/java/com/example/Greeting.java"],
visibility = ["//src/main/java/com/example/cmdline:__pkg__"],
)
ตอนนี้คุณสามารถสร้างแพ็กเกจใหม่โดยเรียกใช้คำสั่งต่อไปนี้ที่รูท ในพื้นที่ทำงาน
bazel build //src/main/java/com/example/cmdline:runner
Bazel จะสร้างเอาต์พุตที่คล้ายกับตัวอย่างต่อไปนี้
INFO: Found 1 target...
Target //src/main/java/com/example/cmdline:runner up-to-date:
bazel-bin/src/main/java/com/example/cmdline/runner.jar
bazel-bin/src/main/java/com/example/cmdline/runner
INFO: Elapsed time: 1.576s, Critical Path: 0.81s
ตอนนี้ให้ทดสอบไบนารีที่สร้างใหม่ โดยทำดังนี้
./bazel-bin/src/main/java/com/example/cmdline/runner
ตอนนี้คุณแก้ไขโปรเจ็กต์เพื่อสร้างเป็น 2 แพ็กเกจแล้ว โดยแต่ละแพ็กเกจจะมี 1 แพ็กเกจ กำหนดเป้าหมายและทำความเข้าใจการพึ่งพากันระหว่างกัน
ใช้ป้ายกำกับเพื่ออ้างอิงเป้าหมาย
ในไฟล์ BUILD
และที่บรรทัดคำสั่ง Bazel จะใช้ป้ายกำกับเป้าหมายในการอ้างอิง
เป้าหมาย - ตัวอย่างเช่น //:ProjectRunner
หรือ
//src/main/java/com/example/cmdline:runner
ไวยากรณ์มีดังนี้
//path/to/package:target-name
หากเป้าหมายเป็นเป้าหมายของกฎ path/to/package
จะเป็นเส้นทางไปยัง
ที่มีไฟล์ BUILD
และ target-name
คือชื่อที่คุณตั้งชื่อ
เป้าหมายในไฟล์ BUILD
(แอตทริบิวต์ name
) หากเป้าหมายเป็นไฟล์
เป้าหมายแล้ว path/to/package
คือเส้นทางไปยังรากของแพ็กเกจ และ
target-name
คือชื่อไฟล์เป้าหมาย รวมถึงเส้นทางแบบเต็ม
เมื่ออ้างอิงเป้าหมายที่รูทของที่เก็บ เส้นทางแพ็กเกจจะว่างเปล่า
เพียงใช้ //:target-name
เมื่ออ้างอิงเป้าหมายภายใน BUILD
เดียวกัน
คุณสามารถข้ามตัวระบุรูทของพื้นที่ทำงาน //
และใช้
:target-name
ตัวอย่างเช่น สำหรับเป้าหมายในไฟล์ java-tutorial/BUILD
คุณไม่จำเป็นต้อง
ระบุเส้นทางแพ็กเกจ เนื่องจากรูทของพื้นที่ทำงานเป็นแพ็กเกจ (//
) และ
ป้ายกำกับเป้าหมาย 2 รายการของคุณคือ //:ProjectRunner
และ //:greeter
อย่างไรก็ตาม สำหรับเป้าหมายในไฟล์ //src/main/java/com/example/cmdline/BUILD
คุณจะ
ต้องระบุเส้นทางแพ็กเกจแบบเต็มของ //src/main/java/com/example/cmdline
และป้ายกำกับเป้าหมายของคุณคือ //src/main/java/com/example/cmdline:runner
สร้างแพ็กเกจเป้าหมาย Java สำหรับการทำให้ใช้งานได้
ตอนนี้เรามาทำแพ็กเกจเป้าหมาย Java สำหรับการทำให้ใช้งานได้ด้วยการสร้างไบนารีที่มี ของทรัพยากร Dependency รันไทม์ ซึ่งจะทำให้คุณสามารถเรียกใช้ไบนารีนอก สภาพแวดล้อมในการพัฒนาซอฟต์แวร์
คุณอาจจำได้ว่ากฎของบิลด์ java_binary
สร้าง .jar
และสคริปต์ Shell Wrapper ดูเนื้อหาของ
runner.jar
โดยใช้คำสั่งนี้
jar tf bazel-bin/src/main/java/com/example/cmdline/runner.jar
คอนเทนต์มีดังนี้
META-INF/
META-INF/MANIFEST.MF
com/
com/example/
com/example/cmdline/
com/example/cmdline/Runner.class
คุณจะเห็นว่า runner.jar
มี Runner.class
แต่ไม่มี Dependency
Greeting.class
สคริปต์ runner
ที่ Bazel สร้างจะเพิ่ม greeter.jar
ไปยังคลาสพาธ ดังนั้นหากคุณปล่อยไว้แบบนี้ รายการก็จะทำงานภายใน แต่
จะไม่ทำงานแบบสแตนด์อโลนในเครื่องอื่น โชคดีที่กฎ java_binary
ช่วยให้คุณสร้างไบนารีแบบ
ในตัวที่นำไปใช้ได้ ต่อท้ายด้วย
_deploy.jar
เป็นชื่อเป้าหมาย:
bazel build //src/main/java/com/example/cmdline:runner_deploy.jar
Bazel จะสร้างเอาต์พุตที่คล้ายกับตัวอย่างต่อไปนี้
INFO: Found 1 target...
Target //src/main/java/com/example/cmdline:runner_deploy.jar up-to-date:
bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar
INFO: Elapsed time: 1.700s, Critical Path: 0.23s
คุณเพิ่งสร้าง runner_deploy.jar
ซึ่งคุณสามารถใช้แบบสแตนด์อโลนได้
สภาพแวดล้อมในการพัฒนาซอฟต์แวร์ของคุณเนื่องจากมีรันไทม์ที่จำเป็น
ทรัพยากร Dependency ดูเนื้อหาของ JAR แบบสแตนด์อโลนนี้โดยใช้
คำสั่งเดียวกับก่อนหน้านี้
jar tf bazel-bin/src/main/java/com/example/cmdline/runner_deploy.jar
เนื้อหาจะมีคลาสทั้งหมดที่จำเป็นต่อการเรียกใช้ ดังนี้
META-INF/
META-INF/MANIFEST.MF
build-data.properties
com/
com/example/
com/example/cmdline/
com/example/cmdline/Runner.class
com/example/Greeting.class
อ่านเพิ่มเติม
โปรดดูรายละเอียดเพิ่มเติมที่หัวข้อต่อไปนี้
rules_jvm_external สำหรับ สำหรับจัดการทรัพยากร Dependency ของ Maven แบบทรานซิทีฟ
ทรัพยากร Dependency ภายนอก เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับการทํางานด้วย ที่เก็บในเครื่องและระยะไกล
กฎอื่นๆ เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับ Bazel
บทแนะนำบิลด์ C++ เพื่อเริ่มต้นใช้งานการสร้าง ทำโปรเจ็กต์ C++ ด้วย Bazel
บทแนะนำแอปพลิเคชัน Android และ บทแนะนำแอปพลิเคชัน iOS เพื่อเริ่มต้นใช้งาน การสร้างแอปพลิเคชันบนอุปกรณ์เคลื่อนที่สำหรับ Android และ iOS ด้วย Bazel
ขอให้สนุกกับการสร้าง