Skip to content
106 changes: 9 additions & 97 deletions src/codechecker.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ load(
"tools.bzl",
"warning"
)
load(
"@bazel_codechecker//src:codechecker_config.bzl",
"get_config_file"
)

def get_platform_alias(platform):
"""
Expand All @@ -33,61 +37,6 @@ def get_platform_alias(platform):
platform = shortname
return platform

CodeCheckerConfigInfo = provider(
doc = "Defines CodeChecker configuration",
fields = {
"analyze": "List of arguments for CodeChecker analyze command",
"parse": "List of arguments for CodeChecker parse command",
"config_file": "CodeChecker configuration file in JSON format",
"env": "Environment variables for CodeChecker",
},
)

def _codechecker_config_impl(ctx):
return [
CodeCheckerConfigInfo(
analyze = ctx.attr.analyze,
parse = ctx.attr.parse,
config_file = ctx.attr.config_file,
env = ctx.attr.env,
),
]

codechecker_config = rule(
implementation = _codechecker_config_impl,
attrs = {
"analyze": attr.string_list(
default = [],
doc = "List of arguments for CodeChecker analyze command",
),
"parse": attr.string_list(
default = [],
doc = "List of arguments for CodeChecker parse command",
),
"config_file": attr.label(
default = None,
allow_single_file = True,
),
"env": attr.string_list(
default = [],
doc = "List of environment variables for CodeChecker",
),
},
)

def _copy_config_to_default(config_file, ctx):
ctx.actions.run(
inputs = [config_file],
outputs = [ctx.outputs.codechecker_config],
mnemonic = "CopyFile",
progress_message = "Copying CodeChecker config file",
executable = "cp",
arguments = [
config_file.path,
ctx.outputs.codechecker_config.path,
],
)

def _codechecker_impl(ctx):
py_runtime_info = ctx.attr._python_runtime[PyRuntimeInfo]
python_path = py_runtime_info.interpreter_path
Expand Down Expand Up @@ -129,43 +78,7 @@ def _codechecker_impl(ctx):
is_executable = False,
)

# Create CodeChecker JSON config file and env vars
if ctx.attr.config:
if type(ctx.attr.config) == "list":
config_info = ctx.attr.config[0][CodeCheckerConfigInfo]
else:
config_info = ctx.attr.config[CodeCheckerConfigInfo]
if config_info.config_file:
# Create a copy of CodeChecker configuration file
# provided via codechecker_config(config_file)
config_file = config_info.config_file.files.to_list()[0]
_copy_config_to_default(config_file, ctx)
else:
# Create CodeChecker configuration file in JSON format
# from Bazel codechecker_config(analyze, parse)
config_json = {}
if config_info.analyze:
config_json["analyze"] = config_info.analyze
if config_info.parse:
config_json["parse"] = config_info.parse
config_content = json.encode_indent(config_json)
ctx.actions.write(
output = ctx.outputs.codechecker_config,
content = config_content,
is_executable = False,
)

# Pack env vars for CodeChecker
codechecker_env = "; ".join(config_info.env)
else:
# Empty CodeChecker JSON config file
ctx.actions.write(
output = ctx.outputs.codechecker_config,
content = "{}",
is_executable = False,
)
codechecker_env = ""

ctx_config_file, codechecker_env = get_config_file(ctx)
codechecker_files = ctx.actions.declare_directory(ctx.label.name + "/codechecker-files")
ctx.actions.expand_template(
template = ctx.file._codechecker_script_template,
Expand All @@ -178,7 +91,7 @@ def _codechecker_impl(ctx):
"{codechecker_bin}": CODECHECKER_BIN_PATH,
"{compile_commands}": ctx.outputs.codechecker_commands.path,
"{codechecker_skipfile}": ctx.outputs.codechecker_skipfile.path,
"{codechecker_config}": ctx.outputs.codechecker_config.path,
"{codechecker_config}": ctx_config_file.path,
"{codechecker_analyze}": " ".join(ctx.attr.analyze),
"{codechecker_files}": codechecker_files.path,
"{codechecker_log}": ctx.outputs.codechecker_log.path,
Expand All @@ -192,7 +105,7 @@ def _codechecker_impl(ctx):
ctx.outputs.codechecker_script,
ctx.outputs.codechecker_commands,
ctx.outputs.codechecker_skipfile,
ctx.outputs.codechecker_config,
ctx_config_file,
] + source_files,
),
outputs = [
Expand All @@ -211,7 +124,7 @@ def _codechecker_impl(ctx):
ctx.outputs.compile_commands,
ctx.outputs.codechecker_commands,
ctx.outputs.codechecker_skipfile,
ctx.outputs.codechecker_config,
ctx_config_file,
codechecker_files,
ctx.outputs.codechecker_script,
ctx.outputs.codechecker_log,
Expand Down Expand Up @@ -273,7 +186,6 @@ codechecker = rule(
"compile_commands": "%{name}/compile_commands.json",
"codechecker_commands": "%{name}/codechecker_commands.json",
"codechecker_skipfile": "%{name}/codechecker_skipfile.cfg",
"codechecker_config": "%{name}/codechecker_config.json",
"codechecker_script": "%{name}/codechecker_script.py",
"codechecker_log": "%{name}/codechecker.log",
},
Expand Down Expand Up @@ -378,7 +290,6 @@ _codechecker_test = rule(
"compile_commands": "%{name}/compile_commands.json",
"codechecker_commands": "%{name}/codechecker_commands.json",
"codechecker_skipfile": "%{name}/codechecker_skipfile.cfg",
"codechecker_config": "%{name}/codechecker_config.json",
"codechecker_script": "%{name}/codechecker_script.py",
"codechecker_log": "%{name}/codechecker.log",
"codechecker_test_script": "%{name}/codechecker_test_script.py",
Expand Down Expand Up @@ -406,6 +317,7 @@ def codechecker_test(
name = name,
targets = targets,
options = analyze,
config = config,
tags = tags,
**kwargs
)
Expand Down
124 changes: 124 additions & 0 deletions src/codechecker_config.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Copyright 2023 Ericsson AB
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.

def get_config_file(ctx):
"""
Returns (config_file, environment_variables)
config_file is a file object that is readable during Codechecker execution
"""

# Decide whether to use json or yaml for configuration
config_file_name = ctx.attr.name + "/config.json"
if ctx.attr.config:
if type(ctx.attr.config) == "list":
config_info = ctx.attr.config[0][CodeCheckerConfigInfo]
else:
config_info = ctx.attr.config[CodeCheckerConfigInfo]
if config_info.config_file:
# Create a copy of CodeChecker configuration file
# provided via codechecker_config(config_file)
config_file = config_info.config_file.files.to_list()[0]
config_file_name = ctx.attr.name + \
"/config." + config_file.extension
ctx_config_file = ctx.actions.declare_file(config_file_name)

# Create CodeChecker JSON config file and env vars
if ctx.attr.config:
if type(ctx.attr.config) == "list":
config_info = ctx.attr.config[0][CodeCheckerConfigInfo]
else:
config_info = ctx.attr.config[CodeCheckerConfigInfo]
if config_info.config_file:
# Create a copy of CodeChecker configuration file
# provided via codechecker_config(config_file)
config_file = config_info.config_file.files.to_list()[0]
ctx.actions.run(
inputs = [config_file],
outputs = [ctx_config_file],
mnemonic = "CopyFile",
progress_message = "Copying CodeChecker config file",
executable = "cp",
arguments = [
config_file.path,
ctx_config_file.path,
],
)
else:
# Create CodeChecker configuration file in JSON format
# from Bazel codechecker_config(analyze, parse)
config_json = {}
if config_info.analyze:
config_json["analyze"] = config_info.analyze
if config_info.parse:
config_json["parse"] = config_info.parse
config_content = json.encode_indent(config_json)
ctx.actions.write(
output = ctx_config_file,
content = config_content,
is_executable = False,
)

# Pack env vars for CodeChecker
codechecker_env = "; ".join(config_info.env)
else:
# Empty CodeChecker JSON config file
ctx.actions.write(
output = ctx_config_file,
content = "{}",
is_executable = False,
)
codechecker_env = ""
return (ctx_config_file, codechecker_env)

CodeCheckerConfigInfo = provider(
doc = "Defines CodeChecker configuration",
fields = {
"analyze": "List of arguments for CodeChecker analyze command",
"parse": "List of arguments for CodeChecker parse command",
"config_file": "CodeChecker configuration file in JSON format",
"env": "Environment variables for CodeChecker",
},
)

def _codechecker_config_impl(ctx):
return [
CodeCheckerConfigInfo(
analyze = ctx.attr.analyze,
parse = ctx.attr.parse,
config_file = ctx.attr.config_file,
env = ctx.attr.env,
),
]

codechecker_config = rule(
implementation = _codechecker_config_impl,
attrs = {
"analyze": attr.string_list(
default = [],
doc = "List of arguments for CodeChecker analyze command",
),
"parse": attr.string_list(
default = [],
doc = "List of arguments for CodeChecker parse command",
),
"config_file": attr.label(
default = None,
allow_single_file = True,
),
"env": attr.string_list(
default = [],
doc = "List of environment variables for CodeChecker",
),
},
)
Loading