Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,8 @@ exports_files(
["MODULE.bazel"],
visibility = ["//test/buildifier:__pkg__"],
)

exports_files(
["requirements_lock.txt"],
visibility = ["//visibility:public"],
)
16 changes: 16 additions & 0 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,22 @@ codechecker_extension = use_extension(
)
use_repo(codechecker_extension, "default_codechecker_tools")

# pip-based CodeChecker: hermetic installation via rules_python
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
is_default = True,
python_version = "3.12",
)

pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
pip.parse(
hub_name = "pip",
python_version = "3.12",
requirements_lock = "//:requirements_lock.txt",
)
use_repo(pip, "pip")
Comment on lines +54 to +60

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is how it should be done


register_toolchains(
"//src:codechecker_pip_toolchain",
"//:default_toolchain",
)
47 changes: 47 additions & 0 deletions requirements_lock.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
alembic==1.19.1

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OMG, is all of this hm.. stuff really needed for CodeChecker?

argcomplete==3.7.2
authlib==1.7.2
certifi==2026.7.22
cffi==2.1.1
charset-normalizer==3.5.0
codechecker==6.28.0
contourpy==1.3.3
cryptography==50.0.0
cycler==0.12.1
dill==0.4.1
fonttools==4.63.0
gitdb==4.0.12
gitpython==3.1.59
greenlet==3.5.5
idna==3.18
jinja2==3.1.6
joserfc==1.7.4
jsonpath-ng==1.8.0
kiwisolver==1.5.0
lxml==6.1.1
mako==1.4.1
markupsafe==3.0.3
matplotlib==3.11.1
multiprocess==0.70.19
numpy==2.5.2
packaging==26.3
pillow==12.3.0
portalocker==3.2.0
psutil==7.2.2
pycparser==3.0
pyparsing==3.3.2
python-dateutil==2.9.0.post0
python-docx==1.2.0
pyyaml==6.0.3
requests==2.34.2
sarif-tools==3.0.5
semver==3.0.4
six==1.17.0
smmap==5.0.3
sqlalchemy==2.0.52
thrift==0.24.0
types-psutil==7.2.2.20260518
types-pyyaml==6.0.12.20260724
typing-extensions==4.16.0
urllib3==2.7.0
setuptools==80.9.0
32 changes: 31 additions & 1 deletion src/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,15 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
load("@rules_python//python:py_binary.bzl", "py_binary")
load(
"@rules_python//python:py_binary.bzl",
"py_binary",
)
load(
"@rules_python//python/entry_points:py_console_script_binary.bzl",
"py_console_script_binary",
)
load(":codechecker_toolchain.bzl", "codechecker_toolchain")

# Tool filter compile_commands.json file
py_binary(
Expand Down Expand Up @@ -65,3 +73,25 @@ label_flag(
build_setting_default = ":clang_tidy_additional_deps_default",
visibility = ["//visibility:public"],
)

# Hermetic pip-based CodeChecker toolchain (uses rules_python pip package)
py_console_script_binary(
name = "CodeChecker",
data = ["@pip//codechecker:data"],
pkg = "@pip//codechecker",
script = "CodeChecker",
visibility = ["//visibility:public"],
)

codechecker_toolchain(
name = "codechecker_pip",
clang_tidy = "@default_codechecker_tools//:clang_tidy",
clangsa = "@default_codechecker_tools//:clang",
codechecker = ":CodeChecker",
)

toolchain(
name = "codechecker_pip_toolchain",
toolchain = ":codechecker_pip",
toolchain_type = "//:toolchain_type",
)
13 changes: 13 additions & 0 deletions src/codechecker.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,18 @@ def _codechecker_impl(ctx):
else:
info = ctx.toolchains["//:toolchain_type"].codecheckerinfo

# Derive CC_BIN_DIR so pip-installed CodeChecker can find its data dir.
# CodeChecker resolves its config as dirname(CC_BIN_DIR) which must
# contain config/, ld_logger/, etc. The pip wheel places these under
# data/share/codechecker/. We scan the toolchain runfiles for that path.
for f in info.runfiles.to_list():
idx = f.path.find("data/share/codechecker/")
if idx >= 0:
cc_bin_dir = f.path[:idx] + "data/share/codechecker/bin"
cc_bin_env = "CC_BIN_DIR=" + cc_bin_dir
codechecker_env = (codechecker_env + "; " + cc_bin_env) if codechecker_env else cc_bin_env
break

codechecker_files = ctx.actions.declare_directory(ctx.label.name + "/codechecker-files")

codechecker_script = ctx.actions.declare_file(ctx.label.name + "/codechecker_script")
Expand Down Expand Up @@ -128,6 +140,7 @@ def _codechecker_impl(ctx):
),
tools = [
info.runfiles,
info.codechecker_files_to_run,
ctx.attr._codechecker_script[DefaultInfo].files_to_run,
],
outputs = [
Expand Down
4 changes: 4 additions & 0 deletions src/codechecker_toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ CodeCheckerInfo = provider(
"clang_tidy": "clang-tidy executable",
"clangsa": "Clang executable",
"codechecker": "CodeChecker executable",
"codechecker_files_to_run": "FilesToRunProvider for the CodeChecker executable. " +
"Pass to `tools` in ctx.actions.run so that Bazel " +
"creates the .runfiles tree in the sandbox.",
"runfiles": "Depset of files needed to run the tools: the three executables " +
"plus their transitive data_runfiles. Pass to `tools` in " +
"ctx.actions.run and include in test runfiles.",
Expand All @@ -33,6 +36,7 @@ def _codechecker_toolchain_impl(ctx):
toolchain_info = platform_common.ToolchainInfo(
codecheckerinfo = CodeCheckerInfo(
codechecker = ctx.executable.codechecker,
codechecker_files_to_run = ctx.attr.codechecker[DefaultInfo].files_to_run,
clang_tidy = ctx.executable.clang_tidy,
clangsa = ctx.executable.clangsa,
runfiles = runfiles,
Expand Down
23 changes: 22 additions & 1 deletion src/per_file.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ def _run_code_checker(
analyzer_executables = "clangsa:" + info.clangsa.path + \
";clang-tidy:" + info.clang_tidy.path

# Derive CC_BIN_DIR so pip-installed CodeChecker can find its data dir.
action_env = {}
for f in info.runfiles.to_list():
idx = f.path.find("data/share/codechecker/")
if idx >= 0:
action_env["CC_BIN_DIR"] = f.path[:idx] + "data/share/codechecker/bin"
break

# Action to run CodeChecker for a file
# env_vars are unused for now, since
# use_default_shell_env and env are incompatible
Expand All @@ -104,8 +112,10 @@ def _run_code_checker(
executable = per_file_script,
tools = [
info.runfiles,
info.codechecker_files_to_run,
ctx.attr._per_file_script[DefaultInfo].files_to_run,
],
env = action_env,
arguments = [
"--codechecker",
info.codechecker.path,
Expand Down Expand Up @@ -230,17 +240,28 @@ def _per_file_impl(ctx):
sources_and_headers,
)
all_files += outputs

# Derive CC_BIN_DIR for the test script so CodeChecker parse can find config
cc_bin_dir_export = ""
for f in info.runfiles.to_list():
idx = f.short_path.find("data/share/codechecker/")
if idx >= 0:
# In test runfiles, short_path for external repos starts with ../
cc_bin_dir_export = 'export CC_BIN_DIR="$TEST_SRCDIR/_main/' + f.short_path[:idx] + 'data/share/codechecker/bin"'
break

ctx.actions.write(
output = ctx.outputs.test_script,
is_executable = True,
content = """
{cc_bin_dir_export}
DATA_DIR=$(dirname {dirname})
# ls -la $DATA_DIR/data
# find $DATA_DIR/data -name *.plist -exec sed -i -e "s|<string>.*execroot/codechecker_bazel/|<string>|g" {{}} \\;
# cat $DATA_DIR/data/test-src-lib.cc_clangsa.plist
echo "Running: CodeChecker parse $DATA_DIR/data"
$(realpath {codechecker}) parse $DATA_DIR/data
""".format(dirname = ctx.outputs.test_script.short_path, codechecker = info.codechecker.short_path),
""".format(dirname = ctx.outputs.test_script.short_path, codechecker = info.codechecker.short_path, cc_bin_dir_export = cc_bin_dir_export),
)
files = depset(
direct = all_files,
Expand Down
6 changes: 6 additions & 0 deletions test/foss/foss_test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@
path = "{rules_path}",
)
bazel_dep(name = "rules_codechecker")
bazel_dep(name = "rules_python", version = "0.40.0")
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
is_default = True,
python_version = "3.12",
)
"""

BUILD_TEMPLATE = """
Expand Down
7 changes: 7 additions & 0 deletions test/unit/caching/caching_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,18 @@
module(name = "caching_test_workspace")

bazel_dep(name = "rules_cc", version = "0.2.3")
bazel_dep(name = "rules_python", version = "0.40.0")
bazel_dep(name = "rules_codechecker")
local_path_override(
module_name = "rules_codechecker",
path = "{rules_codechecker_path}",
)

python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
is_default = True,
python_version = "3.12",
)
"""

BUILD_BAZEL = """\
Expand Down
7 changes: 7 additions & 0 deletions test/unit/external_repository/MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,10 @@ local_path_override(

bazel_dep(name = "external_lib")
bazel_dep(name = "rules_cc", version = "0.2.17")
bazel_dep(name = "rules_python", version = "0.40.0")

python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
is_default = True,
python_version = "3.12",
)
Loading