bazel
Edit and validate Bazel build settings using conventions specific to CodeQL development. Follow established helpers for packaging and operating system differences, add dependencies with checksums, and check changed targets while respecting the standalone build setup.
한국어 요약은 준비 중입니다. 영어 요약을 표시하고 있습니다.
원문원문 설명 보기
Conventions for editing Bazel files in the github/codeql repository: the shared `misc/bazel` helpers, `codeql_platform_select` and the `{CODEQL_PLATFORM}` packaging placeholder, adding `MODULE.bazel` dependencies, and the `semmle_code` stub that keeps the standalone build working. Use when editing any `BUILD.bazel`, `*.bzl`, `MODULE.bazel` or `.bazelrc` here, and before validating such an edit.
이럴 때 유용합니다
- Edit CodeQL Bazel build files
- Configure packaging for different operating systems
- Add external build dependencies
- Validate a changed target or package
- Check changes affecting standalone builds
포함된 파일(1)
- SKILL.md10.3 KB
SKILL.md(원문)
설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
Bazel in the codeql repository
A bzlmod module named ql, repo name @codeql (MODULE.bazel). It builds standalone, and is
also consumed by an internal module; standalone builds replace that module with a stub.
Traps
Things that will waste your time or produce a wrong edit here. Read this section even if you skip the rest.
//...does not work.bazel build //..., and evenbazel query //..., fail at the repo root: the patched modules undermisc/bazel/registryare real packages referencing repos that are not visible from the main repo, and.bazelrcnotes separately that transitions break...builds. The error names a registry directory unrelated to your edit, so it is easy to misdiagnose. Validate the specific target or package you changed, not a recursive pattern.- There is no
MODULE.bazel.lock, deliberately..bazelrcsets--lockfile_mode=offbecause the workspace-relative module override makes a lockfile unstable. Do not add one, and do not "fix" its absence. linux_arm64vslinux-arm64. The keyword argument and config setting use an underscore; the platform string substituted into paths and zip names uses a hyphen. They are not interchangeable.- Do not stub your way out of a missing internal dependency. See Building standalone for the one narrow case where extending the stub is correct.
Conventions
- Copy a neighboring target rather than inventing a shape. Packaging is not uniform: some packages use the
codeql_*wrappers, others still usepkg_filesdirectly. Copy the closest working neighbor, and prefer the wrapper for new code. - Pin anything fetched over the network with
sha256orintegrity. Bazel only warns on an unpinned download, so nothing fails loudly, but the build stops being reproducible and a retagged upstream release silently changes what you build.lfs_archiveis the exception: content is pinned by git object. - Format with
bazel run //misc/bazel/buildifier. It rewrites in place, so do not hand-tune formatting. Also wired as apre-commithook (.pre-commit-config.yaml).
Where new code goes
Bazel's own macro / rule / repository-rule distinction applies as usual. What is repo-specific:
| Adding | Goes in |
|---|---|
| a new packaging shape | extend misc/bazel/pkg.bzl, do not fork pkg_files |
| a new OS or arch split | misc/bazel/os.bzl, do not hand-roll a select() over @platforms// |
| a fetch of something external | a repository rule (lfs.bzl, ripunzip.bzl), not a genrule |
| a wrapper used by one language | next to that language (swift/rules.bzl) |
| a wrapper used across languages | misc/bazel/ |
Prefer inline rules in BUILD.bazel. A .bzl file earns its load() only when the shape repeats across packages or a
value must be computed: rust.bzl is worth it because every Rust binary that ships in a
pack must get the same universal-binary wrapper and symbols test, and forgetting either is a release bug. A local
debugging aid opts out and declares a plain rust_binary; see swift-syntax-parse in
unified/swift-syntax-rs/BUILD.bazel. The _gen_binaries list in
go/BUILD.bazel does not earn a .bzl, because it is shared within a single file, where a
local variable does the job.
Macros here are typically a thin public wrapper around a private rule (codeql_csharp_binary, swift_cc_binary). Keep
the rule narrow and the ergonomics in the macro. Each macro decorates the caller's name to mint its helper targets,
for example internal/<name> or single_arch/<name>. Their visibility is that macro's choice (private, package
default, or the caller's own), so read the macro instead of assuming. When an error names a target you cannot find in
any source file, a macro minted it: grep the suffix under misc/bazel/.
Shared helpers
Frequently-used pieces, so you load the existing one instead of rewriting it. Read the file for its actual exports.
load() path | Covers |
|---|---|
//misc/bazel:pkg.bzl | CodeQL packs and packaging |
//misc/bazel:os.bzl | platform and architecture selection |
//misc/bazel:lfs.bzl | on-demand git-LFS repositories |
//misc/bazel:rust.bzl | Rust binary wrapper |
//misc/bazel:csharp.bzl | C# binary/library/test wrappers |
//misc/bazel:utils.bzl | select_os; prefer os.bzl's os_select in new code |
defs.bzl at the root exports codeql_platform for dependent modules. It is not the way to get
the platform string here; use os.bzl.
Platform selection
codeql_platform_select takes one keyword argument per CodeQL platform: linux64,
linux_arm64, osx64 and win64. otherwise supplies the value for whichever of those you leave unset; it is not
a //conditions:default. There is deliberately no fallback from linux_arm64 to linux64. If you only care about
the OS, use os_select, which gives Linux the same value on both architectures and has a posix shorthand for the
shared Linux/macOS value.
In a macro (no ctx) it returns a select():
load("//misc/bazel:os.bzl", "codeql_platform_select")
load("//misc/bazel:pkg.bzl", "codeql_pkg_files")
codeql_pkg_files(
name = "extractor-arch",
exes = codeql_platform_select(
otherwise = ["//unified/extractor"],
win64 = ["//unified/extractor-unsupported-os:extractor"],
),
prefix = "tools/{CODEQL_PLATFORM}",
)
If implementation code needs to branch on the value rather than pass it through, pass ctx and add
OS_DETECTION_ATTRS to the rule's attributes. The value is then resolved eagerly instead of being an opaque select():
load("//misc/bazel:os.bzl", "OS_DETECTION_ATTRS", "os_select")
def _impl(ctx):
ext = os_select(ctx, windows = ".exe", posix = "")
...
my_rule = rule(
implementation = _impl,
attrs = {"src": attr.label()} | OS_DETECTION_ATTRS,
)
Packs
codeql_pack assembles the files that become an extractor pack. See unified/BUILD.bazel
for a minimal complete example and pkg.bzl for the arguments. The non-obvious parts:
{CODEQL_PLATFORM}in a destination path is the routing mechanism, not just a substitution. A path containing it is arch-specific and lands in the per-architecture zip; every other path is common. Soprefix = "tools/{CODEQL_PLATFORM}"both places the file and marks it arch-specific.arch_overridesforces named destinations into the arch-specific part without a placeholder.codeql_pkg_filessplitssrcs(plain) fromexes(mode 755) and rejectsattributes =with an explicit error. Useexesrather than hand-rollingpkg_attributes(mode = "755").pkg_dirsandpkg_symlinksare unsupported and fail at analysis time.codeql_packalso generates an installer and aninstallalias, hencebazel run //unified:install. Passinstaller_alias = Noneif one package defines several packs.codeql_pack_groupexists for bundling packs into distribution zips, but nothing in this repo instantiates it.
Adding a dependency
In order of preference:
- A Bazel Central Registry module. Add a
bazel_depinMODULE.bazel. - A patched upstream module. Add it under
misc/bazel/registry, which.bazelrcputs ahead of the BCR. Put patches inmodules/<repo>/<version>/patches, rename the version with a-codeql.Nsuffix, and runfix.pyto realign the metadata. - A raw archive. Use
http_archiveviause_repo_rule, or a repository rule. Copy an adjacent declaration and keep its checksum field populated.
Vendored Rust crates under misc/bazel/3rdparty are generated. Regenerate with
update_cargo_deps.sh rather than editing, and keep the
use_repo lists in sync, which bazel mod tidy does for module extensions.
Building standalone
MODULE.bazel declares semmle_code with a local_path_override pointing at .., which
resolves when this repo is checked out inside the internal module. .bazelrc, which Bazel reads
when invoked in this workspace, overrides that with a stub. This line is the whole reason a standalone build resolves:
common --override_module=semmle_code=%workspace%/misc/bazel/semmle_code_stub
Do not change either the override path or the local_path_override; they work as a pair.
misc/bazel/semmle_code_stub is an otherwise empty module supplying no-op
versions of the internal helpers that shared .bzl files load unconditionally. That is its only job, and it is small
enough to read.
Extend the stub only when a .bzl file every standalone target loads gains a new internal load(), which breaks
package loading outright, for everyone. Prefer not needing one. Never add a stub so that an internal-only target
appears to build: some targets depend on internal libraries (grep -rl @semmle_code --include=*.bazel finds them) and
are correctly unbuildable here. Unlike a load(), such a dependency only fails when that target is actually requested.
.bazelrc.internal is not read here; it carries settings for the internal build. A
setting needed by both has to be written in both files, with paths differing because this repo sits at a different depth
there.
리뷰
아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
댓글
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.