여러분, 대규모 프로젝트를 개발하다가 빌드 시간이 너무 오래 걸려서 커피 한 잔 마시고 와도 끝나지 않은 경험 있으신가요? 저도 처음 텐서플로우를 빌드할 때 “이게 대체 언제 끝나지?”라며 답답해했던 기억이 납니다. 그런데 알고 보니 그 텐서플로우를 빌드하는 도구가 바로 오늘 소개할 Bazel이더라고요.

Bazel(베이젤)은 구글이 사내에서 사용하던 빌드 시스템 Blaze를 2015년에 오픈소스로 공개한 것인데요, 구글처럼 수십만 개의 소스 파일을 다루는 거대한 프로젝트도 빠르고 안정적으로 빌드할 수 있게 만들어진 도구입니다. 2025년 10월 현재 Bazel 7.6.2와 8.2 버전이 활발하게 업데이트되고 있고, 올해 말에는 Bazel 9.0 LTS 버전이 출시될 예정이라고 하네요.

 

Bazel

 

 

1. Bazel이 뭐길래 구글이 사용할까요?

Bazel은 Make, Maven, Gradle과 비슷한 오픈소스 빌드 및 테스트 도구입니다. 하지만 단순히 “또 하나의 빌드 툴”이 아니라, 구글이 수년간 대규모 코드베이스를 관리하면서 얻은 노하우가 집약된 도구라고 할 수 있습니다.

Bazel은 소프트웨어 빌드와 테스트를 자동화하는 도구로, 컴파일러와 링커를 실행해서 실행 가능한 프로그램과 라이브러리를 만들고, Android, iOS 등 다양한 타겟 환경용 배포 패키지를 조립하는 작업을 지원합니다.

Bazel의 이름 유래

초기 로고를 보면 알파벳 ‘b’를 바질(Basil) 잎사귀 두 개로 표현했는데, 내부 코드명 Blaze와 허브 식물인 Basil을 중의적으로 연결한 것으로 보입니다. 발음은 영어권에서는 “베이즐” 정도로 읽는다고 하네요.

 

 

2. 다른 빌드 도구와 뭐가 다른가요?

여러분이 이미 Maven이나 Gradle을 사용하고 계신다면 “굳이 새로운 걸 배워야 하나?”라는 생각이 드실 수 있습니다. 저도 처음엔 그랬거든요. 그런데 Bazel만의 특별한 점들을 알고 나니 생각이 바뀌었습니다.

속도와 효율성

Bazel은 이전에 수행한 모든 작업을 캐싱(Caching)하고 파일 내용과 빌드 명령의 변경 사항을 추적합니다. 이를 통해 Bazel은 무엇을 다시 빌드해야 하는지 알고, 필요한 부분만 다시 빌드합니다.

쉽게 말해, 100개 파일 중 1개만 수정했다면 그 1개와 관련된 부분만 다시 빌드한다는 뜻입니다. 마치 똑똑한 비서가 “이 부분은 이미 완료됐으니 건너뛰고, 이것만 다시 하면 됩니다”라고 알려주는 것과 같죠.

멀티 플랫폼, 멀티 언어 지원

Bazel은 Linux, macOS, Windows에서 실행되며, 동일한 프로젝트에서 데스크톱, 서버, 모바일을 포함한 여러 플랫폼용 바이너리와 배포 패키지를 빌드할 수 있습니다.

Python과 Scala도 이제 공식적으로 지원되는 타겟 언어입니다. Java, C++는 물론이고 최근에는 Python, Scala, Go, Rust 등 다양한 언어를 지원합니다. 심지어 Android 앱과 iOS 앱도 빌드할 수 있어요.

확장성 (Scalability)

Bazel은 10만 개 이상의 소스 파일을 처리하는 빌드에서도 민첩성을 유지하며, 수만 명의 사용자 베이스와 여러 저장소에서 작동합니다.

소규모 프로젝트부터 구글급 대규모 모노레포(Monorepo)까지 모두 커버할 수 있다는 것이 장점입니다.

 

 

3. Bazel의 핵심 개념 이해하기

Bazel을 사용하려면 몇 가지 핵심 개념을 알아야 합니다. 어렵지 않으니 천천히 따라오세요.

워크스페이스 (Workspace)

워크스페이스는 Bazel이 빌드할 소스 코드와 출력물을 저장하기 위한 폴더입니다. 프로젝트의 최상위 디렉토리에 WORKSPACE 또는 MODULE.bazel 파일이 있으면 그 폴더가 워크스페이스가 됩니다.

WORKSPACE 파일은 “여기가 프로젝트 루트입니다”라고 알려주는 표시입니다. 빈 파일일 수도 있고, 외부 의존성(External Dependencies)을 정의할 수도 있습니다.

2025년 3월 기준으로 Bazel Central Registry에는 650개 이상의 모듈이 등록되어 있으며, Bzlmod가 Bazel 7부터 표준 외부 의존성 시스템이 되었습니다. Bazel 9에서는 WORKSPACE 기능이 완전히 제거되고 Bzlmod만 사용하게 됩니다.

최신 Bazel에서는 MODULE.bazel 파일로 의존성을 관리하는 것이 표준이 되었습니다.

BUILD 파일 vs BUILD.bazel 파일

각 패키지(Package)마다 빌드 규칙을 정의하는 파일이 필요한데, BUILD 또는 BUILD.bazel 둘 중 하나를 사용할 수 있습니다.

  • BUILD: 전통적인 이름
  • BUILD.bazel: Windows에서 시스템 폴더명과 충돌을 피하기 위한 이름

Windows 사용자라면 BUILD.bazel을 사용하는 것이 좋습니다. Bazel은 둘 다 인식하며, 같은 디렉토리에 둘 다 있으면 BUILD.bazel을 우선시합니다.

예를 들어 간단한 C++ 프로젝트의 BUILD 파일은 이렇게 생겼습니다:

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
)

여기서 cc_binary는 빌드 규칙(Build Rule)이고, hello-world는 타겟(Target) 이름입니다.

규칙(Rules)과 타겟(Targets)

  • 규칙(Rule): 빌드 작업을 수행하는 방법을 정의합니다. cc_binary, cc_library, java_binary, py_library 같은 것들이죠.
  • 타겟(Target): BUILD 파일에서 규칙의 인스턴스입니다. 위 예시의 hello-world가 타겟입니다.

타겟은 //패키지경로:타겟이름 형식으로 참조합니다. 예를 들어 //main:hello-worldmain 디렉토리의 hello-world 타겟을 의미합니다.

Starlark 언어

BUILD 파일은 Starlark라는 도메인 특화 언어를 사용해서 작성합니다. Python과 비슷한 문법을 가지고 있어서 Python 개발자라면 금방 익숙해질 수 있습니다.

 

 

4. Bazel 설치하기 – 단계별 가이드

자, 이제 본격적으로 Bazel을 설치해볼까요? 가장 쉽고 권장되는 방법은 Bazelisk를 사용하는 것입니다.

Bazelisk란?

Bazelisk는 Go로 작성된 Bazel용 래퍼(Wrapper)로, 현재 작업 디렉토리에 맞는 적절한 Bazel 버전을 자동으로 선택하고, 필요한 경우 공식 서버에서 다운로드한 후, 모든 명령줄 인수를 실제 Bazel 바이너리에 투명하게 전달합니다.

쉽게 말해, Bazel의 버전 관리자라고 보시면 됩니다. Node.js의 nvm처럼요.

macOS 설치

brew install bazelisk

Homebrew를 사용하면 한 줄로 끝납니다.

Windows 설치

세 가지 방법 중 편한 걸 선택하세요:

# Windows Package Manager
winget install Bazel.Bazelisk

# Chocolatey
choco install bazelisk

# Scoop
scoop install bazelisk

이 방법들은 모두 bazelisk와 bazel 두 가지 명령어로 PATH에 추가됩니다.

Windows 사용자 주의사항:

  • Windows에서는 경로에 공백이 있으면 문제가 발생할 수 있습니다. C:\Program Files보다는 C:\bazel-workspace 같은 경로를 사용하세요.
  • 긴 경로명(Long Path) 지원을 활성화해야 할 수 있습니다. PowerShell을 관리자 권한으로 실행하고:
    New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force
    

Linux 설치

직접 바이너리를 다운로드하는 방법입니다:

# 최신 Bazelisk 다운로드
wget https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-amd64

# 실행 권한 부여
chmod +x bazelisk-linux-amd64

# /usr/local/bin으로 이동 (PATH에 포함되어 있어야 함)
sudo mv bazelisk-linux-amd64 /usr/local/bin/bazel

# 설치 확인
which bazel

npm을 통한 설치

프론트엔드 개발자라면 npm으로 설치할 수도 있습니다:

npm install -g @bazel/bazelisk

설치 확인

bazel --version

명령어를 실행했을 때 버전 정보가 나오면 성공입니다!

 

 

5. 첫 Bazel 프로젝트 만들어보기

이론만 보면 재미없죠. 직접 간단한 C++ 프로젝트를 만들어보면서 Bazel이 어떻게 작동하는지 체험해봅시다.

프로젝트 구조 만들기

mkdir my-bazel-project
cd my-bazel-project

WORKSPACE 파일 생성

프로젝트 루트에 빈 WORKSPACE 파일을 만듭니다:

# Linux/macOS
touch WORKSPACE

# Windows (PowerShell)
New-Item -Path . -Name "WORKSPACE" -ItemType "file"

최신 버전을 사용한다면 MODULE.bazel 파일을 만드는 것이 좋지만, 기본 예제에서는 빈 WORKSPACE로도 충분합니다.

소스 코드 작성

hello-world.cc 파일을 만듭니다:

#include <iostream>

int main() {
    std::cout << "Hello, Bazel World!" << std::endl;
    return 0;
}

BUILD 파일 작성

같은 디렉토리에 BUILD (또는 Windows에서는 BUILD.bazel) 파일을 만듭니다:

cc_binary(
    name = "hello-world",
    srcs = ["hello-world.cc"],
)

빌드 실행

bazel build //:hello-world

//는 워크스페이스 루트를 의미하고, :hello-world는 타겟 이름입니다.

빌드가 성공하면 다음과 같은 메시지를 볼 수 있습니다:

INFO: Analyzed target //:hello-world (15 packages loaded, 58 targets configured).
INFO: Found 1 target...
Target //:hello-world up-to-date:
  bazel-bin/hello-world
INFO: Elapsed time: 2.456s, Critical Path: 0.89s
INFO: Build completed successfully, 3 total actions

실행하기

bazel run //:hello-world

또는 빌드된 바이너리를 직접 실행:

# Linux/macOS
./bazel-bin/hello-world

# Windows
.\bazel-bin\hello-world.exe

“Hello, Bazel World!”가 출력되면 성공입니다! 🎉

 

 

6. 조금 더 실전적인 예제 – 라이브러리 의존성

실제 프로젝트에서는 여러 파일이 서로 의존하는 경우가 많죠. 라이브러리를 만들고 그것을 사용하는 예제를 만들어봅시다.

프로젝트 구조

my-project/
├── WORKSPACE
├── lib/
│   ├── BUILD
│   ├── greet.h
│   └── greet.cc
└── main/
    ├── BUILD
    └── main.cc

라이브러리 코드 작성

lib/greet.h:

#ifndef GREET_H
#define GREET_H

#include <string>

std::string get_greeting(const std::string& name);

#endif

lib/greet.cc:

#include "lib/greet.h"

std::string get_greeting(const std::string& name) {
    return "Hello, " + name + "!";
}

lib/BUILD:

cc_library(
    name = "greet",
    srcs = ["greet.cc"],
    hdrs = ["greet.h"],
    visibility = ["//visibility:public"],
)

visibility 속성은 이 라이브러리를 다른 패키지에서도 사용할 수 있게 합니다.

메인 프로그램 작성

main/main.cc:

#include <iostream>
#include "lib/greet.h"

int main() {
    std::cout << get_greeting("Bazel") << std::endl;
    return 0;
}

main/BUILD:

cc_binary(
    name = "hello",
    srcs = ["main.cc"],
    deps = ["//lib:greet"],
)

deps 속성에서 //lib:greet는 lib 디렉토리의 greet 타겟을 의존성으로 지정한다는 의미입니다.

빌드 및 실행

bazel build //main:hello
bazel run //main:hello

출력: “Hello, Bazel!”

의존성 그래프 확인

Bazel의 강력한 기능 중 하나는 의존성을 시각화할 수 있다는 것입니다:

bazel query --notool_deps --noimplicit_deps 'deps(//main:hello)' --output graph

이 명령어는 GraphViz 형식으로 의존성 그래프를 출력합니다. Graphviz Online에 붙여넣으면 시각적으로 확인할 수 있어요.

 

 

7. Bazel의 강력한 기능들

증분 빌드 (Incremental Build)

파일 하나만 수정했을 때 전체를 다시 빌드하지 않는다는 것, 정말 큰 장점입니다. 위 예제에서 greet.cc만 수정하고 다시 빌드하면:

bazel build //main:hello

Bazel은 greet.cc와 그것에 의존하는 main.cc만 다시 컴파일합니다. 나머지는 캐시를 사용하죠.

병렬 빌드

Bazel은 기본적으로 여러 작업을 병렬로 처리합니다. CPU 코어를 효율적으로 활용해서 빌드 시간을 크게 단축시킵니다.

병렬 작업 수를 조절하려면:

bazel build //main:hello --jobs=8

원격 캐시 (Remote Cache)

팀 전체가 빌드 캐시를 공유할 수 있습니다. 누군가가 이미 빌드한 결과물을 다른 팀원이 재사용할 수 있어서, CI/CD 환경에서 특히 유용합니다.

테스트 자동화

cc_test(
    name = "greet_test",
    srcs = ["greet_test.cc"],
    deps = ["//lib:greet"],
)

테스트도 Bazel로 관리할 수 있습니다:

bazel test //lib:greet_test

 

 

8. .bazelrc 설정 파일로 옵션 관리하기

매번 명령어에 옵션을 붙이는 건 번거롭죠. .bazelrc 파일을 만들어서 기본 설정을 저장할 수 있습니다.

프로젝트 루트에 .bazelrc 파일을 만듭니다:

# 빌드 최적화
build --jobs=8
build --compilation_mode=opt

# 테스트 설정
test --test_output=errors

# Windows 전용 설정
build:windows --enable_runfiles=false
build:windows --copt=-DWIN32_LEAN_AND_MEAN

# macOS 전용 설정
build:macos --macos_minimum_os=10.15

특정 설정을 사용하려면:

bazel build //main:hello --config=windows

 

 

9. IDE 통합 – IntelliJ IDEA 예시

IntelliJ IDEA 2025.1에서 Bazel 플러그인이 크게 개선되었습니다. Bazel 8과 중첩 모듈(Nested Modules)을 완전히 지원하며, Python과 Scala도 공식 지원 대상이 되었습니다.

IntelliJ IDEA에서 설정하기

  1. IntelliJ IDEA를 실행합니다.
  2. Settings (설정) > **Plugins (플러그인)**으로 이동합니다.
  3. Marketplace에서 “Bazel”을 검색해서 설치합니다.
  4. IDE를 재시작합니다.

프로젝트 열기

  1. File (파일) > **Open (열기)**에서 WORKSPACE 파일이 있는 디렉토리를 선택합니다.
  2. “Import Bazel Project”를 선택합니다.
  3. 프로젝트 구조가 분석되고 IDE가 코드 어시스턴스(Code Assistance)를 제공합니다.

코드에서 의존성을 직접 추가할 수 있습니다. 아직 의존성이 아닌 다른 Bazel 프로젝트 부분의 클래스를 사용하면, IntelliJ의 표준 Alt+Enter 인텐션 액션(Intention Action)이 “Add dependency on module (모듈에 의존성 추가)…” 옵션을 제공합니다.

정말 편리하죠? 수동으로 BUILD 파일을 편집할 필요가 없어집니다.

 

 

10. 트러블슈팅 – 자주 발생하는 문제와 해결법

문제 1: “ERROR: no such package”

증상:

ERROR: no such package '//lib': BUILD file not found in directory 'lib'

원인: BUILD 파일이 없거나 잘못된 위치에 있습니다.

해결:

  • lib 디렉토리에 BUILD 또는 BUILD.bazel 파일이 있는지 확인
  • 파일명 대소문자 확인 (Linux/macOS는 대소문자 구분)

문제 2: “ERROR: Target not found”

증상:

ERROR: no such target '//main:helo': target 'helo' not declared

원인: 타겟 이름을 잘못 입력했거나 BUILD 파일에 선언되지 않았습니다.

해결:

  • BUILD 파일의 name 속성 확인
  • 타이포 체크

문제 3: Windows 경로 문제

증상:

ERROR: error reading BUILD file

원인: Windows 경로 구분자 문제

해결:

  • BUILD 파일에서 경로는 항상 슬래시(/) 사용
  • 백슬래시(\) 대신 슬래시(/) 사용

문제 4: 캐시 문제

증상: 코드를 수정했는데 변경사항이 반영되지 않음

해결:

# 캐시 정리
bazel clean

# 완전히 정리 (모든 빌드 출력물 삭제)
bazel clean --expunge

문제 5: 메모리 부족

증상:

ERROR: Java heap space

해결: .bazelrc에 메모리 설정 추가

startup --host_jvm_args=-Xmx4g

 

 

11. 실전 팁과 주의사항

.bazelversion 파일 사용

프로젝트 루트에 .bazelversion 파일을 만들어 정확한 Bazel 버전을 지정할 수 있습니다:

7.6.2

이렇게 하면 팀 전체가 동일한 버전을 사용하게 되어 “내 컴퓨터에서는 되는데요?” 문제를 방지할 수 있습니다.

빌드 로그 확인

빌드가 실패했을 때 자세한 로그를 보려면:

bazel build //main:hello --verbose_failures

더 자세한 정보가 필요하면:

bazel build //main:hello --subcommands

성능 프로파일링

빌드 속도를 분석하고 싶다면:

bazel build //main:hello --profile=build.prof

그리고 다음 명령어로 분석 결과를 확인:

bazel analyze-profile build.prof

특정 타겟만 테스트

전체 테스트 대신 특정 패키지만:

# lib 패키지의 모든 테스트
bazel test //lib/...

# 특정 테스트만
bazel test //lib:greet_test

빌드 출력물 찾기

Bazel은 심볼릭 링크를 만들어 출력물을 쉽게 찾을 수 있게 합니다:

  • bazel-bin/: 바이너리 출력
  • bazel-out/: 모든 빌드 출력
  • bazel-testlogs/: 테스트 로그

 

 

12. Bazel을 사용하는 유명 프로젝트들

Bazel이 정말 강력한 도구인지 의심스럽다면, 다음 프로젝트들이 Bazel을 사용한다는 사실을 알면 마음이 바뀔지도 모릅니다:

  • TensorFlow: 구글의 머신러닝 프레임워크
  • Kubernetes: 컨테이너 오케스트레이션 플랫폼
  • Envoy: 고성능 프록시
  • gRPC: 구글의 RPC 프레임워크
  • Angular: 구글의 웹 프레임워크

이런 대규모 프로젝트들이 Bazel을 선택한 이유는 명확합니다. 속도, 안정성, 확장성 모두를 만족시키기 때문이죠.

 

 

13. Bazel vs 다른 빌드 도구

Bazel vs Maven

특징 Bazel Maven
속도 매우 빠름 (캐싱, 병렬) 보통
학습 곡선 가파름 완만함
언어 지원 다중 언어 주로 Java
캐싱 로컬 + 원격 로컬만
생태계 성장 중 매우 성숙

Bazel vs Gradle

특징 Bazel Gradle
빌드 속도 매우 빠름 빠름
증분 빌드 매우 정확 좋음
플랫폼 지원 다중 플랫폼 주로 JVM
설정 복잡도 명시적 유연함
Android 개발 지원 공식 도구

언제 Bazel을 선택해야 할까?

Bazel이 좋은 경우:

  • 대규모 모노레포를 관리하는 경우
  • 멀티 언어, 멀티 플랫폼 프로젝트
  • 빌드 속도가 중요한 경우
  • 팀 규모가 크고 빌드 재현성(Reproducibility)이 중요한 경우

다른 도구가 나을 수 있는 경우:

  • 소규모 단일 언어 프로젝트
  • 빠른 프로토타입 개발
  • 기존 생태계에 깊이 의존하는 경우

 

 

14. 2025년 Bazel 로드맵과 커뮤니티

2025년 말에 Bazel 9.0 LTS가 출시될 예정이며, WORKSPACE 기능이 완전히 제거되고 Bzlmod만 사용하게 됩니다.

주목할 만한 항목으로는 WORKSPACE 기능 폐기, C++ 규칙의 Starlark화 및 자동 로드 제거, 심볼릭 매크로의 지연 평가(Lazy Evaluation), 그리고 Bazel 플래그의 인지 부담을 줄이기 위한 새로운 프로젝트 기반 모델이 포함됩니다.

BazelCon 2025

Bazel 커뮤니티의 연례 행사인 BazelCon 20252025년 11월 10-11일 미국 애틀란타, 조지아에서 개최됩니다. 11월 9일에는 커뮤니티 트레이닝 데이(Community Training Day)도 진행됩니다.

무료 참석이 가능하며, 공식 사이트에서 등록할 수 있습니다. Bazel 팀과 직접 소통하고, 최신 발표를 들을 수 있는 좋은 기회입니다.

Bazel 팀은 지속적으로 개발자 경험을 개선하고 있으며, 커뮤니티도 활발합니다.

 

 

처음에는 “왜 굳이 새로운 빌드 도구를 배워야 하지?”라고 생각했던 제가, 지금은 대규모 프로젝트에서 Bazel 없이는 못 살 것 같습니다. 특히 여러 언어가 혼재된 프로젝트나 빌드 시간이 중요한 상황에서 Bazel은 정말 큰 도움이 됩니다.

물론 학습 곡선이 가파른 편이고, 기존 프로젝트를 Bazel로 마이그레이션하는 것은 쉬운 일이 아닙니다. 하지만 한번 제대로 구축해놓으면 그 투자가 충분히 가치 있다는 것을 느끼실 수 있을 거예요.

이 글이 Bazel을 시작하는 분들에게 도움이 되었으면 좋겠습니다. 궁금한 점이 있으시면 Bazel 공식 문서GitHub 저장소를 참고해보세요. 커뮤니티도 활발해서 질문하면 친절하게 답변해주는 분들이 많습니다.

더 자세한 내용이 궁금하시다면:

 

 

댓글 남기기