Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions docs/index.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* @{
* \cond hardware_adc \defgroup hardware_adc hardware_adc \endcond
* \cond hardware_base \defgroup hardware_base hardware_base \endcond
* \cond hardware_bootlock \defgroup hardware_bootlock hardware_bootlock \endcond
* \cond hardware_boot_lock \defgroup hardware_boot_lock hardware_boot_lock \endcond
* \cond hardware_claim \defgroup hardware_claim hardware_claim \endcond
* \cond hardware_clocks \defgroup hardware_clocks hardware_clocks \endcond
* \cond hardware_divider \defgroup hardware_divider hardware_divider \endcond
Expand All @@ -32,7 +32,6 @@
* \cond hardware_pll \defgroup hardware_pll hardware_pll \endcond
* \cond hardware_powman \defgroup hardware_powman hardware_powman \endcond
* \cond hardware_pwm \defgroup hardware_pwm hardware_pwm \endcond
* \cond hardware_pwm \defgroup hardware_pwm hardware_pwm \endcond
* \cond hardware_resets \defgroup hardware_resets hardware_resets \endcond
* \cond hardware_riscv \defgroup hardware_riscv hardware_riscv \endcond
* \cond hardware_riscv_platform_timer \defgroup hardware_riscv_platform_timer hardware_riscv_platform_timer \endcond
Expand All @@ -44,13 +43,11 @@
* \cond hardware_ticks \defgroup hardware_ticks hardware_ticks \endcond
* \cond hardware_timer \defgroup hardware_timer hardware_timer \endcond
* \cond hardware_uart \defgroup hardware_uart hardware_uart \endcond
* \cond hardware_usb \defgroup hardware_usb hardware_usb \endcond
* \cond hardware_vreg \defgroup hardware_vreg hardware_vreg \endcond
* \cond hardware_watchdog \defgroup hardware_watchdog hardware_watchdog \endcond
* \cond hardware_xip_cache \defgroup hardware_xip_cache hardware_xip_cache \endcond
* \cond hardware_xosc \defgroup hardware_xosc hardware_xosc \endcond
* \cond hardware_powman \defgroup hardware_powman hardware_powman \endcond
* \cond hardware_hazard3 \defgroup hardware_hazard3 hardware_hazard3 \endcond
* \cond hardware_riscv \defgroup hardware_riscv hardware_riscv \endcond

* @}
*
Expand All @@ -61,6 +58,7 @@
* \cond pico_aon_timer \defgroup pico_aon_timer pico_aon_timer \endcond
* \cond pico_async_context \defgroup pico_async_context pico_async_context \endcond
* \cond pico_bootsel_via_double_reset \defgroup pico_bootsel_via_double_reset pico_bootsel_via_double_reset \endcond
* \cond pico_fix \defgroup pico_fix pico_fix \endcond
* \cond pico_flash \defgroup pico_flash pico_flash \endcond
* \cond pico_i2c_slave \defgroup pico_i2c_slave pico_i2c_slave \endcond
* \cond pico_multicore \defgroup pico_multicore pico_multicore \endcond
Expand Down
136 changes: 136 additions & 0 deletions tools/check_all_groups.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#!/usr/bin/env python3
#
# Copyright (c) 2025 Raspberry Pi Ltd
#
# SPDX-License-Identifier: BSD-3-Clause
#
#
# Script to check that the "groups" in various contexts all match up. (like an enhanced version of check_doxygen_groups.py)
# Note that it only reports the *first* instance of a missing group, not all occurrences.
#
# Usage:
#
# tools/check_all_groups.py <root of repo>
# (you'll probably want to pipe the output through ` | grep -v cmsis` )

import re
import sys
import os

scandir = sys.argv[1]

DEFGROUP_NAME = r'\defgroup'
DEFGROUP_RE = re.compile(r'{}\s+(\w+)'.format(re.escape(DEFGROUP_NAME)))
INGROUP_NAME = r'\ingroup'
INGROUP_RE = re.compile(r'{}\s+(\w+)'.format(re.escape(INGROUP_NAME)))
DOCS_INDEX_HEADER = 'docs/index.h'

BASE_CONFIG_NAME = 'PICO_CONFIG'
CONFIG_RE = re.compile(r'//\s+{}:\s+(\w+),\s+([^,]+)(?:,\s+(.*))?$'.format(BASE_CONFIG_NAME))
BASE_CMAKE_CONFIG_NAME = 'PICO_CMAKE_CONFIG'
CMAKE_CONFIG_RE = re.compile(r'#\s+{}:\s+([\w-]+),\s+([^,]+)(?:,\s+(.*))?$'.format(BASE_CMAKE_CONFIG_NAME))
BASE_BUILD_DEFINE_NAME = 'PICO_BUILD_DEFINE'
BUILD_DEFINE_RE = re.compile(r'#\s+{}:\s+(\w+),\s+([^,]+)(?:,\s+(.*))?$'.format(BASE_BUILD_DEFINE_NAME))
BASE_GROUP_NAME = 'group='
GROUP_RE = re.compile(r'\b{}(\w+)\b'.format(BASE_GROUP_NAME))

def_groups = {}
in_groups = {}
doc_groups = {}
config_groups = {}
cmake_config_groups = {}
build_define_groups = {}
any_errors = False

def get_group_from_config_attrs(attr_str):
m = GROUP_RE.search(attr_str)
if m:
return m.group(1)

# Scan all .c and .h and .S and .cmake and CMakeLists.txt files in the specific path, recursively.

for dirpath, dirnames, filenames in os.walk(scandir):
for filename in filenames:
file_ext = os.path.splitext(filename)[1]
if filename == 'CMakeLists.txt' or file_ext in ('.c', '.h', '.S', '.cmake'):
file_path = os.path.join(dirpath, filename)
with open(file_path) as fh:
for line in fh.readlines():
m = DEFGROUP_RE.search(line)
if m:
group = m.group(1)
if file_path.endswith(DOCS_INDEX_HEADER):
if group in doc_groups:
any_errors = True
print("{} uses {} {} but so does {}".format(doc_groups[group], DEFGROUP_NAME, group, file_path))
else:
doc_groups[group] = file_path
else:
if group in def_groups:
any_errors = True
print("{} uses {} {} but so does {}".format(def_groups[group], DEFGROUP_NAME, group, file_path))
else:
def_groups[group] = file_path
else:
m = INGROUP_RE.search(line)
if m:
group = m.group(1)
if group not in in_groups:
in_groups[group] = file_path
else:
m = CONFIG_RE.search(line)
if m:
group = get_group_from_config_attrs(m.group(3))
if group not in config_groups:
config_groups[group] = file_path
else:
m = CMAKE_CONFIG_RE.search(line)
if m:
group = get_group_from_config_attrs(m.group(3))
if group not in cmake_config_groups:
cmake_config_groups[group] = file_path
else:
m = BUILD_DEFINE_RE.search(line)
if m:
group = get_group_from_config_attrs(m.group(3))
if group not in build_define_groups:
build_define_groups[group] = file_path

seen_groups = set()
for group, file_path in in_groups.items():
seen_groups.add(group)
if group not in def_groups and group not in doc_groups:
any_errors = True
print("{} uses {} {} which was never defined".format(file_path, INGROUP_NAME, group))
for group, file_path in config_groups.items():
seen_groups.add(group)
if group not in def_groups and group not in doc_groups:
any_errors = True
print("{} uses {} {}{} which was never defined".format(file_path, BASE_CONFIG_NAME, BASE_GROUP_NAME, group))
for group, file_path in cmake_config_groups.items():
seen_groups.add(group)
if group == 'build': # dummy group
continue
if group not in def_groups and group not in doc_groups:
any_errors = True
print("{} uses {} {}{} which was never defined".format(file_path, BASE_CMAKE_CONFIG_NAME, BASE_GROUP_NAME, group))
for group, file_path in build_define_groups.items():
seen_groups.add(group)
if group == 'build': # dummy group
continue
if group not in def_groups and group not in doc_groups:
any_errors = True
print("{} uses {} {}{} which was never defined".format(file_path, BASE_BUILD_DEFINE_NAME, BASE_GROUP_NAME, group))

for group in doc_groups.keys():
seen_groups.add(group)
if group not in seen_groups and group not in def_groups:
any_errors = True
print("{} uses {} {} which doesn't appear anywhere else".format(DOCS_INDEX_HEADER, DEFGROUP_NAME, group))

unused_groups = set(def_groups.keys()) - seen_groups
if unused_groups:
any_errors = True
print("The following groups were defined with {} but never referenced:\n{}".format(DEFGROUP_NAME, sorted(unused_groups)))

sys.exit(any_errors)
Loading