cquery
는 query
의 변형으로, 빌드 그래프에 대한 select()
및 빌드 옵션의 영향을 올바르게 처리합니다.
이는 이러한 효과를 통합하는 Bazel의 분석 단계 결과를 실행하여 달성됩니다. 반면 query
는 옵션이 평가되기 전 Bazel의 로드 단계 결과를 통해 실행됩니다.
예를 들면 다음과 같습니다.
$ cat > tree/BUILD <<EOF sh_library( name = "ash", deps = select({ ":excelsior": [":manna-ash"], ":americana": [":white-ash"], "//conditions:default": [":common-ash"], }), ) sh_library(name = "manna-ash") sh_library(name = "white-ash") sh_library(name = "common-ash") config_setting( name = "excelsior", values = {"define": "species=excelsior"}, ) config_setting( name = "americana", values = {"define": "species=americana"}, ) EOF
# Traditional query: query doesn't know which select() branch you will choose, # so it conservatively lists all of possible choices, including all used config_settings. $ bazel query "deps(//tree:ash)" --noimplicit_deps //tree:americana //tree:ash //tree:common-ash //tree:excelsior //tree:manna-ash //tree:white-ash # cquery: cquery lets you set build options at the command line and chooses # the exact dependencies that implies (and also the config_setting targets). $ bazel cquery "deps(//tree:ash)" --define species=excelsior --noimplicit_deps //tree:ash (9f87702) //tree:manna-ash (9f87702) //tree:americana (9f87702) //tree:excelsior (9f87702)
각 결과에는 타겟이 빌드된 구성의 고유 식별자 (9f87702)
가 포함됩니다.
cquery
는 구성된 타겟 그래프를 통해 실행되므로 빌드 작업과 같은 아티팩트에 대한 통찰력이 없으며 구성된 타겟이 아니므로 test_suite
규칙에 액세스할 수 없습니다. 전자의 경우 aquery
를 참고하세요.
기본 구문
간단한 cquery
호출은 다음과 같습니다.
bazel cquery "function(//target)"
쿼리 표현식 "function(//target)"
은 다음과 같이 구성됩니다.
function(...)
은 타겟에서 실행할 함수입니다.cquery
는query
의 함수 대부분과 몇 가지 새로운 함수를 지원합니다.//target
은 함수에 제공되는 표현식입니다. 이 예에서 표현식은 간단한 타겟입니다. 하지만 쿼리 언어에서는 함수를 중첩할 수도 있습니다. 예는 쿼리 가이드를 참고하세요.
cquery
에는 로드 및 분석 단계를 실행할 타겟이 필요합니다. 달리 지정하지 않으면 cquery
은 쿼리 표현식에 나열된 타겟을 파싱합니다. 최상위 빌드 타겟의 종속 항목을 쿼리하려면 --universe_scope
을 참고하세요.
구성
다음 행은,
//tree:ash (9f87702)
//tree:ash
이 ID가 9f87702
인 구성으로 빌드되었음을 의미합니다. 대부분의 타겟의 경우 이는 구성을 정의하는 빌드 옵션 값의 불투명 해시입니다.
구성의 전체 콘텐츠를 확인하려면 다음을 실행하세요.
$ bazel config 9f87702
9f87702
는 전체 ID의 접두사입니다. 완전한 ID는 SHA-256 해시로, 길고 추적하기 어렵기 때문입니다. cquery
는 Git 짧은 해시와 마찬가지로 완전한 ID의 유효한 접두사를 이해합니다.
전체 ID를 확인하려면 $ bazel config
을 실행합니다.
타겟 패턴 평가
//foo
의 의미는 query
와 cquery
에서 다릅니다. 이는 cquery
가 구성된 타겟을 평가하고 빌드 그래프에 구성된 //foo
버전이 여러 개 있을 수 있기 때문입니다.
cquery
의 경우 쿼리 표현식의 타겟 패턴은 해당 패턴과 일치하는 라벨이 있는 모든 구성된 타겟으로 평가됩니다. 출력은 결정적이지만 cquery
는 핵심 쿼리 순서 지정 계약을 넘어 순서를 보장하지 않습니다.
이렇게 하면 query
을 사용하는 경우보다 쿼리 표현식에 대해 더 미묘한 결과가 생성됩니다.
예를 들어 다음은 여러 결과를 생성할 수 있습니다.
# Analyzes //foo in the target configuration, but also analyzes # //genrule_with_foo_as_tool which depends on an exec-configured # //foo. So there are two configured target instances of //foo in # the build graph. $ bazel cquery //foo --universe_scope=//foo,//genrule_with_foo_as_tool //foo (9f87702) //foo (exec)
쿼리할 인스턴스를 정확하게 선언하려면 config
함수를 사용하세요.
타겟 패턴에 관한 자세한 내용은 query
의 타겟 패턴 문서를 참고하세요.
함수
query
에서 지원하는 함수 집합 중 cquery
는 allrdeps
, buildfiles
, rbuildfiles
, siblings
, tests
, visible
를 제외한 모든 함수를 지원합니다.
cquery
에서는 다음과 같은 새로운 함수도 도입합니다.
config
expr ::= config(expr, word)
config
연산자는 첫 번째 인수로 표시된 라벨과 두 번째 인수로 지정된 구성에 대해 구성된 타겟을 찾으려고 시도합니다.
두 번째 인수의 유효한 값은 null
또는 맞춤 구성 해시입니다. 해시는 $
bazel config
또는 이전 cquery
의 출력에서 가져올 수 있습니다.
예:
$ bazel cquery "config(//bar, 3732cc8)" --universe_scope=//foo
$ bazel cquery "deps(//foo)" //bar (exec) //baz (exec) $ bazel cquery "config(//baz, 3732cc8)"
첫 번째 인수의 일부 결과를 지정된 구성에서 찾을 수 없는 경우 찾을 수 있는 결과만 반환됩니다. 지정된 구성에서 결과를 찾을 수 없는 경우 쿼리가 실패합니다.
옵션
빌드 옵션
cquery
는 일반 Bazel 빌드에서 실행되므로 빌드 중에 사용할 수 있는 옵션 집합을 상속합니다.
cquery 옵션 사용
--universe_scope
(쉼표로 구분된 목록)
구성된 타겟의 종속 항목은 전환을 거치는 경우가 많으며, 이로 인해 구성이 종속 항목과 달라집니다. 이 플래그를 사용하면 타겟이 다른 타겟의 종속 항목 또는 전이 종속 항목으로 빌드된 것처럼 타겟을 쿼리할 수 있습니다. 예를 들면 다음과 같습니다.
# x/BUILD genrule( name = "my_gen", srcs = ["x.in"], outs = ["x.cc"], cmd = "$(locations :tool) $< >$@", tools = [":tool"], ) cc_binary( name = "tool", srcs = ["tool.cpp"], )
genrule은 실행 구성에서 도구를 구성하므로 다음 쿼리는 다음 출력을 생성합니다.
쿼리 | 타겟 빌드됨 | 출력 |
---|---|---|
bazel cquery "//x:tool" | //x:tool | //x:tool(targetconfig) |
bazel cquery "//x:tool" --universe_scope="//x:my_gen" | //x:my_gen | //x:tool(execconfig) |
이 플래그가 설정되면 콘텐츠가 빌드됩니다. 설정되지 않은 경우 쿼리 표현식에 언급된 모든 타겟이 대신 빌드됩니다. 빌드된 타겟의 전이적 폐쇄는 쿼리의 유니버스로 사용됩니다. 어떤 경우든 빌드할 타겟은 최상위 수준에서 빌드할 수 있어야 합니다 (즉, 최상위 수준 옵션과 호환되어야 함). cquery
는 이러한 최상위 타겟의 전이적 폐쇄에서 결과를 반환합니다.
최상위 수준의 쿼리 표현식에서 모든 타겟을 빌드할 수 있더라도 그렇게 하지 않는 것이 유익할 수 있습니다. 예를 들어 --universe_scope
를 명시적으로 설정하면 신경 쓰지 않는 구성에서 타겟을 여러 번 빌드하지 않을 수 있습니다. 또한 원하는 타겟의 구성 버전을 지정하는 데도 도움이 될 수 있습니다. 쿼리 표현식이 deps(//foo)
보다 복잡한 경우 이 플래그를 설정해야 합니다.
--implicit_deps
(불리언, 기본값=True)
이 플래그를 false로 설정하면 BUILD 파일에 명시적으로 설정되지 않고 Bazel에 의해 다른 곳에 설정된 모든 결과가 필터링됩니다. 여기에는 확인된 도구 모음 필터링이 포함됩니다.
--tool_deps
(불리언, 기본값=True)
이 플래그를 false로 설정하면 쿼리된 타겟에서 해당 타겟까지의 경로가 타겟 구성과 비타겟 구성 간의 전환을 교차하는 모든 구성된 타겟이 필터링됩니다. 쿼리된 타겟이 타겟 구성에 있는 경우 --notool_deps
을 설정하면 타겟 구성에 있는 타겟만 반환됩니다. 쿼리된 타겟이 타겟이 아닌 구성에 있는 경우 --notool_deps
를 설정하면 타겟이 아닌 구성에 있는 타겟만 반환됩니다. 이 설정은 일반적으로 해결된 도구 모음 필터링에 영향을 미치지 않습니다.
--include_aspects
(불리언, 기본값=True)
관점에서 추가한 종속 항목을 포함합니다.
이 플래그가 사용 중지되면 cquery somepath(X, Y)
및 cquery deps(X) | grep 'Y'
은 X가 측면을 통해서만 Y에 종속되는 경우 Y를 생략합니다.
출력 형식
기본적으로 cquery는 라벨 및 구성 쌍의 종속 항목 순서 목록으로 결과를 출력합니다. 결과를 노출하는 다른 옵션도 있습니다.
화면전환
--transitions=lite --transitions=full
구성 전환은 최상위 타겟과 다른 구성으로 최상위 타겟 아래에 타겟을 빌드하는 데 사용됩니다.
예를 들어 타겟은 tools
속성의 모든 종속 항목에 exec 구성으로의 전환을 적용할 수 있습니다. 이를 속성 전환이라고 합니다. 규칙은 규칙 클래스 전환이라고 하는 자체 구성에 전환을 적용할 수도 있습니다. 이 출력 형식은 이러한 전환에 관한 정보(예: 유형 및 빌드 옵션에 미치는 영향)를 출력합니다.
이 출력 형식은 기본적으로 NONE
로 설정된 --transitions
플래그에 의해 트리거됩니다. FULL
또는 LITE
모드로 설정할 수 있습니다. FULL
모드는 전환 전후 옵션의 자세한 차이를 포함하여 규칙 클래스 전환 및 속성 전환에 관한 정보를 출력합니다. LITE
모드는 옵션 차이 없이 동일한 정보를 출력합니다.
프로토콜 메시지 출력
--output=proto
이 옵션을 사용하면 결과 타겟이 바이너리 프로토콜 버퍼 형식으로 출력됩니다. 프로토콜 버퍼의 정의는 src/main/protobuf/analysis_v2.proto에서 확인할 수 있습니다.
CqueryResult
는 cquery 결과를 포함하는 최상위 메시지입니다. ConfiguredTarget
메시지 목록과 Configuration
메시지 목록이 있습니다. 각 ConfiguredTarget
에는 값이 해당 Configuration
메시지의 id
필드 값과 동일한 configuration_id
이 있습니다.
--[no]proto:include_configurations
기본적으로 cquery 결과는 구성된 각 타겟의 일부로 구성 정보를 반환합니다. 이 정보를 생략하고 쿼리의 프로토 출력과 정확히 동일한 형식의 프로토 출력을 가져오려면 이 플래그를 false로 설정하세요.
프로토 출력 관련 옵션에 관한 자세한 내용은 쿼리의 프로토 출력 문서를 참고하세요.
그래프 출력
--output=graph
이 옵션은 Graphviz와 호환되는 .dot 파일로 출력을 생성합니다. 자세한 내용은 query
의 그래프 출력 문서를 참고하세요. cquery
는 --graph:node_limit
및 --graph:factored
도 지원합니다.
파일 출력
--output=files
이 옵션은 쿼리와 일치하는 각 타겟에서 생성된 출력 파일 목록을 bazel build
호출 끝에 출력되는 목록과 유사하게 출력합니다. 출력에는 --output_groups
플래그에 따라 요청된 출력 그룹에 광고된 파일만 포함됩니다.
소스 파일은 포함됩니다.
이 출력 형식에서 내보낸 모든 경로는 bazel info execution_root
를 통해 가져올 수 있는 execroot을 기준으로 합니다. bazel-out
편의 심볼릭 링크가 있으면 기본 저장소의 파일 경로도 작업공간 디렉터리를 기준으로 확인됩니다.
Starlark를 사용하여 출력 형식 정의
--output=starlark
이 출력 형식은 쿼리 결과에서 구성된 각 타겟에 대해 Starlark 함수를 호출하고 호출에서 반환된 값을 출력합니다. --starlark:file
플래그는 단일 매개변수 target
로 format
이라는 함수를 정의하는 Starlark 파일의 위치를 지정합니다. 이 함수는 쿼리 결과의 각 타겟에 대해 호출됩니다. 또는 편의를 위해 --starlark:expr
플래그를 사용하여 def format(target): return expr
로 선언된 함수의 본문만 지정할 수 있습니다.
'cquery' Starlark 언어
cquery Starlark 환경은 BUILD 또는 .bzl 파일과 다릅니다. 여기에는 모든 핵심 Starlark 내장 상수 및 함수와 아래에 설명된 몇 가지 cquery 전용 함수가 포함되지만 glob
, native
, rule
등은 포함되지 않으며 load 문은 지원되지 않습니다.
build_options(target)
build_options(target)
는 키가 빌드 옵션 식별자(구성 참고)이고 값이 Starlark 값인 맵을 반환합니다. 값이 유효한 Starlark 값이 아닌 빌드 옵션은 이 맵에서 생략됩니다.
타겟이 입력 파일인 경우 입력 파일 타겟에는 null 구성이 있으므로 build_options(target)
는 None을 반환합니다.
providers(target)
providers(target)
는 키가 제공자(예: "DefaultInfo"
)의 이름이고 값이 Starlark 값인 맵을 반환합니다.
값이 유효한 Starlark 값이 아닌 제공자는 이 맵에서 생략됩니다.
예
//foo
에서 생성된 모든 파일의 기본 이름을 공백으로 구분된 목록으로 출력합니다.
bazel cquery //foo --output=starlark \ --starlark:expr="' '.join([f.basename for f in providers(target)['DefaultInfo'].files.to_list()])"
//bar
및 하위 패키지에 있는 rule 타겟에서 생성된 모든 파일의 경로를 공백으로 구분된 목록으로 출력합니다.
bazel cquery 'kind(rule, //bar/...)' --output=starlark \ --starlark:expr="' '.join([f.path for f in providers(target)['DefaultInfo'].files.to_list()])"
//foo
에 의해 등록된 모든 작업의 니모닉 목록을 출력합니다.
bazel cquery //foo --output=starlark \ --starlark:expr="[a.mnemonic for a in target.actions]"
cc_library
//baz
에 의해 등록된 컴파일 출력 목록을 출력합니다.
bazel cquery //baz --output=starlark \ --starlark:expr="[f.path for f in target.output_groups.compilation_outputs.to_list()]"
//foo
빌드 시 명령줄 옵션 --javacopt
의 값을 출력합니다.
bazel cquery //foo --output=starlark \ --starlark:expr="build_options(target)['//command_line_option:javacopt']"
출력이 하나인 각 타겟의 라벨을 출력합니다. 이 예시에서는 파일에 정의된 Starlark 함수를 사용합니다.
$ cat example.cquery def has_one_output(target): return len(providers(target)["DefaultInfo"].files.to_list()) == 1 def format(target): if has_one_output(target): return target.label else: return "" $ bazel cquery //baz --output=starlark --starlark:file=example.cquery
엄격하게 Python 3인 각 타겟의 라벨을 출력합니다. 이 예시에서는 파일에 정의된 Starlark 함수를 사용합니다.
$ cat example.cquery def format(target): p = providers(target) py_info = p.get("PyInfo") if py_info and py_info.has_py3_only_sources: return target.label else: return "" $ bazel cquery //baz --output=starlark --starlark:file=example.cquery
사용자 정의 제공자에서 값을 추출합니다.
$ cat some_package/my_rule.bzl MyRuleInfo = provider(fields={"color": "the name of a color"}) def _my_rule_impl(ctx): ... return [MyRuleInfo(color="red")] my_rule = rule( implementation = _my_rule_impl, attrs = {...}, ) $ cat example.cquery def format(target): p = providers(target) my_rule_info = p.get("//some_package:my_rule.bzl%MyRuleInfo'") if my_rule_info: return my_rule_info.color return "" $ bazel cquery //baz --output=starlark --starlark:file=example.cquery
cquery와 query의 차이
cquery
와 query
는 서로를 보완하며 서로 다른 틈새시장에서 뛰어납니다. 다음 사항을 고려하여 적합한 옵션을 선택하세요.
cquery
은 특정select()
브랜치를 따라 사용자가 빌드하는 정확한 그래프를 모델링합니다.query
는 빌드에서 선택하는 브랜치를 알지 못하므로 모든 브랜치를 포함하여 과도하게 근사합니다.cquery
의 정밀도를 위해서는query
보다 더 많은 그래프를 빌드해야 합니다. 구체적으로cquery
는 구성된 타겟을 평가하는 반면query
는 타겟만 평가합니다. 이렇게 하면 시간이 더 오래 걸리고 메모리를 더 많이 사용합니다.cquery
의 질의 언어 해석에는query
에서 피하는 모호성이 도입됩니다. 예를 들어"//foo"
이 두 구성에 있는 경우cquery "deps(//foo)"
은 어떤 구성을 사용해야 할까요?config
함수를 사용하면 이 작업을 수행할 수 있습니다.
비확정적 출력
cquery
는 이전 명령어에서 빌드 그래프를 자동으로 삭제하지 않습니다.
따라서 이전 쿼리의 결과를 선택하기 쉽습니다.
예를 들어 genrule
는 tools
속성에 exec 전환을 적용합니다. 즉, exec 구성에서 도구를 구성합니다.
아래에서 이러한 전환의 지속적인 영향을 확인할 수 있습니다.
$ cat > foo/BUILD <<평가하려는 항목에 따라 바람직한 동작일 수도 있고 아닐 수도 있습니다.
이를 사용 중지하려면
cquery
전에blaze clean
를 실행하여 새로운 분석 그래프를 확인하세요.문제 해결
재귀 타겟 패턴 (
/...
)다음과 같은 문제가 발생하면
$ bazel cquery --universe_scope=//foo:app "somepath(//foo:app, //foo/...)" ERROR: Error doing post analysis query: Evaluation failed: Unable to load package '[foo]' because package is not in scope. Check that all target patterns in query expression are within the --universe_scope of this query.
--universe_scope=//foo:app
에 포함되어 있는데도 패키지//foo
가 범위에 포함되지 않는다고 잘못 제안합니다. 이는cquery
의 설계 제한 때문입니다. 이 문제를 해결하려면 유니버스 범위에//foo/...
를 명시적으로 포함하세요. $ bazel cquery --universe_scope=//foo:app,//foo/... "somepath(//foo:app, //foo/...)"이 방법이 작동하지 않는 경우 (예: 선택한 빌드 플래그로
//foo/...
의 일부 타겟을 빌드할 수 없는 경우) 전처리 쿼리를 사용하여 패턴을 구성 패키지로 수동으로 래핑 해제합니다. # Replace "//foo/..." with a subshell query call (not cquery!) outputting each package, piped into # a sed call converting "<pkg>" to "//<pkg>:*", piped into a "+"-delimited line merge. # Output looks like "//foo:*+//foo/bar:*+//foo/baz". # $ bazel cquery --universe_scope=//foo:app "somepath(//foo:app, $(bazel query //foo/... --output=package | sed -e 's/^/\/\//' -e 's/$/:*/' | paste -sd "+" -))"