소개
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
│ └── MODULE.bazel
├──stage2
│ ├── main
│ │ ├── BUILD
│ │ ├── hello-world.cc
│ │ ├── hello-greet.cc
│ │ └── hello-greet.h
│ └── MODULE.bazel
└──stage3
├── main
│ ├── BUILD
│ ├── hello-world.cc
│ ├── hello-greet.cc
│ └── hello-greet.h
├── lib
│ ├── BUILD
│ ├── hello-time.cc
│ └── hello-time.h
└── MODULE.bazel
파일 세트는 세 개가 있으며 각 세트는 이 튜토리얼의 단계를 나타냅니다. 첫 번째 단계에서는 단일 패키지에 있는 단일 타겟을 빌드합니다. 두 번째 단계에서는 단일 패키지에서 바이너리와 라이브러리를 모두 빌드합니다. 세 번째이자 마지막 단계에서는 여러 패키지가 있는 프로젝트를 빌드하고 여러 타겟으로 빌드합니다.
요약: 소개
Bazel(및 Git)을 설치하고 이 튜토리얼의 저장소를 클론하여 Bazel을 사용한 첫 번째 빌드의 기반을 마련했습니다. 다음 섹션으로 이동하여 몇 가지 용어를 정의하고 작업공간을 설정합니다.
시작하기
프로젝트를 빌드하려면 먼저 작업공간을 설정해야 합니다. 워크스페이스는 프로젝트의 소스 파일과 Bazel의 빌드 출력을 보관하는 디렉터리입니다. 또한 다음과 같은 중요한 파일이 포함되어 있습니다.
MODULE.bazel
파일: 디렉터리와 디렉터리의 콘텐츠를 Bazel 작업공간으로 식별하고 프로젝트 디렉터리 구조의 루트에 있습니다. 여기에서 외부 종속 항목도 지정합니다.- 하나 이상의
BUILD
파일: Bazel에 프로젝트의 여러 부분을 빌드하는 방법을 알려줍니다.BUILD
파일이 포함된 작업공간 내 디렉터리는 패키지입니다. 패키지에 관한 자세한 내용은 이 튜토리얼의 뒷부분을 참고하세요.
향후 프로젝트에서 디렉터리를 Bazel 워크스페이스로 지정하려면 해당 디렉터리에 MODULE.bazel
라는 빈 파일을 만듭니다. 이 튜토리얼에서는 각 단계에 MODULE.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
규칙을 인스턴스화합니다. 이 규칙은 Bazel에게 종속 항목이 없는 hello-world.cc
> 소스 파일에서 독립형 실행 파일 바이너리를 빌드하도록 지시합니다.
요약: 시작하기
이제 몇 가지 주요 용어와 이 프로젝트 및 일반적으로 Bazel의 맥락에서 이러한 용어가 의미하는 바를 알게 되었습니다. 다음 섹션에서는 프로젝트의 1단계를 빌드하고 테스트합니다.
1단계: 단일 타겟, 단일 패키지
이제 프로젝트의 첫 번째 부분을 빌드할 시간입니다. 시각적으로 참고할 수 있도록 프로젝트의 1단계 섹션 구조는 다음과 같습니다.
examples
└── cpp-tutorial
└──stage1
├── main
│ ├── BUILD
│ └── hello-world.cc
└── MODULE.bazel
다음을 실행하여 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
│ └── MODULE.bazel
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",
],
)
Bazel은 이 BUILD
파일을 사용하여 먼저 Bazel의 내장 cc_library
규칙을 사용하여 hello-greet
라이브러리를 빌드한 다음 hello-world
바이너리를 빌드합니다. hello-world
타겟의 deps
속성은 hello-world
바이너리를 빌드하는 데 hello-greet
라이브러리가 필요하다고 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
└── MODULE.bazel
이제 하위 디렉터리가 두 개 있고 각각에 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
속성을 통해 이를 인식합니다. 종속 항목 그래프에 반영된 것을 확인할 수 있습니다.
빌드가 성공하려면 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단계
이제 프로젝트를 세 개의 대상이 있는 두 패키지로 빌드하고 패키지 간의 종속 항목을 이해했으므로 앞으로 Bazel을 사용하여 프로젝트를 빌드할 수 있습니다. 다음 섹션에서는 Bazel 여정을 계속하는 방법을 살펴봅니다.
다음 단계
이제 Bazel을 사용하여 첫 번째 기본 빌드를 완료했지만 이것은 시작에 불과합니다. Bazel을 계속 학습할 수 있는 몇 가지 리소스는 다음과 같습니다.
- C++에 계속 집중하려면 일반적인 C++ 빌드 사용 사례를 읽어보세요.
- Bazel을 사용하여 다른 애플리케이션을 빌드하려면 Java, Android 애플리케이션 또는 iOS 애플리케이션 튜토리얼을 참고하세요.
- 로컬 및 원격 저장소 작업에 대한 자세한 내용은 외부 종속 항목을 참조하세요.
- Bazel의 다른 규칙에 대해 자세히 알아보려면 이 참조 가이드를 참고하세요.
즐겁게 빌드하세요!