개요
bazel 빌드 시스템은 Python 언어의 일부 기능을 기반으로 빌드 시스템을 자체 개발한 Skylark 언어로 확장한다. bazel 빌드 시스템을 설치하면, Skylark 언어로 개발한 기본 라이브러리를 @bazel-tool repository로 제공한다. 이번 시간에는 @bazel-tool를 사용하기 이전에, 같은 팀이 개발한 bazel-skylib를 다운받아 외부 의존성으로 사용하는 방법을 언급하려 한다.
@bazel-tool에서 제공하는 기능을 활용해 bazel-skylib를 다운받고, @ bazel-skylib repository를 구성하고 외부 라이브러리로 사용하는 예제는 연이어 오는 다음 게시글 내용이다.
풀어야 할 과제.
초기 시작 단계의 폴더 구성은 아래와 같다. my 폴더 하부에 자체 빌드 시스템을 구성하고, bazel-skylib 폴더를 my과 같은 레벨에 git 프로그램을 활용해 다운로드할 것이다.
my 폴더 하부에 자체 빌드 시스템을 구성하기 위해서는 WORKSPACE.bazel 파일을 생성해야 한다. src에 포함된 main.cc를 컴파일하기 위해 BUILD.bazel 파일을 구성할 것이다.
└─my
│ BUILD.bazel
│ WORKSPACE.bazel
│
└─src
main.cc
version.h.in
main.cc 파일 내용을 보자.
일단 version.h.in 파일에서 생성된 version.h 파일을 밑도 끝도 없이 include한다.
#include <version.h>
#include <iostream>
int main() {
std::cout<< "MY_VERSION:" << MY_VERSION << "\n";
std::cout<< "STRING_DATA:" << STRING_DATA << "\n";
return 0;
}
version.h.in 파일 내용을 보자. @MY_VERSION@과 @STRING_DATA@를 적절한 구문으로 대체해서 version.h 파일을 소스 폴더가 아닌 임의 어떤 폴더에 생성해야 한다. 이렇게 생성된 파일의 경로가 main.cc를 컴파일할 때 include directory 경로로 사용되어야 한다.
#define MY_VERSION @MY_VERSION@
#define STRING_DATA "@STRING_DATA@"
여기까지가 빌드 시스템이 해야 할 작업이다. 자!! 시작해보자.
git으로 bazel-skylib 다운로드하기
아마도 주어진 과제 중에 가장 쉽다. 일단 my 폴더과 같은 폴더에서 다음 명령을 console 창에 입력한다.
git clone https://github.com/bazelbuild/bazel-skylib.git
외부 의존성을 작성한다.
다운받은 bazel-skylib 폴더를 확인해보면, 맨 상위에 WORKSPACE.* 형태의 다양한 버전이 존재함을 확인할 수 있다. 실제 이번 프로젝트에서 빌드 시스템 맨 상위 폴더는 확장자가 없는 WORKSPACE가 담당하고 있다. WORKSPACE.bzlmod는 언급할 예정이다.
결론적으로 외부 의존성을 걸 수 있는 또다른 빌드 시스템이다. local_repository 구문으로 외부 의존성을 my 폴더의 WORKSPACE.bazel에 추가하자. 바로 앞 예제에서 이 부분은 이미 한번 배운 상태다.
# my/WORKSPACE.bazel
local_repository(
name = "bazel-skylib",
path = "..\bazel-skylib"
)
BUILD.bazel 파일로 main.cc에 생명력을 불어 넣어보자.
bazel_skylib 외부 의존 repository의 하부 폴더 rules의 expand_template.bzl 파일에서 expand_template rule를 load rule를 사용해 끌어올리자. 실제 skylark 언어로 작성한 파일은 bzl 확장을 갖고 있고, bzl 파일을 업로드하는 과정도 BUILD 파일을 통해 진행된다. BUILD 파일 내부 정보를 확인해보면 bzl_library rule를 사용한다.
expand_template rule는 substitutions 항목에 지정한 내용에 따라 template로 지정한 파일에서 out로 지정한 파일로 저장해준다.
substitutions 항목은 "SERACH" :"REPLACE" 형태, 즉 KEY:VALUE 형태로 리스트화한다. expand_template 결과 파일을 명명하면 의존성이 형성된다.
cc_library rule의 hdrs에 expand_template rule로 생성한 결과물을 적어주고, includes 항목에 생성된 파일이 포함된 폴더를 적어준다. 의존성 검사를 통해서 생성된 파일이 있는 위치를 자동적으로 includes 항목에 추가하고, cc_library rule에 의존성을 설정한 cc_binary는 생성한 파일 경로를 알 수 있게 된다.
# my/BUILD.bazel
load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
expand_template(
name = "sub_version",
template = "src/version.h.in",
out = "src/version.h",
substitutions = {
"@MY_VERSION@": "62",
"@STRING_DATA@": "안녕하세요.",
},
)
cc_library(
name = "version_lib",
hdrs = ["src/version.h"],
includes =["src/"]
)
cc_binary(
name = "main",
srcs = ["src/main.cc"],
deps = [":version_lib"],
)
cc_library rule로 생성한 version_lib를 cc_binary rule의 deps 항목에 추가할 때, ":" 앞에 추가하면 해당 파일에서 생성한 target 이름으로 해석한다.
생각해보기
조금 복잡하게 돌아온 듯한 느낌이다. 왜 곧바로 cc_binary에 사용하지 않고 cc_library를 만들어야 하는가?
이런 저런 고민을 해보면, 일단 cc_binary는 hdrs 항목이 없고, srcs 항목에는 헤더 파일을 추가할 수 없다. deps 항목에는 expand_template로 생성된 target를 추가할 수 없다. 즉 deps로도, hdrs로도 문제를 풀 수 없다. 결국 cc_library를 경유함으로써 이러한 문제를 해결 할 수 있다.
최종 결과 확인하기
빌드하기
bazelisk build //...
main.cc 실행하기
bazelisk run //:main
결과 화면
D:\test\bazel\MyProject\my>bazelisk run //:main
INFO: Analyzed target //:main (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
Target //:main up-to-date:
bazel-bin/main.exe
INFO: Elapsed time: 0.115s, Critical Path: 0.01s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action
INFO: Running command line: bazel-bin/main.exe
MY_VERSION:62
STRING_DATA:안녕하세요.
'building system > bazel' 카테고리의 다른 글
bzlMod 기반 GoogleTest 기본 예제 구현하기 (1) | 2024.01.23 |
---|---|
새로운 의존성 설계 bzlMod 기본 예제 구현하기 (1) | 2024.01.22 |
http_archive/git_repository 기반 bazel 예제 구현하기 (0) | 2024.01.22 |
외부 의존성이 있는 bazel 기본 예제 구현하기 (0) | 2024.01.20 |
bazel 빌드시스템 설치하기 (0) | 2024.01.20 |