빌드 또는 실행 시 A
에 B
가 필요한 경우 타겟 A
는 타겟 B
에 종속됩니다. depends upon 관계는 타겟에 대해 방향성 비순환 그래프(DAG)를 유도하며 이를 종속 항목 그래프라고 합니다.
타겟의 직접 종속 항목은 종속 항목 그래프에서 길이가 1인 경로로 도달할 수 있는 다른 타겟입니다. 대상의 전이 종속 항목은 그래프를 통과하는 임의 길이의 경로를 통해 종속되는 대상입니다.
실제로 빌드 컨텍스트에는 실제 종속 항목 그래프와 선언된 종속 항목 그래프라는 두 가지 종속 항목 그래프가 있습니다. 대부분의 경우 두 그래프는 매우 유사하므로 구분이 필요하지 않지만 아래 논의에서는 유용합니다.
실제 종속 항목 및 선언된 종속 항목
X
가 올바르게 빌드되려면 Y
가 있어야 하고 빌드되어야 하며 최신 상태여야 하는 경우 타겟 X
는 타겟 Y
에 실제로 종속됩니다. 빌드됨은 생성, 처리, 컴파일, 연결, 보관처리, 압축, 실행 또는 빌드 중에 일상적으로 발생하는 기타 모든 종류의 작업을 의미할 수 있습니다.
X
패키지에 X
에서 Y
까지의 종속 항목 경계가 있으면 타겟 X
에 타겟 Y
에 선언된 종속 항목이 있습니다.
올바른 빌드의 경우 실제 종속 항목 그래프 A가 선언된 종속 항목 그래프 D의 하위 그래프여야 합니다. 즉, A의 모든 직접 연결된 노드 쌍 x --> y
은 D에서도 직접 연결되어야 합니다. D는 A의 오버아프로이제이션이라고 할 수 있습니다.
BUILD
파일 작성자는 빌드 시스템에 대한 모든 규칙의 실제 직접 종속 항목을 모두 명시적으로 선언해야 하며 그 이상은 선언하면 안 됩니다.
이 원칙을 준수하지 않으면 정의되지 않은 동작이 발생합니다. 빌드가 실패할 수 있지만 더 나쁜 것은 빌드가 이전 작업이나 타겟에 있는 전이 선언된 종속 항목에 종속될 수 있다는 점입니다. Bazel은 누락된 종속 항목을 확인하고 오류를 보고하지만, 모든 경우에 이 검사가 완료되는 것은 아닙니다.
실행 시 A
에 필요한 경우에도 간접적으로 가져온 모든 항목을 나열할 필요는 없으며 나열해서는 안 됩니다.
타겟 X
의 빌드 중에 빌드 도구는 X
의 종속 항목의 전체 전이 폐쇄를 검사하여 이러한 타겟의 변경사항이 최종 결과에 반영되도록 하고 필요에 따라 중간 빌드를 다시 빌드합니다.
종속 항목의 전이적 특성으로 인해 흔히 실수가 발생합니다. 한 파일의 코드가 선언된 종속 항목 그래프에서 직접적인 것이 아닌 전이적이지만 간접적인 종속 항목(간접 종속 항목)에서 제공하는 코드를 사용할 수 있습니다. 간접 종속 항목은 BUILD
파일에 표시되지 않습니다. 규칙이 제공업체에 직접 종속되지 않으므로 다음 타임라인 예와 같이 변경사항을 추적할 방법이 없습니다.
1. 선언된 종속 항목이 실제 종속 항목과 일치함
처음에는 모든 것이 작동합니다. a
패키지의 코드는 b
패키지의 코드를 사용합니다.
패키지 b
의 코드는 c
패키지의 코드를 사용하므로 a
은 전이적으로 c
에 종속됩니다.
a/BUILD |
b/BUILD |
---|---|
rule( name = "a", srcs = "a.in", deps = "//b:b", ) |
rule( name = "b", srcs = "b.in", deps = "//c:c", ) |
a / a.in |
b / b.in |
import b; b.foo(); |
import c; function foo() { c.bar(); } |
선언된 종속 항목이 실제 종속 항목을 과도하게 근사합니다. 문제가 없습니다.
2. 선언되지 않은 종속 항목 추가
c
에 대한 직접적인 실제 종속 항목을 만드는 코드를 a
에 추가했지만 빌드 파일 a/BUILD
에서 선언하는 것을 잊어버리면 잠재적 위험이 발생합니다.
a / a.in |
|
---|---|
import b; import c; b.foo(); c.garply(); |
|
선언된 종속 항목이 더 이상 실제 종속 항목을 과대 추정하지 않습니다.
두 그래프의 전이 클로저는 동일하지만 문제를 마스킹하기 때문에 정상적으로 빌드될 수 있습니다. a
에는 실제로 선언되지 않은 c
종속 항목이 있습니다.
3. 선언된 종속 항목 그래프와 실제 종속 항목 그래프 간의 불일치
이 위험은 누군가 b
가 더 이상 c
에 종속되지 않도록 리팩터링하여 의도치 않게 자신의 잘못이 아닌 이유로 a
를 중단할 때 드러납니다.
b/BUILD |
|
---|---|
rule( name = "b", srcs = "b.in", deps = "//d:d", ) |
|
b / b.in |
|
import d; function foo() { d.baz(); } |
|
이제 선언된 종속 항목 그래프는 전이적으로 닫힌 경우에도 실제 종속 항목의 하한 근사치가 됩니다. 빌드가 실패할 가능성이 높습니다.
2단계에서 도입된 a
에서 c
로의 실제 종속 항목이 BUILD
파일에 올바르게 선언되었는지 확인하여 이 문제를 방지할 수 있었습니다.
종속 항목 유형
대부분의 빌드 규칙에는 다양한 종류의 일반 종속 항목을 지정하기 위한 세 가지 속성(srcs
, deps
, data
)이 있습니다. 이에 대한 설명은 아래와 같습니다. 자세한 내용은 모든 규칙에 공통된 속성을 참고하세요.
또한 많은 규칙에는 규칙별 종류의 종속 항목(예: compiler
또는 resources
)에 관한 추가 속성이 있습니다. 자세한 내용은 백과사전 빌드를 참고하세요.
srcs
종속 항목
소스 파일을 출력하는 규칙에서 직접 사용하는 파일입니다.
deps
종속 항목
헤더 파일, 기호, 라이브러리, 데이터 등을 제공하는 별도로 컴파일된 모듈을 가리키는 규칙
data
종속 항목
빌드 타겟이 올바르게 실행되려면 일부 데이터 파일이 필요할 수 있습니다. 이러한 데이터 파일은 소스 코드가 아니므로 타겟 빌드 방식에 영향을 미치지 않습니다. 예를 들어 단위 테스트는 함수의 출력을 파일의 콘텐츠와 비교할 수 있습니다. 단위 테스트를 빌드할 때는 이 파일이 필요하지 않지만 테스트를 실행할 때는 필요합니다. 실행 중에 실행되는 도구에도 동일하게 적용됩니다.
빌드 시스템은 data
로 표시된 파일만 사용할 수 있는 격리된 디렉터리에서 테스트를 실행합니다. 따라서 바이너리/라이브러리/테스트를 실행하는 데 파일이 필요한 경우 data
에서 해당 파일(또는 해당 파일이 포함된 빌드 규칙)을 지정합니다. 예를 들면 다음과 같습니다.
# I need a config file from a directory named env:
java_binary(
name = "setenv",
...
data = [":env/default_env.txt"],
)
# I need test data from another directory
sh_test(
name = "regtest",
srcs = ["regtest.sh"],
data = [
"//data:file1.txt",
"//data:file2.txt",
...
],
)
이러한 파일은 상대 경로 path/to/data/file
를 사용하여 사용할 수 있습니다. 테스트에서 테스트의 소스 디렉터리 경로와 워크스페이스 상대 경로(예: ${TEST_SRCDIR}/workspace/path/to/data/file
)를 결합하여 이러한 파일을 참조할 수 있습니다.
라벨을 사용하여 디렉터리 참조
BUILD
파일을 살펴보면 일부 data
라벨이 디렉터리를 참조하는 것을 확인할 수 있습니다. 이러한 라벨은 다음 예와 같이 /.
또는 /
로 끝나며 사용해서는 안 됩니다.
권장하지 않음 —
data = ["//data/regression:unittest/."]
권장하지 않음 —
data = ["testdata/."]
권장하지 않음 —
data = ["testdata/"]
이는 테스트가 디렉터리의 모든 데이터 파일을 사용할 수 있으므로 특히 테스트에 편리해 보입니다.
하지만 이렇게 하지는 마세요. 변경 후 올바른 증분 빌드 (및 테스트 재실행)를 보장하려면 빌드 시스템이 빌드 (또는 테스트)의 입력인 전체 파일 세트를 인식해야 합니다. 디렉터리를 지정하면 빌드 시스템은 파일 추가 또는 삭제로 인해 디렉터리 자체가 변경되는 경우에만 다시 빌드하지만, 이러한 변경사항은 포함 디렉터리에 영향을 미치지 않으므로 개별 파일의 수정사항은 감지할 수 없습니다.
디렉터리를 빌드 시스템의 입력으로 지정하는 대신 명시적으로 또는 glob()
함수를 사용하여 디렉터리에 포함된 파일 집합을 열거해야 합니다. **
를 사용하여 glob()
를 재귀적으로 강제 적용합니다.
권장:
data = glob(["testdata/**"])
안타깝게도 디렉터리 라벨을 사용해야 하는 시나리오가 있습니다.
예를 들어 testdata
디렉터리에 이름이 라벨 문법을 따르지 않는 파일이 포함되어 있으면 파일을 명시적으로 열거하거나 glob()
함수를 사용하면 잘못된 라벨 오류가 발생합니다. 이 경우 디렉터리 라벨을 사용해야 하지만 위에 설명된 잘못된 리빌드의 관련 위험에 유의하세요.
디렉터리 라벨을 사용해야 하는 경우 상대 ../
경로로 상위 패키지를 참조할 수 없습니다. 대신 //data/regression:unittest/.
와 같은 절대 경로를 사용하세요.
여러 파일을 사용해야 하는 외부 규칙(예: 테스트)은 모든 파일에 대한 종속 항목을 명시적으로 선언해야 합니다. filegroup()
를 사용하여 BUILD
파일에서 파일을 그룹화할 수 있습니다.
filegroup(
name = 'my_data',
srcs = glob(['my_unittest_data/*'])
)
그런 다음 테스트에서 my_data
라벨을 데이터 종속 항목으로 참조할 수 있습니다.
BUILD 파일 | 공개 상태 |