이 가이드에서는 Java 애플리케이션을 빌드하는 데 필요한 기본 사항을
Bazel을 사용하세요. 작업공간을 설정하고 Google Cloud 콘솔에서
대상 및 BUILD
파일과 같은 주요 Bazel 개념을 보여줍니다.
예상 완료 시간: 30분
학습할 내용
이 튜토리얼에서는 다음 방법을 알아봅니다.
- 대상 빌드
- 프로젝트의 종속 항목 시각화
- 프로젝트를 여러 대상과 패키지로 분할
- 패키지 전반의 대상 가시성 제어
- 라벨을 통해 대상 참조
- 대상 배포
시작하기 전에
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
)로 이동합니다. - '확인'을 클릭합니다. 를 클릭합니다.
샘플 프로젝트 가져오기
Bazel의 GitHub 저장소에서 샘플 프로젝트를 가져옵니다.
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 작업공간이며 프로젝트 디렉터리 구조의 루트에 상주합니다.하나 이상의
BUILD
파일: Bazel에게 프로젝트입니다 (BUILD
파일이 포함된 작업공간 내의 디렉터리) 은 패키지입니다. 패키지에 대해서는 이 튜토리얼의 뒷부분에서 알아봅니다.)
디렉터리를 Bazel 작업공간으로 지정하려면 이름이 지정된 빈 파일을 만듭니다.
WORKSPACE
를 찾습니다.
Bazel이 프로젝트를 빌드할 때 모든 입력과 종속 항목이 동일해야 합니다. 살펴보겠습니다 여러 작업공간에 있는 파일이 하나의 작업공간에 독립적임 이 튜토리얼의 범위를 벗어납니다.
BUILD 파일 이해
BUILD
파일에는 Bazel에 관한 여러 유형의 안내가 포함되어 있습니다.
가장 중요한 유형은 빌드 규칙으로, Bazel에
원하는 출력을 생성합니다. 각 인스턴스
BUILD
파일에 있는 빌드 규칙의 대상은 대상이라고 하며
소스 파일 및 종속 항목 집합을 포함합니다. 또한 타겟은 다른
있습니다
java-tutorial/BUILD
파일을 살펴봅니다.
java_binary(
name = "ProjectRunner",
srcs = glob(["src/main/java/com/example/*.java"]),
)
이 예에서 ProjectRunner
대상은 Bazel의 기본 제공
규칙 java_binary
개. 규칙은 Bazel에게
.jar
파일과 래퍼 셸 스크립트를 빌드합니다 (둘 다 타겟에 따라 이름이 지정됨).
타겟의 속성은 종속 항목과 옵션을 명시적으로 명시합니다.
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
종속 항목 그래프 검토
Bazel을 사용하려면 BUILD 파일에서 빌드 종속 항목을 명시적으로 선언해야 합니다. Bazel은 이러한 문을 사용하여 프로젝트의 종속 항목 그래프를 만듭니다. 정확한 증분 빌드를 지원합니다
샘플 프로젝트의 종속 항목을 시각화하려면 종속 항목 그래프 표현을 작업공간 루트:
bazel query --notool_deps --noimplicit_deps "deps(//:ProjectRunner)" --output graph
위의 명령어는 Bazel에게 대상의 모든 종속 항목을 찾도록 지시합니다.
//:ProjectRunner
(호스트 및 암시적 종속 항목 제외)하고 형식을 지정합니다.
출력됩니다.
그런 다음 텍스트를 GraphViz에 붙여넣습니다.
보시다시피 프로젝트에는 추가 종속 항목이 없습니다.
작업공간을 설정한 후 프로젝트를 빌드하고 복잡성을 더할 수 있습니다.
Bazel 빌드 미세 조정
소규모 프로젝트는 단일 대상으로 충분하지만 대규모 프로젝트를 여러 대상 및 패키지로 분할하여 빌드 (변경된 사항만 재빌드)하고 빌드 속도를 높이려면 빌드가 필요하지 않습니다
여러 빌드 대상 지정
샘플 프로젝트 빌드를 두 개의 대상으로 분할할 수 있습니다. 이
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
바이너리 java_binary
의 deps
속성은 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만 적용됩니다.
다시 컴파일합니다
종속 항목 그래프를 보면 ProjectRunner
가
입력은 동일하지만 빌드의 구조가 다릅니다.
이제 두 개의 대상을 사용하여 프로젝트를 빌드했습니다. ProjectRunner
타겟 빌드
2개의 소스 파일이며, 다른 타겟 (:greeter
)에 종속되어
추가 소스 파일 1개가 포함됩니다.
여러 패키지 사용
이제 프로젝트를 여러 패키지로 분할해 보겠습니다. 이
src/main/java/com/example/cmdline
디렉터리에 들어가면
BUILD
파일 및 일부 소스 파일 따라서 이제 Bazel에게 작업공간은
포함된 두 패키지 (//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
속성을 통해 이를 알고 있습니다.
종속 항목 그래프를 살펴보세요.
그러나 빌드에 성공하려면 runner
타겟을 명시적으로 제공해야 합니다.
//src/main/java/com/example/cmdline/BUILD
의 타겟에 대한 가시성
visibility
속성을 사용하여 //BUILD
. 이는 기본적으로
동일한 BUILD
파일에 있는 다른 타겟에만 표시됩니다. (Bazel은 대상
구현 세부정보가 포함된 라이브러리와 같은 문제를 방지하기 위한 가시성
발생할 수 있습니다.)
이렇게 하려면 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
이제 프로젝트를 수정하여 각각 하나씩 포함된 두 개의 패키지로 빌드했습니다. 이들 간의 종속 항목을 이해할 수 있습니다.
라벨을 사용하여 타겟 참조
Bazel은 BUILD
파일과 명령줄에서 대상 라벨을 사용하여 참조
타겟(예: //:ProjectRunner
또는
//src/main/java/com/example/cmdline:runner
입니다. 문법은 다음과 같습니다.
//path/to/package:target-name
대상이 규칙 대상인 경우 path/to/package
는
BUILD
파일이 포함된 디렉터리이며 target-name
은
BUILD
파일의 타겟 (name
속성) 타겟이 파일인 경우
target인 경우 path/to/package
는 패키지의 루트 경로입니다.
target-name
은 전체 경로를 포함한 대상 파일의 이름입니다.
저장소 루트에서 대상을 참조할 때 패키지 경로가 비어 있습니다.
//:target-name
를 사용하면 됩니다. 동일한 BUILD
내에서 타겟을 참조하는 경우
파일의 경우 //
작업공간 루트 식별자를 건너뛰고
:target-name
입니다.
예를 들어 java-tutorial/BUILD
파일에 있는 대상의 경우
작업공간 루트 자체가 패키지 (//
)이므로 패키지 경로를 지정합니다.
두 개의 타겟 라벨은 단순히 //:ProjectRunner
와 //:greeter
였습니다.
그러나 //src/main/java/com/example/cmdline/BUILD
파일에 있는 대상의 경우
//src/main/java/com/example/cmdline
의 전체 패키지 경로를 지정해야 함
타겟 라벨은 //src/main/java/com/example/cmdline:runner
입니다.
배포할 Java 타겟 패키징
이제 배포를 위한 Java 타겟을 패키징해 보겠습니다. kube-APIserver입니다 이렇게 하면 개발 환경입니다.
java_binary 빌드 규칙은
.jar
및 래퍼 셸 스크립트를 생성합니다. 자세한 내용은
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
가 포함되어 있지만 종속 항목은 포함되어 있지 않습니다.
Greeting.class
입니다. Bazel이 생성하는 runner
스크립트는 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
를 빌드했습니다. 이는 독립형으로 실행할 수 있습니다.
필요한 런타임이 포함되어 있으므로 개발 환경에
종속 항목이 포함됩니다 다음을 사용하여 이 독립형 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 규칙을 사용하여 전이 Maven 종속 항목을 관리할 수도 있습니다.
외부 종속 항목: 로컬 및 원격 리포지토리로 구성됩니다
Bazel에 대해 자세히 알아볼 수 있는 기타 규칙
빌드를 시작하는 C++ 빌드 튜토리얼 Bazel을 사용한 C++ 프로젝트
Android 애플리케이션 가이드 및 iOS 애플리케이션 튜토리얼에서 Bazel을 사용하여 Android 및 iOS용 모바일 애플리케이션을 빌드하는 방법을 알아봤습니다.
즐겁게 빌드하세요!