소개
Bazel을 처음 사용하시나요? 여기에서 요청하세요. Bazel 사용에 대한 간소화된 소개는 첫 번째 빌드 튜토리얼을 참고하세요. 이 튜토리얼에서는 Bazel 컨텍스트에서 사용되는 주요 용어를 정의하고 Bazel 워크플로의 기본사항을 안내합니다. 필요한 도구로 시작하여 복잡성이 증가하는 세 가지 프로젝트를 빌드하고 실행하면서 프로젝트가 더 복잡해지는 방법과 이유를 알아봅니다.
Bazel은 다중 언어 빌드를 지원하는 빌드 시스템이지만 이 튜토리얼에서는 C++ 프로젝트를 예로 사용하고 대부분의 언어에 적용되는 일반 가이드라인과 흐름을 제공합니다.
예상 완료 시간: 30분
기본 요건
아직 설치하지 않았다면 먼저 Bazel을 설치합니다. 이 튜토리얼에서는 소스 제어에 Git을 사용하므로 최상의 결과를 얻으려면 Git도 설치하세요.
다음으로 원하는 명령줄 도구에서 다음을 실행하여 Bazel의 GitHub 저장소에서 샘플 프로젝트를 가져옵니다.
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
파일 세트는 세 개이며 각 세트는 이 튜토리얼의 단계를 나타냅니다. 첫 번째 단계에서는 단일 패키지에 있는 단일 타겟을 빌드합니다. 두 번째 단계에서는 단일 패키지에서 바이너리와 라이브러리를 모두 빌드합니다. 세 번째이자 마지막 단계에서는 여러 패키지가 있는 프로젝트를 빌드하고 여러 타겟으로 빌드합니다.
요약: 소개
Bazel (및 Git)을 설치하고 이 튜토리얼의 저장소를 클론하여 Bazel을 사용한 첫 번째 빌드의 기반을 마련했습니다. 다음 섹션으로 계속 진행하여 몇 가지 용어를 정의하고 작업공간을 설정합니다.
시작하기
작업공간 설정
프로젝트를 빌드하려면 먼저 작업공간을 설정해야 합니다. 작업공간은 프로젝트의 소스 파일과 Bazel의 빌드 출력을 보유하는 디렉터리입니다. 또한 다음 중요한 파일도 포함되어 있습니다.
: 디렉터리와 그 내용을 Bazel 작업공간으로 식별하며 프로젝트 디렉터리 구조의 루트에 있습니다.WORKSPACE
file- 하나 이상의
: Bazel에 프로젝트의 여러 부분을 빌드하는 방법을 알려줍니다. 작업공간 내에BUILD
filesBUILD
파일이 포함된 디렉터리는 패키지입니다. (패키지에 관한 자세한 내용은 이 튜토리얼의 뒷부분에서 설명합니다.)
향후 프로젝트에서 디렉터리를 Bazel 작업공간으로 지정하려면 해당 디렉터리에 WORKSPACE
이라는 빈 파일을 만드세요. 이 튜토리얼의 목적에 따라 각 단계에 WORKSPACE
파일이 이미 있습니다.
참고: Bazel이 프로젝트를 빌드할 때는 모든 입력이 동일한 작업공간에 있어야 합니다. 다른 작업공간에 있는 파일은 연결되지 않는 한 서로 독립적입니다. 작업공간 규칙에 관한 자세한 내용은 이 가이드를 참고하세요.
BUILD 파일 이해하기
BUILD
파일에는 Bazel에 관한 여러 유형의 명령어가 포함되어 있습니다. 각 BUILD
파일에는 실행 가능한 바이너리나 라이브러리와 같은 원하는 출력을 빌드하는 방법을 Bazel에 알려주는 명령어 집합인 규칙이 하나 이상 필요합니다. BUILD
파일의 각 빌드 규칙 인스턴스를 타겟이라고 하며 특정 소스 파일 및 종속 항목 집합을 가리킵니다.
타겟은 다른 타겟을 가리킬 수도 있습니다.
cpp-tutorial/stage1/main
디렉터리의 BUILD
파일을 살펴보세요.
cc_binary(
name = "hello-world",
srcs = ["hello-world.cc"],
)
이 예에서 hello-world
타겟은 Bazel의 내장 cc_binary rule
를 인스턴스화합니다.
이 규칙은 Bazel에게 종속 항목이 없는 hello-world.cc
소스 파일에서 독립형 실행 파일 바이너리를 빌드하도록 지시합니다.
요약: 시작하기
이제 주요 용어와 이 프로젝트 및 일반적인 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
cpp-tutorial/stage2/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",
],
)
이 BUILD
파일을 사용하면 Bazel이 먼저 hello-greet
라이브러리(Bazel의 내장 cc_library rule
사용)를 빌드한 다음 hello-world
바이너리를 빌드합니다. hello-world
타겟의 deps
속성은 hello-greet
라이브러리가 hello-world
바이너리를 빌드하는 데 필요하다고 Bazel에 알려줍니다.
이 새 버전의 프로젝트를 빌드하려면 먼저 디렉터리를 변경하여 다음을 실행하여 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은 해당 파일만 다시 컴파일합니다.
종속 항목 그래프를 보면 hello-world
가 hello-greet
라는 추가 입력에 종속되어 있습니다.
요약: 2단계
이제 타겟이 두 개인 프로젝트를 빌드했습니다. hello-world
타겟은 하나의 소스 파일을 빌드하고 두 개의 추가 소스 파일을 빌드하는 다른 타겟 (//main:hello-greet
)에 종속됩니다. 다음 섹션에서는 한 단계 더 나아가 다른 패키지를 추가합니다.
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
이제 하위 디렉터리가 두 개 있으며 각 디렉터리에는 BUILD
파일이 포함되어 있습니다. 따라서 Bazel에서 작업공간에는 이제 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
타겟은 lib
패키지의 hello-time
타겟에 종속됩니다 (따라서 타겟 라벨은 //lib:hello-time
). Bazel은 deps
속성을 통해 이를 알고 있습니다. 종속 항목 그래프에 반영된 것을 확인할 수 있습니다.
빌드가 성공하려면 visibility 속성을 사용하여 lib/BUILD
의 //lib:hello-time
타겟을 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단계
이제 타겟이 3개인 패키지 2개로 프로젝트를 빌드하고 패키지 간의 종속 항목을 이해했으므로 Bazel로 향후 프로젝트를 빌드할 수 있습니다. 다음 섹션에서는 Bazel 여정을 계속하는 방법을 살펴봅니다.
다음 단계
이제 Bazel을 사용하여 첫 번째 기본 빌드를 완료했지만 이는 시작에 불과합니다. 다음은 Bazel로 학습을 계속할 수 있는 추가 리소스입니다.
- C++에 계속 집중하려면 일반적인 C++ 빌드 사용 사례를 읽어보세요.
- Bazel로 다른 애플리케이션을 빌드하는 방법을 알아보려면 Java, Android 애플리케이션 또는 iOS 애플리케이션 튜토리얼을 참고하세요.
- 로컬 및 원격 저장소 작업에 대해 자세히 알아보려면 외부 종속 항목을 참고하세요.
- Bazel의 다른 규칙에 대해 자세히 알아보려면 이 참조 가이드를 확인하세요.
즐거운 빌드 되세요!