From 805648297502bffd25c9a15b167e4f7d4a4a1110 Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Mon, 1 Sep 2025 16:49:47 +0200 Subject: [PATCH 1/8] Add ccache detection --- src/tools.bzl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools.bzl b/src/tools.bzl index 32ad4207..4dd03b4c 100644 --- a/src/tools.bzl +++ b/src/tools.bzl @@ -82,6 +82,10 @@ def _codechecker_local_repository_impl(repository_ctx): if not codechecker_bin_path: fail("ERROR! CodeChecker is not detected") + ccache_bin_path = repository_ctx.which("ccache") + if ccache_bin_path: + fail("ERROR! ccache is detected") + defs = "CODECHECKER_BIN_PATH = '{}'\n".format(codechecker_bin_path) repository_ctx.file( repository_ctx.path("defs.bzl"), From 71d4910998b3b59e50cef31d49aecf7af1feba8b Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Tue, 2 Sep 2025 08:10:18 +0200 Subject: [PATCH 2/8] More sophisticated ccache detection --- src/tools.bzl | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/tools.bzl b/src/tools.bzl index 4dd03b4c..26354ff7 100644 --- a/src/tools.bzl +++ b/src/tools.bzl @@ -84,7 +84,18 @@ def _codechecker_local_repository_impl(repository_ctx): ccache_bin_path = repository_ctx.which("ccache") if ccache_bin_path: - fail("ERROR! ccache is detected") + gcc_bin_path = repository_ctx.which("gcc") + clang_bin_path = repository_ctx.which("clang") + readlink_bin_path = repository_ctx.which("readlink") + if readlink_bin_path: + gcc_bin_real = repository_ctc.execute( + [readlink_bin_path, "-f", gcc_bin_path] + ) + clang_bin_real = repository_ctc.execute( + [readlink_bin_path, "-f", clang_bin_path] + ) + if gcc_bin_real == ccache_bin_path or clang_bin_real == ccache_bin_path: + fail("ERROR! ccache is detected!") defs = "CODECHECKER_BIN_PATH = '{}'\n".format(codechecker_bin_path) repository_ctx.file( From cf53fd2324b2851620b4d0a638a4b589a63613f2 Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Tue, 2 Sep 2025 08:34:58 +0200 Subject: [PATCH 3/8] Revert "More sophisticated ccache detection" This reverts commit c430ce53e9c23802a3c9a5a4026e2aa88c33a6b9. --- src/tools.bzl | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/src/tools.bzl b/src/tools.bzl index 26354ff7..4dd03b4c 100644 --- a/src/tools.bzl +++ b/src/tools.bzl @@ -84,18 +84,7 @@ def _codechecker_local_repository_impl(repository_ctx): ccache_bin_path = repository_ctx.which("ccache") if ccache_bin_path: - gcc_bin_path = repository_ctx.which("gcc") - clang_bin_path = repository_ctx.which("clang") - readlink_bin_path = repository_ctx.which("readlink") - if readlink_bin_path: - gcc_bin_real = repository_ctc.execute( - [readlink_bin_path, "-f", gcc_bin_path] - ) - clang_bin_real = repository_ctc.execute( - [readlink_bin_path, "-f", clang_bin_path] - ) - if gcc_bin_real == ccache_bin_path or clang_bin_real == ccache_bin_path: - fail("ERROR! ccache is detected!") + fail("ERROR! ccache is detected") defs = "CODECHECKER_BIN_PATH = '{}'\n".format(codechecker_bin_path) repository_ctx.file( From 60adc0b8ffd54d41966731d1d9302811085720e9 Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Tue, 2 Sep 2025 09:02:10 +0200 Subject: [PATCH 4/8] Add ccache detection --- src/tools.bzl | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/tools.bzl b/src/tools.bzl index 4dd03b4c..9cee1fd4 100644 --- a/src/tools.bzl +++ b/src/tools.bzl @@ -71,6 +71,36 @@ def register_default_python_toolchain(): default_python_tools(name = "default_python_tools") native.register_toolchains("@default_python_tools//:python_toolchain") +def parse_tool_output(output): + """ + Parses a string of tool output and returns a dictionary. + + Args: + output (str): The string output to parse. Each line should contain + a tool name, its path (if found), and its version. + + Returns: + dict: A dictionary where keys are tool names and values are dictionaries + containing 'path' and 'version'. If a tool is 'NOT FOUND', the + value is a dictionary with 'path' and 'version' both set to None. + """ + parsed_data = [] + lines = output.strip().split('\n') + for line in lines: + parts_dirty = line.split(" ") + parts = [] + for fragment in parts_dirty: + if fragment != "": + parts.append(fragment) + tool_name = parts[0] + if 'NOT' not in parts: + path = parts[1] + version = parts[2] + parsed_data.append( + {'tool_name': tool_name, 'path': path, 'version': version} + ) + return parsed_data + def _codechecker_local_repository_impl(repository_ctx): repository_ctx.file( repository_ctx.path("BUILD"), @@ -82,9 +112,18 @@ def _codechecker_local_repository_impl(repository_ctx): if not codechecker_bin_path: fail("ERROR! CodeChecker is not detected") + analyzers = repository_ctx.execute([codechecker_bin_path, "analyzers"]) + + parsed_analyzers = parse_tool_output(analyzers.stdout) + ccache_bin_path = repository_ctx.which("ccache") - if ccache_bin_path: - fail("ERROR! ccache is detected") + readlink_bin = repository_ctx.which("readlink") + for item in parsed_analyzers: + realpath = repository_ctx.execute( + [readlink_bin, "-f", item["path"]] + ).stdout + if realpath.strip() == str(ccache_bin_path): + fail("ERROR! ccache detected") defs = "CODECHECKER_BIN_PATH = '{}'\n".format(codechecker_bin_path) repository_ctx.file( From 85878bcddc73ef72fab8c3d870227e18145c7aae Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Wed, 3 Sep 2025 08:34:24 +0200 Subject: [PATCH 5/8] Remove unnecesary function --- src/tools.bzl | 47 ++++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/src/tools.bzl b/src/tools.bzl index 9cee1fd4..4950401b 100644 --- a/src/tools.bzl +++ b/src/tools.bzl @@ -71,36 +71,6 @@ def register_default_python_toolchain(): default_python_tools(name = "default_python_tools") native.register_toolchains("@default_python_tools//:python_toolchain") -def parse_tool_output(output): - """ - Parses a string of tool output and returns a dictionary. - - Args: - output (str): The string output to parse. Each line should contain - a tool name, its path (if found), and its version. - - Returns: - dict: A dictionary where keys are tool names and values are dictionaries - containing 'path' and 'version'. If a tool is 'NOT FOUND', the - value is a dictionary with 'path' and 'version' both set to None. - """ - parsed_data = [] - lines = output.strip().split('\n') - for line in lines: - parts_dirty = line.split(" ") - parts = [] - for fragment in parts_dirty: - if fragment != "": - parts.append(fragment) - tool_name = parts[0] - if 'NOT' not in parts: - path = parts[1] - version = parts[2] - parsed_data.append( - {'tool_name': tool_name, 'path': path, 'version': version} - ) - return parsed_data - def _codechecker_local_repository_impl(repository_ctx): repository_ctx.file( repository_ctx.path("BUILD"), @@ -114,7 +84,22 @@ def _codechecker_local_repository_impl(repository_ctx): analyzers = repository_ctx.execute([codechecker_bin_path, "analyzers"]) - parsed_analyzers = parse_tool_output(analyzers.stdout) + parsed_analyzers = [] + + lines = analyzers.stdout.strip().split('\n') + for line in lines: + parts_dirty = line.split(" ") + parts = [] + for fragment in parts_dirty: + if fragment != "": + parts.append(fragment) + tool_name = parts[0] + if 'NOT' not in parts: + path = parts[1] + version = parts[2] + parsed_analyzers.append( + {'tool_name': tool_name, 'path': path, 'version': version} + ) ccache_bin_path = repository_ctx.which("ccache") readlink_bin = repository_ctx.which("readlink") From 850eba17e08e85dd150a4de7b998175ce2eb2ab2 Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Wed, 3 Sep 2025 08:34:41 +0200 Subject: [PATCH 6/8] Add CCACHE_DISABLE env variable detection --- src/tools.bzl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/tools.bzl b/src/tools.bzl index 4950401b..4c95a426 100644 --- a/src/tools.bzl +++ b/src/tools.bzl @@ -82,6 +82,9 @@ def _codechecker_local_repository_impl(repository_ctx): if not codechecker_bin_path: fail("ERROR! CodeChecker is not detected") + # In future versions use repository_ctx.getenv() + ccache_disable = repository_ctx.os.environ.get("CCACHE_DISABLE", 0) + analyzers = repository_ctx.execute([codechecker_bin_path, "analyzers"]) parsed_analyzers = [] @@ -107,10 +110,11 @@ def _codechecker_local_repository_impl(repository_ctx): realpath = repository_ctx.execute( [readlink_bin, "-f", item["path"]] ).stdout - if realpath.strip() == str(ccache_bin_path): + if realpath.strip() == str(ccache_bin_path) and ccache_disable != "1": fail("ERROR! ccache detected") - defs = "CODECHECKER_BIN_PATH = '{}'\n".format(codechecker_bin_path) + defs = "CODECHECKER_BIN_PATH = '{}'\n".format(codechecker_bin_path) + \ + "CCACHE_DISABLE = '{}'\n".format(ccache_disable) repository_ctx.file( repository_ctx.path("defs.bzl"), content = defs, From 4300180861da354cce16585c9e3a2b045f50f81b Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Wed, 3 Sep 2025 09:58:17 +0200 Subject: [PATCH 7/8] Pass CCACHE_DISABLE variable to jobs --- src/clang.bzl | 11 +++++++++++ src/clang_ctu.bzl | 10 ++++++++++ src/codechecker.bzl | 8 ++++++++ src/per_file.bzl | 10 ++++++++++ 4 files changed, 39 insertions(+) diff --git a/src/clang.bzl b/src/clang.bzl index 121a458f..bf88b983 100644 --- a/src/clang.bzl +++ b/src/clang.bzl @@ -1,5 +1,9 @@ load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") +load( + "@default_codechecker_tools//:defs.bzl", + "CCACHE_DISABLE" +) CLANG_TIDY_WRAPPER_SCRIPT = """#!/usr/bin/env bash CLANG_TIDY=$1 @@ -176,12 +180,19 @@ def _run_analyzer( direct = input_files, transitive = [compilation_context.headers], ) + + # Have it None by default to avoid overwriting use_default_shell_env + env_var = {} + if CCACHE_DISABLE == "1": + env_var["CCACHE_DISABLE"] = CCACHE_DISABLE + ctx.actions.run( inputs = inputs, outputs = [outfile], executable = wrapper, arguments = [args], mnemonic = "ClangAnalyzer", + env = env_var, use_default_shell_env = True, progress_message = "Run clang -analyze on {}".format(infile.short_path), ) diff --git a/src/clang_ctu.bzl b/src/clang_ctu.bzl index c18b4147..c188ebab 100644 --- a/src/clang_ctu.bzl +++ b/src/clang_ctu.bzl @@ -1,5 +1,9 @@ load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") +load( + "@default_codechecker_tools//:defs.bzl", + "CCACHE_DISABLE" +) CLANG_CTU_WRAPPER_SCRIPT = """#!/usr/bin/env bash #set -x @@ -99,6 +103,11 @@ def _run_clang_ctu( args.add(src.path) args.add_all(arguments) + # Have it None by default to avoid overwriting use_default_shell_env + env_var = None + if CCACHE_DISABLE == 1: + env_var = {"CCACHE_DISABLE": CCACHE_DISABLE} + # Action to run CodeChecker for a file ctx.actions.run( inputs = inputs, @@ -106,6 +115,7 @@ def _run_clang_ctu( executable = wrapper, arguments = [args], mnemonic = "ClangCTU", + env = env_var, use_default_shell_env = True, progress_message = "clang -analyze +CTU {}".format(src.short_path), ) diff --git a/src/codechecker.bzl b/src/codechecker.bzl index 187e04e6..c7a6df0d 100644 --- a/src/codechecker.bzl +++ b/src/codechecker.bzl @@ -9,6 +9,7 @@ load( load( "@default_codechecker_tools//:defs.bzl", "CODECHECKER_BIN_PATH", + "CCACHE_DISABLE" ) load( "per_file.bzl", @@ -102,6 +103,11 @@ def _codechecker_impl(ctx): if compile_commands != ctx.outputs.compile_commands: fail("Seems compile_commands.json file is incorrect!") + # Have it None by default to avoid overwriting use_default_shell_env + env_var = {} + if CCACHE_DISABLE == "1": + env_var["CCACHE_DISABLE"] = CCACHE_DISABLE + # Convert flacc calls to clang in compile_commands.json # and save to codechecker_commands.json ctx.actions.run( @@ -115,6 +121,7 @@ def _codechecker_impl(ctx): ], mnemonic = "CodeCheckerConvertFlaccToClang", progress_message = "Filtering %s" % str(ctx.label), + env = env_var, # use_default_shell_env = True, ) @@ -199,6 +206,7 @@ def _codechecker_impl(ctx): arguments = [], mnemonic = "CodeChecker", progress_message = "CodeChecker %s" % str(ctx.label), + env = env_var, # use_default_shell_env = True, ) diff --git a/src/per_file.bzl b/src/per_file.bzl index cfb76621..d4243911 100644 --- a/src/per_file.bzl +++ b/src/per_file.bzl @@ -3,6 +3,10 @@ load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") +load( + "@default_codechecker_tools//:defs.bzl", + "CCACHE_DISABLE" +) CODE_CHECKER_WRAPPER_SCRIPT = """#!/usr/bin/env bash #set -x @@ -94,6 +98,11 @@ def _run_code_checker( args.add("--output=" + data_dir) args.add("--file=*/" + src.path) + # Have it None by default to avoid overwriting use_default_shell_env + env_var = {} + if CCACHE_DISABLE == "1": + env_var["CCACHE_DISABLE"] = CCACHE_DISABLE + # Action to run CodeChecker for a file ctx.actions.run( inputs = inputs, @@ -101,6 +110,7 @@ def _run_code_checker( executable = wrapper, arguments = [args], mnemonic = "CodeChecker", + env = env_var, use_default_shell_env = True, progress_message = "CodeChecker analyze {}".format(src.short_path), ) From 581e572491c844637307128d594b287926a800c8 Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Wed, 3 Sep 2025 18:50:11 +0200 Subject: [PATCH 8/8] Use `--ccache-skip` to detect ccache instead of using symlinks --- src/tools.bzl | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/tools.bzl b/src/tools.bzl index 4c95a426..baa0698c 100644 --- a/src/tools.bzl +++ b/src/tools.bzl @@ -87,7 +87,7 @@ def _codechecker_local_repository_impl(repository_ctx): analyzers = repository_ctx.execute([codechecker_bin_path, "analyzers"]) - parsed_analyzers = [] + parsed_analyzers = {} lines = analyzers.stdout.strip().split('\n') for line in lines: @@ -100,18 +100,25 @@ def _codechecker_local_repository_impl(repository_ctx): if 'NOT' not in parts: path = parts[1] version = parts[2] - parsed_analyzers.append( - {'tool_name': tool_name, 'path': path, 'version': version} + parsed_analyzers[tool_name] = {'path': path, 'version': version} + bash_bin = repository_ctx.which("bash") + clang_ccache = repository_ctx.execute( + [ + bash_bin, "-c", + "{} -xc -c - --ccache-skip