cquery
는 빌드 그래프에 대한 select()
및 빌드 옵션의 효과를 올바르게 처리하는 query
의 변형입니다.
이러한 효과를 통합하는 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
는 cquery
와 query
의 의미가 다릅니다. 이는 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
는 visible
, siblings
, buildfiles
, tests
를 제외한 나머지를 모두 지원합니다.
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"], )
Genrules는 다음 쿼리가 다음과 같은 출력을 생성하도록 exec 구성에서 도구를 구성합니다.
쿼리 | 구축된 대상 | 출력 |
---|---|---|
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)
가로세로 추가된 종속 항목을 포함합니다.
이 플래그가 사용 중지된 경우 X가 한 측면을 통해서만 Y에 종속되는 경우 cquery somepath(X, Y)
와 cquery deps(X) | grep '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 결과는 구성된 각 대상의 일부로 구성 정보를 반환합니다. 이 정보를 생략하고 쿼리의 proto 출력과 정확히 같은 형식의 proto 출력을 가져오려면 이 플래그를 false로 설정하세요.
proto 출력 관련 옵션에 대해서는 쿼리의 proto 출력 문서를 참조하세요.
그래프 출력
--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 파일의 위치를 지정합니다. 이 함수는 쿼리 결과의 각 Target(대상)에 대해 호출됩니다. 또는 편의를 위해 --starlark:expr
플래그를 사용하여 def format(target): return expr
로 선언된 함수의 본문만 지정할 수도 있습니다.
'cquery' 스타라크 방언
cquery Starlark 환경은 BUILD 또는 .bzl 파일과 다릅니다. 여기에는 모든 핵심 Starlark 기본 제공 상수 및 함수와 아래에 설명된 몇 가지 cquery 관련 상수가 포함되지만 glob
, native
, rule
는 포함되지 않으며 로드 문은 지원되지 않습니다.
build_options(target)
build_options(target)
는 키가 빌드 옵션 식별자 (구성 참고)이고 값이 Starlark 값인 맵을 반환합니다. 값이 유효한 Starlark 값이 아닌 빌드 옵션은 이 맵에서 생략됩니다.
타겟이 입력 파일인 경우 입력 파일 타겟에 null 구성이 있으므로 build_options(target)
는 None을 반환합니다.
제공업체(대상)
providers(target)
은 키가 제공업체의 이름(예: "DefaultInfo"
)이고 값이 Starlark 값인 맵을 반환합니다. 값이 유효한 Starlark 값이 아닌 제공업체는 이 맵에서 생략됩니다.
예
//foo
로 생성된 모든 파일의 기본 이름을 공백으로 구분된 목록으로 출력합니다.
bazel cquery //foo --output=starlark \ --starlark:expr="' '.join([f.basename for f in target.files.to_list()])"
//bar
및 하위 패키지의 rule 대상에 의해 생성된 모든 파일의 경로 목록을 공백으로 구분한 목록을 출력합니다.
bazel cquery 'kind(rule, //bar/...)' --output=starlark \ --starlark:expr="' '.join([f.path for f in target.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']"
정확히 1개의 출력으로 각 대상의 라벨을 출력합니다. 이 예에서는 파일에 정의된 Starlark 함수를 사용합니다.
$ cat example.cquery def has_one_output(target): return len(target.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
는 특정 사용 사례를 지원하지 않습니다. 자세한 내용은 알려진 문제를 참고하세요.
알려진 문제
cquery
'빌드'하는 모든 대상은 구성이 동일해야 합니다.
쿼리를 평가하기 전에 cquery
은 빌드 작업이 실행되는 시점 직전까지 빌드를 트리거합니다. '빌드'하는 대상은 기본적으로 쿼리 표현식에 표시되는 모든 라벨에서 선택됩니다 (--universe_scope
로 재정의할 수 있음). 이러한 라벨에는 구성이 동일해야 합니다.
이러한 규칙은 일반적으로 최상위 '대상' 구성을 공유하지만 규칙은 수신 에지 전환을 통해 자체 구성을 변경할 수 있습니다.
여기서 cquery
가 짧습니다.
해결 방법: 가능하면 --universe_scope
을 더 엄격한 범위로 설정합니다. 예를 들면 다음과 같습니다.
# This command attempts to build the transitive closures of both //foo and # //bar. //bar uses an incoming edge transition to change its --cpu flag. $ bazel cquery 'somepath(//foo, //bar)' ERROR: Error doing post analysis query: Top-level targets //foo and //bar have different configurations (top-level targets with different configurations is not supported) # This command only builds the transitive closure of //foo, under which # //bar should exist in the correct configuration. $ bazel cquery 'somepath(//foo, //bar)' --universe_scope=//foo
--output=xml
는 지원되지 않습니다.
비확정 출력.
cquery
는 이전 명령어에서 빌드 그래프를 자동으로 완전 삭제하지 않으므로 이전 쿼리에서 결과를 가져오기 쉽습니다. 예를 들어 genquery
는 tools
속성에서 exec 전환을 실행합니다. 즉, exec 구성에서 도구를 구성합니다.
아래에서 이러한 전환의 지속적인 영향을 확인할 수 있습니다.
$ cat > foo/BUILD <<<EOF genrule( name = "my_gen", srcs = ["x.in"], outs = ["x.cc"], cmd = "$(locations :tool) $< >$@", tools = [":tool"], ) cc_library( name = "tool", ) EOF $ bazel cquery "//foo:tool" tool(target_config) $ bazel cquery "deps(//foo:my_gen)" my_gen (target_config) tool (exec_config) ... $ bazel cquery "//foo:tool" tool(exec_config)
해결 방법: 시작 옵션을 변경하여 구성된 대상의 재분석을 강제로 적용합니다.
예를 들어, 빌드 명령어에 --test_arg=<whatever>
를 추가합니다.
문제 해결
재귀 대상 패턴 (/...
)
다음과 같은 문제가 발생했다면 다음 단계를 따르세요.
$ 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 "+" -))"