ชวาและบาเซล

รายงานปัญหา ดูแหล่งที่มา

หน้านี้มีทรัพยากรที่ช่วยให้คุณใช้ Bazel กับโปรเจ็กต์ Java ซึ่งจะลิงก์ไปยังบทแนะนำ การสร้างกฎ และข้อมูลอื่นๆ ที่เกี่ยวข้องกับการสร้างโปรเจ็กต์ Java ด้วย Bazel โดยเฉพาะ

การทำงานร่วมกับ Bazel

ทรัพยากรต่อไปนี้จะช่วยคุณในการทำงานร่วมกับ Bazel ในโปรเจ็กต์ Java

การย้ายข้อมูลไปยัง Bazel

หากคุณสร้างโปรเจ็กต์ Java ด้วย Maven อยู่ ให้ทําตามขั้นตอนในคู่มือการย้ายข้อมูลเพื่อเริ่มสร้างโปรเจ็กต์ Maven ด้วย Bazel

เวอร์ชัน Java

มี Java ที่เกี่ยวข้อง 2 เวอร์ชันที่ตั้งค่าไว้ด้วยแฟล็กการกำหนดค่า ดังนี้

  • เวอร์ชันของไฟล์ต้นฉบับในที่เก็บ
  • เวอร์ชันของรันไทม์ Java ที่ใช้เพื่อเรียกใช้โค้ดและทดสอบ

การกำหนดค่าเวอร์ชันของซอร์สโค้ดในที่เก็บ

หากไม่มีการกำหนดค่าเพิ่มเติม Bazel จะถือว่าไฟล์ต้นฉบับ Java ทั้งหมดในที่เก็บเขียนขึ้นใน Java เวอร์ชันเดียว หากต้องการระบุเวอร์ชันของแหล่งที่มาในที่เก็บ ให้เพิ่ม build --java_language_version={ver} ลงในไฟล์ .bazelrc โดยที่ {ver} คือ 11 เจ้าของที่เก็บ Bazel ควรตั้งค่า Flag นี้เพื่อให้ Bazel และผู้ใช้อ้างอิงหมายเลขเวอร์ชันของ Java ได้ ดูรายละเอียดเพิ่มเติมได้ที่แฟล็กเวอร์ชันภาษา Java

การกำหนดค่า JVM ที่ใช้เพื่อเรียกใช้และทดสอบโค้ด

Bazel ใช้ JDK 1 รายการสำหรับการคอมไพล์และอีก JVM เพื่อเรียกใช้และทดสอบโค้ด

โดยค่าเริ่มต้น Bazel คอมไพล์โค้ดโดยใช้ JDK ที่โค้ดดาวน์โหลดจะประมวลผลและทดสอบโค้ดด้วย JVM ที่ติดตั้งในเครื่อง Bazel ค้นหา JVM โดยใช้ JAVA_HOME หรือเส้นทาง

ไบนารีที่ได้จะเข้ากันได้กับ JVM ที่ติดตั้งในเครื่องในไลบรารีระบบ ซึ่งหมายความว่าไบนารีที่ได้จะขึ้นอยู่กับสิ่งที่ติดตั้งบนเครื่อง

หากต้องการกำหนดค่า JVM ที่ใช้สำหรับการดำเนินการและทดสอบ ให้ใช้แฟล็ก --java_runtime_version ค่าเริ่มต้นคือ local_jdk

การทดสอบและการรวบรวมตัวอย่าง

หากต้องการสร้างคอมไพล์แบบ Hermetic ให้ใช้แฟล็กบรรทัดคำสั่ง --java_runtime_version=remotejdk_11 โค้ดจะได้รับการคอมไพล์ เรียกใช้งาน และทดสอบใน JVM ที่ดาวน์โหลดจากที่เก็บระยะไกล ดูรายละเอียดเพิ่มเติมได้ที่แฟล็กเวอร์ชันรันไทม์ของ Java

การกำหนดค่าการคอมไพล์และการดำเนินการของเครื่องมือบิลด์ใน Java

มีการใช้ JDK และ JVM คู่ที่ 2 เพื่อสร้างและเรียกใช้เครื่องมือ ซึ่งใช้ในกระบวนการบิลด์ แต่ไม่ได้อยู่ในผลลัพธ์ของบิลด์ JDK และ JVM นี้ควบคุมโดยใช้ --tool_java_language_version และ --tool_java_runtime_version ค่าเริ่มต้นคือ 11 และ remotejdk_11 ตามลำดับ

การคอมไพล์โดยใช้ JDK ที่ติดตั้งในเครื่อง

Bazel คอมไพล์โดยใช้ JDK ระยะไกลโดยค่าเริ่มต้นเนื่องจากจะลบล้างข้อมูลภายในของ JDK เชนเครื่องมือการคอมไพล์ที่ใช้ JDK ที่ติดตั้งในเครื่องจะได้รับการกำหนดค่าแม้ว่าจะไม่ได้ใช้งาน

หากต้องการคอมไพล์โดยใช้ JDK ที่ติดตั้งในเครื่อง กล่าวคือใช้เครื่องมือการคอมไพล์สำหรับ JDK ในพื้นที่ ให้ใช้ Flag --extra_toolchains=@local_jdk//:all เพิ่มเติม แต่โปรดทราบว่าตัวเลือกนี้อาจใช้ไม่ได้กับ JDK ของผู้ให้บริการที่กำหนดเอง

ดูรายละเอียดเพิ่มเติมได้ที่การกำหนดค่าห่วงโซ่เครื่องมือ Java

แนวทางปฏิบัติแนะนำ

นอกเหนือจากแนวทางปฏิบัติแนะนำทั่วไปของ Bazel แล้ว ด้านล่างนี้คือแนวทางปฏิบัติแนะนำสำหรับโปรเจ็กต์ Java โดยเฉพาะ

โครงสร้างไดเรกทอรี

เลือกใช้เลย์เอาต์ไดเรกทอรีมาตรฐานของ Maven (แหล่งที่มาภายใต้ src/main/java การทดสอบภายใต้ src/test/java)

ไฟล์ BUILD

ทำตามหลักเกณฑ์ต่อไปนี้เมื่อสร้างไฟล์ BUILD

  • ใช้ไฟล์ BUILD 1 ไฟล์ต่อไดเรกทอรีที่มีซอร์สของ Java เพราะจะช่วยปรับปรุงประสิทธิภาพของบิลด์

  • ทุกไฟล์ BUILD ควรมีกฎ java_library 1 ข้อที่มีลักษณะดังนี้

    java_library(
        name = "directory-name",
        srcs = glob(["*.java"]),
        deps = [...],
    )
    
  • ชื่อของไลบรารีควรเป็นชื่อของไดเรกทอรีที่มีไฟล์ BUILD ซึ่งจะทำให้ป้ายกำกับของไลบรารีสั้นลง โดยใช้ "//package" แทน "//package:package"

  • แหล่งที่มาควรเป็น glob แบบไม่ซ้ำของไฟล์ Java ทั้งหมดในไดเรกทอรี

  • การทดสอบควรอยู่ในไดเรกทอรีที่ตรงกันภายใต้ src/test และขึ้นอยู่กับไลบรารีนี้

การสร้างกฎใหม่สำหรับบิลด์ Java ขั้นสูง

หมายเหตุ: การสร้างกฎใหม่มีไว้สําหรับสถานการณ์บิลด์และการทดสอบขั้นสูง คุณไม่จำเป็นต้องใช้เมื่อเริ่มต้นใช้งาน Bazel

โมดูล Fragment การกำหนดค่า และผู้ให้บริการต่อไปนี้จะช่วยคุณขยายความสามารถของ Bazel เมื่อสร้างโปรเจ็กต์ Java

การกำหนดค่าเชนเครื่องมือ Java

Bazel ใช้ห่วงโซ่เครื่องมือของ Java 2 ประเภท ได้แก่ - การดำเนินการ ใช้เพื่อเรียกใช้และทดสอบไบนารีของ Java ควบคุมด้วยแฟล็ก --java_runtime_version - การคอมไพล์ ใช้ในการคอมไพล์แหล่งที่มาของ Java ควบคุมด้วยแฟล็ก --java_language_version

การกำหนดค่าเชนเครื่องมือการดำเนินการเพิ่มเติม

เชนเครื่องมือการดำเนินการคือ JVM ไม่ว่าจะใช้ในเครื่องหรือจากที่เก็บ พร้อมข้อมูลเพิ่มเติมบางส่วนเกี่ยวกับเวอร์ชัน ระบบปฏิบัติการ และสถาปัตยกรรม CPU

อาจเพิ่มเชนเครื่องมือการดำเนินการของ Java โดยใช้กฎ local_java_repository หรือ remote_java_repository ในไฟล์ WORKSPACE การเพิ่มกฎทำให้ JVM พร้อมใช้งานโดยใช้แฟล็ก เมื่อกำหนดคำจำกัดความหลายรายการสำหรับระบบปฏิบัติการและสถาปัตยกรรม CPU เดียวกัน ระบบจะใช้คำแรก

ตัวอย่างการกำหนดค่าของ JVM ในเครื่อง

load("@bazel_tools//tools/jdk:local_java_repository.bzl", "local_java_repository")

local_java_repository(
  name = "additionaljdk",          # Can be used with --java_runtime_version=additionaljdk, --java_runtime_version=11 or --java_runtime_version=additionaljdk_11
  version = 11,                    # Optional, if not set it is autodetected
  java_home = "/usr/lib/jdk-15/",  # Path to directory containing bin/java
)

ตัวอย่างการกำหนดค่าของ JVM ระยะไกล

load("@bazel_tools//tools/jdk:remote_java_repository.bzl", "remote_java_repository")

remote_java_repository(
  name = "openjdk_canary_linux_arm",
  prefix = "openjdk_canary", # Can be used with --java_runtime_version=openjdk_canary_11
  version = "11",            # or --java_runtime_version=11
  target_compatible_with = [ # Specifies constraints this JVM is compatible with
    "@platforms//cpu:arm",
    "@platforms//os:linux",
  ],
  urls = ...,               # Other parameters are from http_repository rule.
  sha256 = ...,
  strip_prefix = ...
)

การกำหนดค่าเชนเครื่องมือการคอมไพล์เพิ่มเติม

เชนเครื่องมือการคอมไพล์ประกอบด้วย JDK และเครื่องมือมากมายที่ Bazel ใช้ระหว่างการคอมไพล์และมีฟีเจอร์เพิ่มเติม เช่น ข้อผิดพลาด แนวโน้ม, การพึ่งพา Java ที่เข้มงวด การคอมไพล์ส่วนหัว, การเพิ่มน้ำตาลของ Android, การวัดคุมการครอบคลุม และการจัดการ Genclass สำหรับ IDE

JavaBuilder เป็นเครื่องมือที่นำมารวมเป็นชุดของ Bazel ที่ดำเนินการคอมไพล์ และยังมีฟีเจอร์ที่กล่าวถึงข้างต้น การคอมไพล์จริงจะดำเนินการโดยใช้คอมไพเลอร์ภายในโดย JDK JDK ที่ใช้ในการคอมไพล์จะระบุโดยแอตทริบิวต์ java_runtime ของ Toolchain

Bazel ลบล้างข้อมูลภายในของ JDK บางส่วน ในกรณีของ JDK เวอร์ชัน > 9 จะมีการแพตช์โมดูล java.compiler และ jdk.compiler โดยใช้แฟล็กของ JDK --patch_module ในกรณีของ JDK เวอร์ชัน 8 คอมไพเลอร์ Java จะถูกแพตช์โดยใช้แฟล็ก -Xbootclasspath

VanillaJavaBuilder เป็นการใช้งาน JavaBuilder แบบที่ 2 ซึ่งไม่ได้แก้ไขคอมไพเลอร์ภายในของ JDK และไม่มีฟีเจอร์เพิ่มเติมใดๆ Toolchain ในตัวไม่ได้ใช้ VanillaJavaBuilder เลย

นอกเหนือจาก JavaBuilder แล้ว Bazel ยังใช้เครื่องมืออื่นๆ อีกหลายอย่างระหว่างการคอมไพล์

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

เครื่องมือ singlejar จะรวมไฟล์ jar หลายๆ ไฟล์ไว้ในที่เดียว

เครื่องมือ genclass จะประมวลผลเอาต์พุตของการคอมไพล์ Java และสร้าง jar ที่มีเฉพาะไฟล์คลาสสำหรับแหล่งที่มาที่สร้างโดยตัวประมวลผลคำอธิบายประกอบ

เครื่องมือ JacocoRunner จะเรียกใช้ Jacoco ผ่านไฟล์และเอาต์พุตที่มีการวัดคุมซึ่งแสดงผลลัพธ์ในรูปแบบ LCOV

เครื่องมือ TestRunner จะทำการทดสอบ JUnit 4 ในสภาพแวดล้อมที่มีการควบคุม

คุณกำหนดค่าการคอมไพล์อีกครั้งได้โดยการเพิ่มมาโคร default_java_toolchain ลงในไฟล์ BUILD และลงทะเบียนไฟล์ดังกล่าวด้วยการเพิ่มกฎ register_toolchains ลงในไฟล์ WORKSPACE หรือใช้แฟล็ก --extra_toolchains

Toolchain จะใช้เมื่อแอตทริบิวต์ source_version ตรงกับค่าที่แฟล็ก --java_language_version ระบุไว้เท่านั้น

ตัวอย่างการกำหนดค่า Toolchain

load(
  "@bazel_tools//tools/jdk:default_java_toolchain.bzl",
  "default_java_toolchain", "DEFAULT_TOOLCHAIN_CONFIGURATION", "BASE_JDK9_JVM_OPTS", "DEFAULT_JAVACOPTS"
)

default_java_toolchain(
  name = "repository_default_toolchain",
  configuration = DEFAULT_TOOLCHAIN_CONFIGURATION,        # One of predefined configurations
                                                          # Other parameters are from java_toolchain rule:
  java_runtime = "@bazel_tools//tools/jdk:remote_jdk11", # JDK to use for compilation and toolchain's tools execution
  jvm_opts = BASE_JDK9_JVM_OPTS + ["--enable_preview"],   # Additional JDK options
  javacopts = DEFAULT_JAVACOPTS + ["--enable_preview"],   # Additional javac options
  source_version = "9",
)

ซึ่งสามารถใช้โดยใช้ --extra_toolchains=//:repository_default_toolchain_definition หรือด้วยการเพิ่ม register_toolchains("//:repository_default_toolchain_definition") ลงในพื้นที่ทำงานก็ได้

การกำหนดค่าที่กำหนดไว้ล่วงหน้า

  • DEFAULT_TOOLCHAIN_CONFIGURATION: ฟีเจอร์ทั้งหมด รองรับ JDK เวอร์ชัน >= 9
  • VANILLA_TOOLCHAIN_CONFIGURATION: ไม่มีฟีเจอร์เพิ่มเติม แต่รองรับ JDK ของผู้ให้บริการที่กำหนดเอง
  • PREBUILT_TOOLCHAIN_CONFIGURATION: เหมือนกับค่าเริ่มต้น แต่ใช้เฉพาะเครื่องมือที่สร้างไว้ล่วงหน้า (ijar, singlejar)
  • NONPREBUILT_TOOLCHAIN_CONFIGURATION: เหมือนกับค่าเริ่มต้น แต่เครื่องมือทั้งหมดสร้างขึ้นจากแหล่งที่มา (ซึ่งอาจเป็นประโยชน์ในระบบปฏิบัติการที่มี libc อื่น)

การกำหนดค่าแฟล็ก JVM และคอมไพเลอร์ Java

คุณกำหนดค่าแฟล็ก JVM และ JavaScript ด้วยแฟล็กหรือแอตทริบิวต์ default_java_toolchain ได้

แฟล็กที่เกี่ยวข้องคือ --jvmopt, --host_jvmopt, --javacopt และ --host_javacopt

แอตทริบิวต์ default_java_toolchain ที่เกี่ยวข้องคือ javacopts, jvm_opts, javabuilder_jvm_opts และ turbine_jvm_opts

การกำหนดค่าแฟล็กคอมไพเลอร์ Java ที่เจาะจงแพ็กเกจ

คุณกำหนดค่าแฟล็กของคอมไพเลอร์ Java สำหรับไฟล์ต้นฉบับที่เฉพาะเจาะจงได้โดยใช้แอตทริบิวต์ package_configuration ของ default_java_toolchain โปรดดูตัวอย่างด้านล่าง

load("@bazel_tools//tools/jdk:default_java_toolchain.bzl", "default_java_toolchain")

# This is a convenience macro that inherits values from Bazel's default java_toolchain
default_java_toolchain(
    name = "toolchain",
    package_configuration = [
        ":error_prone",
    ],
    visibility = ["//visibility:public"],
)

# This associates a set of javac flags with a set of packages
java_package_configuration(
    name = "error_prone",
    javacopts = [
        "-Xep:MissingOverride:ERROR",
    ],
    packages = ["error_prone_packages"],
)

# This is a regular package_group, which is used to specify a set of packages to apply flags to
package_group(
    name = "error_prone_packages",
    packages = [
        "//foo/...",
        "-//foo/bar/...", # this is an exclusion
    ],
)

ซอร์สโค้ดของ Java หลายเวอร์ชันในที่เก็บเดียว

Bazel รองรับการคอมไพล์แหล่งที่มาของ Java เวอร์ชันเดียวเท่านั้นในบิวด์ ซึ่งหมายความว่าเมื่อสร้างการทดสอบ Java หรือแอปพลิเคชัน ระบบจะสร้างทรัพยากร Dependency ทั้งหมดโดยเทียบกับ Java เวอร์ชันเดียวกัน

อย่างไรก็ตาม บิลด์แยกต่างหากอาจดำเนินการโดยใช้แฟล็กที่ต่างกันได้

หากต้องการให้การใช้แฟล็กต่างๆ ง่ายขึ้น คุณอาจจัดกลุ่มชุดแฟล็กสำหรับเวอร์ชันที่เจาะจงด้วยการกำหนดค่า .bazelrc ได้ดังนี้

build:java8 --java_language_version=8
build:java8 --java_runtime_version=local_jdk_8
build:java11 --java_language_version=11
build:java11 --java_runtime_version=remotejdk_11

การกำหนดค่าเหล่านี้ใช้กับแฟล็ก --config ได้ เช่น bazel test --config=java11 //:java11_test