From patchwork Fri Aug 27 14:47:53 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 13557 X-Patchwork-Delegate: kieran.bingham@ideasonboard.com Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id A6C17BD87D for ; Fri, 27 Aug 2021 14:47:59 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 11F6B68895; Fri, 27 Aug 2021 16:47:59 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="WpJVNEgu"; dkim-atps=neutral Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 07C8160256 for ; Fri, 27 Aug 2021 16:47:57 +0200 (CEST) Received: from Monstersaurus.local (cpc89244-aztw30-2-0-cust3082.18-1.cable.virginm.net [86.31.172.11]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 8446C5A1; Fri, 27 Aug 2021 16:47:56 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1630075676; bh=8DgES/Uoi1tNrVO2nIRDbJ60Dj3CmjIYjyA+3zM3hbQ=; h=From:To:Cc:Subject:Date:From; b=WpJVNEguDL/su+BWRSOjuBiOEN6/sX5w7fvQE/lutEGThgaW0gzGxd/EN86Ra6qMc RvH43KEu1+1Ra1c+jRwwx6nqklHY0NP9Lkdw8k4W9e/fmW+lwDwJSTiDLDPu+t991O FwJCVrtBeK0QXQQ7HwR9KVn+bmIWijtVclBBv5ps= From: Kieran Bingham To: libcamera devel Date: Fri, 27 Aug 2021 15:47:53 +0100 Message-Id: <20210827144753.419929-1-kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH] clang-format: Support multiple versions X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" The .clang-format file can use CaseSensitive on Regex rules for Include Categories. With this we can distinguish between QT headers which commence with a 'Q' verses system headers including . This requires clang-format-12 to support that rule, and clang-format is not very amicable to .clang-format files with unsupported entries, and will fail to run on previous versions if we add that option directly. This causes the checkstyle utility to become unusable for users of clang-format versions prior to 12. Unfortunately, clang-format does not provide a way to specify a specific file to use for the rules to apply when formatting, so we can not easily call clang-format with a file specific to its versioned needs. Implement a means of identifying the version of clang-format, and use that information to search for the most recent supportable .clang-format-$(version) file, which can then be symlinked to the fixed file location used by clang format (.clang-format). .clang-format-12: is added with CaseSensitive:true for QT headers .clang-format-7: is moved from the current .clang-format implementation Signed-off-by: Kieran Bingham --- Note there are few things I dislike about this, hence RFC: - We leave our tree without a .clang-format until checkstyle runs.. - We run the unlinking and symlinking on every invocation of checkstyle - The 'autogenerated' file in place of a git tracked one causes issues on rebase. Could be an issue for bisects...? .clang-format-12 | 169 +++++++++++++++++++++++++++++++ .clang-format => .clang-format-7 | 0 utils/checkstyle.py | 49 ++++++++- 3 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 .clang-format-12 rename .clang-format => .clang-format-7 (100%) diff --git a/.clang-format-12 b/.clang-format-12 new file mode 100644 index 000000000000..98e9fad472fc --- /dev/null +++ b/.clang-format-12 @@ -0,0 +1,169 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# clang-format configuration file. Intended for clang-format >= 12. +# +# For more information, see: +# +# Documentation/process/clang-format.rst +# https://clang.llvm.org/docs/ClangFormat.html +# https://clang.llvm.org/docs/ClangFormatStyleOptions.html +# +--- +Language: Cpp +AccessModifierOffset: -8 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: InlineOnly +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: true + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: false +ColumnLimit: 0 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 8 +ContinuationIndentWidth: 8 +Cpp11BracedListStyle: false +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - 'udev_list_entry_foreach' +SortIncludes: true +IncludeBlocks: Regroup +IncludeCategories: + # Headers matching the name of the component are matched automatically. + # Priority 1 + # Other library headers (explicit overrides to match before system headers) + - Regex: '(|||||)' + Priority: 9 + # Qt includes (match before C++ standard library) + - Regex: '' + Priority: 9 + CaseSensitive: true + # Headers in <> with an extension. (+system libraries) + - Regex: '<([A-Za-z0-9\-_])+\.h>' + Priority: 2 + # System headers + - Regex: '' + Priority: 2 + # C++ standard library includes (no extension) + - Regex: '<([A-Za-z0-9\-_/])+>' + Priority: 2 + # Linux headers, as a second group/subset of system headers + - Regex: '' + Priority: 3 + # Headers for libcamera Base support + - Regex: '' + Priority: 4 + - Regex: '' + Priority: 5 + # Public API Headers for libcamera, which are not in a subdir (i.e. ipa/,internal/) + - Regex: '' + Priority: 6 + # IPA Interfaces + - Regex: '' + Priority: 7 + # libcamera Internal headers in "" + - Regex: '"libcamera/internal/.*\.h"' + Priority: 8 + # Other libraries headers with one group per library (.h or .hpp) + - Regex: '<.*/.*\.hp*>' + Priority: 9 + # local modular includes "path/file.h" (.h or .hpp) + - Regex: '"(.*/)+.*\.hp*"' + Priority: 10 + # Other local headers "file.h" with extension (.h or .hpp) + - Regex: '".*.hp*"' + Priority: 11 + # Any unmatched line, separated from the last group + - Regex: '"*"' + Priority: 100 + +IncludeIsMainRegex: '(_test)?$' +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 8 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 8 +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true + +# Taken from git's rules +PenaltyBreakAssignment: 10 +PenaltyBreakBeforeFirstCallParameter: 30 +PenaltyBreakComment: 10 +PenaltyBreakFirstLessLess: 0 +PenaltyBreakString: 10 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 100 +PenaltyReturnTypeOnItsOwnLine: 60 + +PointerAlignment: Right +ReflowComments: false +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 8 +UseTab: Always +... diff --git a/.clang-format b/.clang-format-7 similarity index 100% rename from .clang-format rename to .clang-format-7 diff --git a/utils/checkstyle.py b/utils/checkstyle.py index ececb46eaacc..279ace8346b4 100755 --- a/utils/checkstyle.py +++ b/utils/checkstyle.py @@ -16,6 +16,7 @@ import argparse import difflib import fnmatch +import glob import os.path import re import shutil @@ -566,9 +567,55 @@ class Formatter(metaclass=ClassRegistry): return patterns -class CLangFormatter(Formatter): +# Identify the version of clang-format running, and match it against locally +# available versioned configuration files of the form: +# .clang-format-$(version) +# +# The highest supported local configuration file is linked as .clang-format by +# ClangFormatLinker.relink() for use by the ClangFormatter. +# +class ClangFormatLinker(): + def version(): + version_regex = re.compile('[^0-9]*([0-9]+).*') + ret = subprocess.run(['clang-format', '--version'], stdout=subprocess.PIPE) + version = ret.stdout.decode('utf-8') + search = version_regex.search(version) + if search: + version = search.group(1) + return int(version) + + # Lowest supported version + return 7 + + def supported(): + version = ClangFormatLinker.version() + + # Match the highest supported version + clang_files = glob.glob('.clang-format-[0-9]*') + clang_files = sorted(clang_files, reverse=True, + key=lambda s: [int(re.sub("[^0-9]", "", s))]) + for f in clang_files: + file_version = int(re.sub("[^0-9]", "", f)) + if file_version <= version: + return f + + return None + + def relink(): + supported = ClangFormatLinker.supported() + if not supported: + return + + if os.path.exists('.clang-format'): + os.unlink('.clang-format') + os.symlink(supported, '.clang-format') + + +class ClangFormatter(Formatter): patterns = ('*.c', '*.cpp', '*.h') + ClangFormatLinker.relink() + @classmethod def format(cls, filename, data): ret = subprocess.run(['clang-format', '-style=file',