Skip to content

Conversation

ziuziakowska
Copy link

This replaces the existing ot-tidy.sh script with a new Python script.

This new script should make it easier to run the linter locally in the same way as CI, as the older wrapper script did not have any usage information.

The script also checks for some misconfigurations and reports those - such as QEMU not being configured to use Clang which results in a different incompatible set of warning flags to be used with GCC to be used for clang-tidy.

In addition, this script adds a -j flag to run linting in parallel, using the run-clang-tidy wrapper that comes with clang-tidy. On my machine, this reduced linting time on the same set of files as CI from ~3 minutes to 30 seconds.

Copy link

@jwnrt jwnrt left a comment

Choose a reason for hiding this comment

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

I get this error from the script:

$ scripts/opentitan/ot_tidy.py --ci-files
Could not parse 'clang-tidy' version string.

Here's my output of clang-tidy --version:

$ clang-tidy --version
LLVM (http://llvm.org/):
  LLVM version 16.0.2
  Optimized build.

I think it's because my version_line is the second line, not the first

@ziuziakowska
Copy link
Author

I think it's because my version_line is the second line, not the first

Fixed it to look for that on any line.
Mine appeared like this:

$ clang-tidy-20 --version
Ubuntu LLVM version 20.1.2
  Optimized build.

@jwnrt
Copy link

jwnrt commented Sep 23, 2025

Yep, that works now, thanks

Copy link

@rivos-eblot rivos-eblot left a comment

Choose a reason for hiding this comment

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

I think several features are broken, and some are a bit fragile (parsing, ANSI management, ...).

Can you run flake8, as there are many outsized lines and argument aligment warning messages. Thanks.

parser.add_argument('-f', '--files', required=False, nargs="+", action='extend', default=[],
help="Files to run tidy on")

args = parser.parse_args()

Choose a reason for hiding this comment

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

It think there is a regression here (vs. .sh script): we need to be able to pass any argument to clang-tidy, not just files.

Copy link
Author

Choose a reason for hiding this comment

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

Is this used anywhere? I'm not sure how compatible it would be, since run-clang-tidy and clang-tidy support different flags, and the former doesn't have a way to pass arguments to the latter. Both only have the option to pass additional flags to the compiler with -extra-arg/-extra-arg-before and -- [ARGS...] respectively.

Copy link

@rivos-eblot rivos-eblot Sep 24, 2025

Choose a reason for hiding this comment

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

Yes we do use it: the public version of OpenTitan emulation is only about a half of what we emulate: we wrote ot-tidy.sh so that it could be use by either public OpenTitan or with our extensions. Our CI extensively uses it.

I wonder whether it would make sense to have two tidy helper scripts, as this one is getting complex and is likely to become more difficult to use at least from a developer from the command line. Maybe a dedicated script to run run-clang-tidy would be easier, and keep ot-tidy.sh as it is? ot-tidy.sh is really though as a very thin wrapper around cland-tidy: it clang-tidy with some sugar syntax.

Copy link
Author

@ziuziakowska ziuziakowska Sep 24, 2025

Choose a reason for hiding this comment

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

I see. Perhaps it might make more sense to have separate helper scripts then. I originally had the thought to write this because the only usage information was in the CI, and the warning flag errors when not configuring with --cc=clang were only documented in the comments there too. The run-clang-tidy wrapper also let me lint a lot faster instead of waiting for CI to do it. So I suppose this script is more public development-oriented.

Choose a reason for hiding this comment

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

out of curiosity: does run-clang-tidy manage output streams from its various subprocesses when several of them report errors?

This script is intendde to replace the `ot-tidy.sh` script for running
clang-tidy on our part of the codebase.

A `-j` flag is added to run clang-tidy jobs in parallel, using the
run-clang-tidy script that comes with it. On my machine this speeds up
linting files for CI from >3 minutes to ~30 seconds.

The script also checks for some configuration issues, such as the C
compiler for QEMU not being set to clang - this causes some warnings
flags to be enabled that are recognised by GCC but not clang, and these
will show up as errors.

Signed-off-by: Alice Ziuziakowska <[email protected]>
Replaces all usages, updates docs, and removes the older script.

Signed-off-by: Alice Ziuziakowska <[email protected]>
@ziuziakowska ziuziakowska changed the title New ot_tidy.py script for development and CI New ot-tidy.py script for development and CI Sep 24, 2025
try:
parser = argparse.ArgumentParser()

parser.add_argument("-b", "--build-dir", required=False,

Choose a reason for hiding this comment

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

You can remove the required=False which is the default behavior for all options

parser.add_argument('-f', '--files', required=False, nargs="+", action='extend', default=[],
help="Files to run tidy on")

args = parser.parse_args()

Choose a reason for hiding this comment

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

out of curiosity: does run-clang-tidy manage output streams from its various subprocesses when several of them report errors?

action="store_true",
help="Run on all files checked by CI")

parser.add_argument("-f", "--files", required=False,

Choose a reason for hiding this comment

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

I wonder if this case is allowed: required=False means the option is optional, but on the other side nargs="+" indicates that the option should be specified at least once.

Choose a reason for hiding this comment

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

BTW, maybe this which is the main one should use positional argument (files) rather than an option?

if args.ci_files:
args.files.extend(ci_files())

if not args.files:

Choose a reason for hiding this comment

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

The option you specify to the parser should handle this case I believe

]

fmt_args = " ".join(cmd_args[1:])
print(f"run '{cmd} {fmt_args} ... ({len(args.files)} files)'")

Choose a reason for hiding this comment

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

Maybe use a logger for this?

eprint = eprint_tty


def check_compile_commands(build_dir) -> None:

Choose a reason for hiding this comment

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

missing type hint (: str)


eprint = eprint_plain
if sys.stderr.isatty():
eprint = eprint_tty

Choose a reason for hiding this comment

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

or

eprint = eprint_tty if sys.stderr.isatty() else eprint_plain

return [relpath(normpath(join(QEMU_ROOT, f))) for f in ci_files_list]


def uint(value) -> int:

Choose a reason for hiding this comment

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

value: str

LLVM_MAJOR = 20
"""LLVM major version to check for"""

OT_SCRIPTS = dirname(normpath(__file__))

Choose a reason for hiding this comment

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

my mistake from a previous comment: abspath is better than normpath, sorry about that.

if match is not None:
ccs = [f"clang-{LLVM_MAJOR}", "clang"]
if match.group(1) not in ccs:
eprint("QEMU build is configured with non-clang C compiler "

Choose a reason for hiding this comment

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

May be use f"" on each line, it should be more readable.
Python would only complain if the resulting string contains no variable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants