SERVER-89878 add support for bazel with coverity (#21587)

GitOrigin-RevId: 4224f8170307bb0288d349c308368127734c7537
This commit is contained in:
Daniel Moody 2024-04-30 00:36:06 -05:00 committed by MongoDB Bot
parent d1db0d8291
commit 933cf012ef
10 changed files with 142 additions and 2 deletions

View File

@ -1,5 +1,9 @@
# Reference docs: https://bazel.build/run/bazelrc
# coverity need to use the local command without remote execution auto
# enabled.
info --config=local
# This automatically sets a config based on host platform, ex: --config=macos if the host is macos
build --enable_platform_specific_config=true

1
.gitignore vendored
View File

@ -276,6 +276,7 @@ buildifier
.bazelrc.local
.bazel_info_for_ninja.txt
.ninja_last_command_line_targets.txt
bazel/coverity/analysis/BUILD.bazel
# generated configs for external fixture suites
docker_compose/

View File

@ -393,6 +393,15 @@ add_option(
help="Compress debug sections",
)
add_option(
'coverity-build',
action="store_true",
default=False,
help=(
"Enable coverity build mode, which only means the bazel build will not run. "
"The bazel build is expected to be run in a prior separate coverity enabled bazel build."),
)
add_option(
'sanitize',
help='enable selected sanitizers',

View File

@ -20,6 +20,16 @@ load("//bazel/toolchains:python_toolchain.bzl", "setup_mongo_python_toolchains")
[register_toolchains(toolchain) for toolchain in setup_mongo_python_toolchains()]
load("//bazel/coverity:coverity_toolchain.bzl", "coverity_toolchain")
coverity_toolchain(
name = "rules_coverity",
)
load("@rules_coverity//coverity:repositories.bzl", "rules_coverity_toolchains")
rules_coverity_toolchains()
http_archive(
name = "rules_python",
sha256 = "8c8fe44ef0a9afc256d1e75ad5f448bb59b81aba149b8958f02f7b3a98f5d9b4",

View File

View File

View File

@ -0,0 +1,32 @@
def _coverity_toolchain(ctx):
result = ctx.execute([
"ls",
"/data/cov-sa/bin/cov-build",
])
if result.return_code == 0:
ctx.report_progress("extracting coverity rules...")
result = ctx.download_and_extract("file:///data/cov-sa/bazel/rules_coverity.tar.gz")
else:
ctx.template(
"coverity/BUILD.bazel",
ctx.attr.build_tpl,
)
ctx.template(
"coverity/repositories.bzl",
ctx.attr.repositories_tpl,
)
coverity_toolchain = repository_rule(
implementation = _coverity_toolchain,
attrs = {
"build_tpl": attr.label(
default = "//bazel/coverity:coverity_toolchain.BUILD",
doc = "Label denoting the BUILD file template that gets installed in the repo.",
),
"repositories_tpl": attr.label(
default = "//bazel/coverity:repositories.bzl",
doc = "Label denoting the repositories files the gets installed to the repo.",
),
},
)

View File

@ -0,0 +1,75 @@
import os
import sys
import subprocess
import io
# assume we are always running from project root to find buildscripts
sys.path.append('.')
from buildscripts.install_bazel import install_bazel
bazel_bin_dir = os.path.expanduser("~/.local/bin")
if not os.path.exists(bazel_bin_dir):
os.makedirs(bazel_bin_dir)
fake_out = io.StringIO()
orig_stdout = sys.stdout
orig_stderr = sys.stderr
sys.stdout = fake_out
sys.stderr = fake_out
bazel_executable = install_bazel(bazel_bin_dir)
sys.stdout = orig_stdout
sys.stderr = orig_stderr
# coverity requires a single target which has dependencies on all
# the cc_library and cc_binaries in our build. There is not a good way from
# within the build to get all those targets, so we will generate the list via query
# https://sig-product-docs.synopsys.com/bundle/coverity-docs/page/coverity-analysis/topics/building_with_bazel.html#build_with_bazel
proc = subprocess.run([
bazel_executable,
"aquery",
'--config=local',
'mnemonic("CppCompile|LinkCompile", //src/mongo/...)'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
targets = []
for line in proc.stdout.splitlines():
if line.startswith(" Target: "):
targets.append(line.split()[-1])
coverity_dir = os.path.dirname(__file__)
analysis_dir = os.path.join(coverity_dir, "analysis")
os.makedirs(analysis_dir, exist_ok=True)
with open(os.path.join(coverity_dir, "analysis", "BUILD.bazel"), 'w') as buildfile:
buildfile.write("""\
load("@rules_coverity//coverity:defs.bzl", "cov_gen_script")
cov_gen_script(
name="coverity_build",
deps=[
""")
for target in targets:
buildfile.write("""\
"%s",
""" % target)
buildfile.write("""\
],
)
""")
cmd = [
sys.executable,
"./buildscripts/scons.py",
] + sys.argv + [
"BAZEL_INTEGRATION_DEBUG=1",
"\\$BUILD_ROOT/scons/\\$VARIANT_DIR/sconf_temp"]
# Run a lightwieght scons build to generate the bazel command.
proc = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
for line in proc.stdout.splitlines():
if "BAZEL_COMMAND:" in line:
# The script is intended to be have output placed into a bash variable, so we should
# only ever print the bazel build command
cmd = line.split('BAZEL_COMMAND:')[-1].strip().split()[:-1] + ["//bazel/coverity/analysis:coverity_build"]
print(' '.join(cmd))

View File

@ -0,0 +1,2 @@
def rules_coverity_toolchains():
return None

View File

@ -265,7 +265,7 @@ def ninja_bazel_builder(env: SCons.Environment.Environment, _dup_env: SCons.Envi
}
def bazel_build_thread_func(log_dir: str, verbose: bool) -> None:
def bazel_build_thread_func(env, log_dir: str, verbose: bool) -> None:
"""This thread runs the bazel build up front."""
done_with_temp = False
@ -277,6 +277,12 @@ def bazel_build_thread_func(log_dir: str, verbose: bool) -> None:
bazel_cmd = Globals.bazel_base_build_command + extra_args + ['//src/...']
bazel_debug(f"BAZEL_COMMAND: {' '.join(bazel_cmd)}")
if env.GetOption("coverity-build"):
print(
"--coverity-build selected, assuming bazel targets were built in a previous coverity run. Not running bazel build."
)
return
print("Starting bazel build thread...")
try:
@ -841,7 +847,8 @@ def generate(env: SCons.Environment.Environment) -> None:
# ninja will handle the build so do not launch the bazel batch thread
bazel_build_thread = threading.Thread(target=bazel_build_thread_func,
args=(log_dir, env["VERBOSE"]))
args=(env, log_dir, env["VERBOSE"]))
bazel_build_thread.start()
def wait_for_bazel(env):