작업 그래프 쿼리 (aquery)

컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.
문제 신고 출처 보기

aquery 명령어를 사용하면 빌드 그래프에서 작업을 쿼리할 수 있습니다. 분석 후 구성된 타겟 그래프에서 작동하며 작업, 아티팩트 및 그 관계에 대한 정보를 제공합니다.

aquery는 구성된 타겟 그래프에서 생성된 작업/아티팩트의 속성에 관심이 있는 경우 유용합니다. 예를 들어 실제 명령어 실행과 입력/출력/니모닉 등이 있습니다.

이 도구는 몇 가지 명령줄 옵션을 허용합니다. 특히, 쿼리 명령어는 일반 Bazel 빌드 위에서 실행되며 빌드 중에 사용 가능한 옵션 집합을 상속합니다.

기존 query에도 사용할 수 있는 것과 동일한 함수 집합을 지원하지만 siblings, buildfiles, tests도 지원합니다.

aquery 출력 예 (구체적인 세부정보 없음):

$ bazel aquery 'deps(//some:label)'
action 'Writing file some_file_name'
  Mnemonic: ...
  Target: ...
  Configuration: ...
  ActionKey: ...
  Inputs: [...]
  Outputs: [...]

기본 구문

aquery 구문의 간단한 예시는 다음과 같습니다.

bazel aquery "aquery_function(function(//target))"

쿼리 표현식 (따옴표)은 다음으로 구성됩니다.

  • aquery_function(...): aquery과 관련된 함수입니다. 자세한 내용은 아래를 참조하세요.
  • function(...): 기존 query과 같은 표준 함수입니다.
  • //target는 원하는 타겟의 라벨입니다.
# aquery examples:
# Get the action graph generated while building //src/target_a
$ bazel aquery '//src/target_a'

# Get the action graph generated while building all dependencies of //src/target_a
$ bazel aquery 'deps(//src/target_a)'

# Get the action graph generated while building all dependencies of //src/target_a
# whose inputs filenames match the regex ".*cpp".
$ bazel aquery 'inputs(".*cpp", deps(//src/target_a))'

쿼리 함수 사용

다음과 같은 세 가지 aquery 함수가 있습니다.

  • inputs: 입력별로 작업을 필터링합니다.
  • outputs: 출력별로 작업 필터링
  • mnemonic: 니모닉을 기준으로 작업 필터링

expr ::= inputs(word, expr)

inputs 연산자는 expr를 빌드하여 생성된 작업을 반환하며 입력 파일 이름은 word에서 제공하는 정규식과 일치합니다.

$ bazel aquery 'inputs(".*cpp", deps(//src/target_a))'

outputsmnemonic 함수도 비슷한 구문을 공유합니다.

함수를 결합하여 AND 연산을 수행할 수도 있습니다. 예를 들면 다음과 같습니다.

  $ bazel aquery 'mnemonic("Cpp.*", (inputs(".*cpp", inputs("foo.*", //src/target_a))))'

위의 명령어는 연상 기법이 "Cpp.*"와 일치하고 입력이 ".*cpp""foo.*" 패턴과 일치하는 //src/target_a 빌드와 관련된 모든 작업을 찾습니다.

생성된 구문 오류의 예는 다음과 같습니다.

        $ bazel aquery 'deps(inputs(".*cpp", //src/target_a))'
        ERROR: aquery filter functions (inputs, outputs, mnemonic) produce actions,
        and therefore can't be the input of other function types: deps
        deps(inputs(".*cpp", //src/target_a))

옵션

빌드 옵션

aquery는 일반 Bazel 빌드 위에서 실행되므로 빌드 중에 사용할 수 있는 옵션 집합을 상속합니다.

쿼리 옵션

--output=(text|summary|proto|jsonproto|textproto), default=text

기본 출력 형식(text)은 사람이 읽을 수 있습니다. 컴퓨터가 읽을 수 있는 형식에는 proto, textproto 또는 jsonproto를 사용하세요. proto 메시지는 analysis.ActionGraphContainer입니다.

--include_commandline, default=true

출력에 작업 명령줄의 콘텐츠를 포함합니다 (크기가 클 수 있음).

--include_artifacts, default=true

출력에 있는 작업 입력 및 출력의 이름을 포함합니다 (크기가 클 수 있음).

--include_aspects, default=true

출력에 가로세로로 생성된 작업을 포함할지 여부입니다.

--include_param_files, default=false

명령어에 사용된 매개변수 파일의 콘텐츠를 포함합니다 (크기가 클 수 있음).

--include_file_write_contents, default=false

actions.write() 작업의 파일 콘텐츠와 SourceSymlinkManifest 작업의 매니페스트 파일 콘텐츠를 포함합니다. 파일 콘텐츠는 file_contents 필드에서 --output=xxxproto로 반환됩니다. --output=text를 사용하면 출력에 FileWriteContents: [<base64-encoded file contents>] 줄이 있습니다.

--skyframe_state, default=false

추가 분석을 수행하지 않고 Skyframe에서 액션 그래프를 덤프합니다.

기타 도구 및 기능

Skyframe의 상태에 대한 쿼리

Skyframe은 Bazel의 평가 및 성과 증분 모델입니다. Bazel 서버의 각 인스턴스에서 Skyframe은 Analysis 단계의 이전 실행에서 구성된 종속 항목 그래프를 저장합니다.

경우에 따라 Skyframe에서 액션 그래프를 쿼리하는 것이 유용합니다. 사용 사례는 다음과 같습니다.

  1. bazel build //target_a 실행
  2. bazel build //target_b 실행
  3. foo.out 파일이 생성되었습니다.

Bazel 사용자로서 foo.out//target_a 또는 //target_b 빌드에서 생성되었는지 확인하고 싶습니다.

bazel aquery 'outputs("foo.out", //target_a)'bazel aquery 'outputs("foo.out", //target_b)'를 실행하여 foo.out 생성을 담당하는 작업을 파악하고 대상을 지정할 수 있습니다. 그러나 이전에 빌드된 다른 대상의 수는 2보다 클 수 있으므로 여러 aquery 명령어를 실행하는 것이 번거로울 수 있습니다.

대신 --skyframe_state 플래그를 사용할 수 있습니다.

  # List all actions on Skyframe's action graph
  $ bazel aquery --output=proto --skyframe_state

  # or

  # List all actions on Skyframe's action graph, whose output matches "foo.out"
  $ bazel aquery --output=proto --skyframe_state 'outputs("foo.out")'

--skyframe_state 모드를 사용하면 aquery가 Skyframe이 Bazel의 인스턴스에 보관하는 작업 그래프의 콘텐츠를 취하며(선택사항) 필터링을 수행하여 분석 단계를 다시 실행하지 않고 콘텐츠를 출력합니다.

특별 고려사항

출력 형식

--skyframe_state는 현재 --output=proto--output=textproto에만 사용할 수 있습니다.

쿼리 표현식에 대상 라벨이 포함되지 않음

현재 --skyframe_state는 대상에 관계없이 Skyframe에 존재하는 전체 작업 그래프를 쿼리합니다. 쿼리에 --skyframe_state와 함께 대상 라벨이 지정되어 있으면 구문 오류로 간주됩니다.

  # WRONG: Target Included
  $ bazel aquery --output=proto --skyframe_state **//target_a**
  ERROR: Error while parsing '//target_a)': Specifying build target(s) [//target_a] with --skyframe_state is currently not supported.

  # WRONG: Target Included
  $ bazel aquery --output=proto --skyframe_state 'inputs(".*.java", **//target_a**)'
  ERROR: Error while parsing '//target_a)': Specifying build target(s) [//target_a] with --skyframe_state is currently not supported.

  # CORRECT: Without Target
  $ bazel aquery --output=proto --skyframe_state
  $ bazel aquery --output=proto --skyframe_state 'inputs(".*.java")'

쿼리 출력 비교

aquery_differ 도구를 사용하여 서로 다른 두 쿼리 호출의 결과를 비교할 수 있습니다. 예를 들어 규칙 정의를 변경하고 실행 중인 명령줄이 변경되지 않았는지 확인하려면 이를 위한 도구는 aquery_differ입니다.

이 도구는 bazelbuild/bazel 저장소에서 사용할 수 있습니다. 사용하려면 저장소를 로컬 머신에 클론하세요. 사용 예는 다음과 같습니다.

  $ bazel run //tools/aquery_differ -- \
  --before=/path/to/before.proto \
  --after=/path/to/after.proto \
  --input_type=proto \
  --attrs=cmdline \
  --attrs=inputs

위 명령어는 before 쿼리 출력과 after 쿼리 출력의 차이를 반환합니다. 즉, 어떤 작업은 존재하고 다른 작업은 발생하지 않으며 어떤 작업은 각 쿼리 출력에서 서로 다른 명령줄/입력을 갖는지 등의 결과를 반환합니다. 위 명령어를 실행하면 다음과 같은 결과가 발생합니다.

  Aquery output 'after' change contains an action that generates the following outputs that aquery output 'before' change doesn't:
  ...
  /list of output files/
  ...

  [cmdline]
  Difference in the action that generates the following output(s):
    /path/to/abc.out
  --- /path/to/before.proto
  +++ /path/to/after.proto
  @@ -1,3 +1,3 @@
    ...
    /cmdline diff, in unified diff format/
    ...

명령어 옵션

--before, --after: 비교할 쿼리 출력 파일

--input_type=(proto|text_proto), default=proto: 입력 파일의 형식입니다. prototextproto 쿼리 출력이 지원됩니다.

--attrs=(cmdline|inputs), default=cmdline: 비교할 작업의 속성입니다.

관점

다양한 측면은 위에 적용할 수 있습니다. 이러한 Aspect에서 생성된 작업의 쿼리 출력에는 작업을 생성한 대상에 적용된 Aspect 시퀀스인 Aspect path가 포함됩니다.

가로 모드 중심의 예:

  t0
  ^
  | <- a1
  t1
  ^
  | <- a2
  t2

ti를 종속 항목에 i를 적용하는 규칙 ri의 대상으로 하겠습니다.

타겟 t0에 적용할 때 a2가 액션 X를 생성한다고 가정해 보겠습니다. 작업 X에 대한 bazel aquery --include_aspects 'deps(//t2)'의 텍스트 출력은 다음과 같습니다.

  action ...
  Mnemonic: ...
  Target: //my_pkg:t0
  Configuration: ...
  AspectDescriptors: [//my_pkg:rule.bzl%**a2**(foo=...)
    -> //my_pkg:rule.bzl%**a1**(bar=...)]
  ...

즉, a1(t0)에 적용된 가로세로 a2에 의해 X 작업이 생성되었습니다. 여기서 a1(t0)은 대상 t0에 적용된 가로세로 a1의 결과입니다.

AspectDescriptor의 형식은 다음과 같습니다.

  AspectClass([param=value,...])

AspectClass는 Aspect 클래스 (네이티브 Aspect) 또는 bzl_file%aspect_name (Starlark Aspect) 이름입니다. AspectDescriptor종속 항목 그래프의 토폴로지 순서로 정렬됩니다.

JSON 프로필로 연결

쿼리는 빌드에서 실행 중인 작업 (실행 중인 이유, 입력/출력)에 대한 정보를 제공하지만 JSON 프로필은 실행 타이밍과 지속 시간을 알려줍니다. 공통 분모인 작업의 기본 출력으로 이 두 가지 정보를 조합할 수 있습니다.

JSON 프로필에 작업 출력을 포함하려면 --experimental_include_primary_output --noexperimental_slim_json_profile를 사용하여 프로필을 생성합니다. 슬림 프로필은 기본 출력 포함과 호환되지 않습니다. 작업의 기본 출력은 기본적으로 쿼리에 포함됩니다.

현재 이 두 데이터 소스를 결합할 수 있는 표준 도구는 제공되지 않지만 위 정보로 직접 스크립트를 빌드할 수 있습니다.

알려진 문제

공유 작업 처리

구성된 대상 간에 작업이 공유되는 경우도 있습니다.

실행 단계에서는 이러한 공유 작업이 하나로 간주되며 한 번만 실행됩니다. 하지만 쿼리는 실행 전, 분석 후 작업 그래프에서 작동하므로 출력 아티팩트가 정확히 동일한 execPath를 갖는 별도의 작업으로 취급됩니다. 따라서 동일한 아티팩트가 중복되어 표시됩니다.

쿼리 문제/계획된 기능 목록은 GitHub에서 찾을 수 있습니다.

FAQ

입력 키는 입력 파일의 콘텐츠가 변경된 경우에도 동일하게 유지됩니다.

쿼리 컨텍스트에서 ActionKeyActionAnalysisMetadata#getKey에서 가져온 String를 참조합니다.

  Returns a string encoding all of the significant behaviour of this Action that might affect the
  output. The general contract of `getKey` is this: if the work to be performed by the
  execution of this action changes, the key must change.

  ...

  Examples of changes that should affect the key are:

  - Changes to the BUILD file that materially affect the rule which gave rise to this Action.
  - Changes to the command-line options, environment, or other global configuration resources
      which affect the behaviour of this kind of Action (other than changes to the names of the
      input/output files, which are handled externally).
  - An upgrade to the build tools which changes the program logic of this kind of Action
      (typically this is achieved by incorporating a UUID into the key, which is changed each
      time the program logic of this action changes).
  Note the following exception: for actions that discover inputs, the key must change if any
  input names change or else action validation may falsely validate.

이때 입력 파일의 내용 변경사항은 제외되고 RemoteCacheClient#ActionKey와 혼동해서는 안 됩니다.

업데이트

문제/기능 요청의 경우 여기에서 문제를 제출해 주세요.