mirror of
https://github.com/raspberrypi/pico-sdk.git
synced 2025-02-05 18:40:21 +00:00
Add scripts to extract PICO_CMAKE_CONFIG and PICO_BUILD_DEFINE entries (#1708)
Tidy up a couple of PICO_CMAKE_CONFIG and PICO_BUILD_DEFINE entries
This commit is contained in:
parent
abce1d427c
commit
115eae7c66
@ -1,4 +1,4 @@
|
||||
# PICO_CMAKE_CONFIG: PICO_PLATFORM, platform to build for e.g. rp2040/host, default=rp2040 or environment value, group=build
|
||||
# PICO_CMAKE_CONFIG: PICO_PLATFORM, platform to build for e.g. rp2040/host, type=string, default=rp2040 or environment value, group=build
|
||||
if (DEFINED ENV{PICO_PLATFORM} AND (NOT PICO_PLATFORM))
|
||||
set(PICO_PLATFORM $ENV{PICO_PLATFORM})
|
||||
message("Using PICO_PLATFORM from environment ('${PICO_PLATFORM}')")
|
||||
@ -13,7 +13,7 @@ endif ()
|
||||
|
||||
set(PICO_PLATFORM ${PICO_PLATFORM} CACHE STRING "PICO Build platform (e.g. rp2040, host)")
|
||||
|
||||
# PICO_CMAKE_CONFIG: PICO_CMAKE_PRELOAD_PLATFORM_FILE, custom CMake file to use to set up the platform environment, default=none, group=build
|
||||
# PICO_CMAKE_CONFIG: PICO_CMAKE_PRELOAD_PLATFORM_FILE, custom CMake file to use to set up the platform environment, type=string, group=build
|
||||
set(PICO_CMAKE_PRELOAD_PLATFORM_FILE "" CACHE INTERNAL "")
|
||||
set(PICO_CMAKE_PRELOAD_PLATFORM_DIR "${CMAKE_CURRENT_LIST_DIR}/preload/platforms" CACHE INTERNAL "")
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# PICO_CMAKE_CONFIG: PICO_TOOLCHAIN_PATH, Path to search for compiler, default=none (i.e. search system paths), group=build
|
||||
# PICO_CMAKE_CONFIG: PICO_TOOLCHAIN_PATH, Path to search for compiler, type=string, default=none (i.e. search system paths), group=build
|
||||
set(PICO_TOOLCHAIN_PATH "${PICO_TOOLCHAIN_PATH}" CACHE INTERNAL "")
|
||||
|
||||
# Set a default build type if none was specified
|
||||
@ -16,7 +16,7 @@ if (CMAKE_BUILD_TYPE STREQUAL "Default")
|
||||
error("Default build type is NOT supported")
|
||||
endif()
|
||||
|
||||
# PICO_CMAKE_CONFIG: PICO_COMPILER, Optionally specifies a different compiler (other than pico_arm_gcc.cmake) - this is not yet fully supported, default=none, group=build
|
||||
# PICO_CMAKE_CONFIG: PICO_COMPILER, Optionally specifies a different compiler (other than pico_arm_gcc.cmake) - this is not yet fully supported, type=string, group=build
|
||||
# If PICO_COMPILER is specified, set toolchain file to ${PICO_COMPILER}.cmake.
|
||||
if (DEFINED PICO_COMPILER)
|
||||
if (DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||
|
@ -12,7 +12,7 @@ else()
|
||||
endif()
|
||||
set(PICO_BOARD ${PICO_BOARD} CACHE STRING "PICO target board (e.g. pico)" FORCE)
|
||||
|
||||
# PICO_CMAKE_CONFIG: PICO_BOARD_CMAKE_DIRS, Directories to look for <PICO_BOARD>.cmake in. This is overridable from the user environment, type=list, default="", group=build
|
||||
# PICO_CMAKE_CONFIG: PICO_BOARD_CMAKE_DIRS, Directories to look for <PICO_BOARD>.cmake in. This is overridable from the user environment, type=list, group=build
|
||||
if (DEFINED ENV{PICO_BOARD_CMAKE_DIRS})
|
||||
set(PICO_BOARD_CMAKE_DIRS $ENV{PICO_BOARD_CMAKE_DIRS})
|
||||
message("Using PICO_BOARD_CMAKE_DIRS from environment ('${PICO_BOARD_CMAKE_DIRS}')")
|
||||
|
@ -1,6 +1,6 @@
|
||||
# For boards without their own cmake file, simply include a header
|
||||
|
||||
# PICO_CMAKE_CONFIG: PICO_BOARD_HEADER_DIRS, Directories to look for <PICO_BOARD>.h in. This is overridable from the user environment, type=list, default="", group=build
|
||||
# PICO_CMAKE_CONFIG: PICO_BOARD_HEADER_DIRS, Directories to look for <PICO_BOARD>.h in. This is overridable from the user environment, type=list, group=build
|
||||
if (DEFINED ENV{PICO_BOARD_HEADER_DIRS})
|
||||
set(PICO_BOARD_HEADER_DIRS $ENV{PICO_BOARD_HEADER_DIRS})
|
||||
message("Using PICO_BOARD_HEADER_DIRS from environment ('${PICO_BOARD_HEADER_DIRS}')")
|
||||
|
@ -10,11 +10,11 @@ macro(add_header_content_from_var VAR)
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
# PICO_CMAKE_CONFIG: PICO_CONFIG_HEADER_FILES, List of extra header files to include from pico/config.h for all platforms, type=list, default="", group=pico_base
|
||||
# PICO_CMAKE_CONFIG: PICO_CONFIG_HEADER_FILES, List of extra header files to include from pico/config.h for all platforms, type=list, group=pico_base
|
||||
add_header_content_from_var(PICO_CONFIG_HEADER_FILES)
|
||||
|
||||
# PICO_CMAKE_CONFIG: PICO_RP2040_CONFIG_HEADER_FILES, List of extra header files to include from pico/config.h for rp2040 platform, type=list, default="", group=pico_base
|
||||
# PICO_CMAKE_CONFIG: PICO_HOST_CONFIG_HEADER_FILES, List of extra header files to include from pico/config.h for host platform, type=list, default="", group=pico_base
|
||||
# PICO_CMAKE_CONFIG: PICO_RP2040_CONFIG_HEADER_FILES, List of extra header files to include from pico/config.h for rp2040 platform, type=list, group=pico_base
|
||||
# PICO_CMAKE_CONFIG: PICO_HOST_CONFIG_HEADER_FILES, List of extra header files to include from pico/config.h for host platform, type=list, group=pico_base
|
||||
add_header_content_from_var(PICO_${PICO_PLATFORM_UPPER}_CONFIG_HEADER_FILES)
|
||||
|
||||
file(GENERATE
|
||||
|
@ -11,7 +11,7 @@ endif()
|
||||
target_link_libraries(pico_binary_info INTERFACE pico_binary_info_headers)
|
||||
|
||||
function(pico_set_program_name TARGET name)
|
||||
# PICO_BUILD_DEFINE: PICO_PROGRAM_NAME, value passed to pico_set_program_name, type=string, default=none, group=pico_binary_info
|
||||
# PICO_BUILD_DEFINE: PICO_PROGRAM_NAME, value passed to pico_set_program_name, type=string, group=pico_binary_info
|
||||
target_compile_definitions(${TARGET} PRIVATE -DPICO_PROGRAM_NAME="${name}")
|
||||
endfunction()
|
||||
|
||||
@ -19,16 +19,16 @@ function(pico_set_program_description TARGET description)
|
||||
# since this is the command line, we will remove newlines
|
||||
string(REPLACE "\n" " " description ${description})
|
||||
string(REPLACE "\"" "\\\"" description ${description})
|
||||
# PICO_BUILD_DEFINE: PICO_PROGRAM_DESCRIPTION, value passed to pico_set_program_description, type=string, default=none, group=pico_binary_info
|
||||
# PICO_BUILD_DEFINE: PICO_PROGRAM_DESCRIPTION, value passed to pico_set_program_description, type=string, group=pico_binary_info
|
||||
target_compile_definitions(${TARGET} PRIVATE -DPICO_PROGRAM_DESCRIPTION="${description}")
|
||||
endfunction()
|
||||
|
||||
function(pico_set_program_url TARGET url)
|
||||
# PICO_BUILD_DEFINE: PICO_PROGRAM_URL, value passed to pico_set_program_url, type=string, default=none, group=pico_binary_info
|
||||
# PICO_BUILD_DEFINE: PICO_PROGRAM_URL, value passed to pico_set_program_url, type=string, group=pico_binary_info
|
||||
target_compile_definitions(${TARGET} PRIVATE -DPICO_PROGRAM_URL="${url}")
|
||||
endfunction()
|
||||
|
||||
function(pico_set_program_version TARGET version)
|
||||
# PICO_BUILD_DEFINE: PICO_PROGRAM_VERSION_STRING, value passed to pico_set_program_version, type=string, default=none, group=pico_binary_info
|
||||
# PICO_BUILD_DEFINE: PICO_PROGRAM_VERSION_STRING, value passed to pico_set_program_version, type=string, group=pico_binary_info
|
||||
target_compile_definitions(${TARGET} PRIVATE -DPICO_PROGRAM_VERSION_STRING="${version}")
|
||||
endfunction()
|
||||
|
@ -1,5 +1,5 @@
|
||||
# PICO_CMAKE_CONFIG: PICO_DEFAULT_BOOT_STAGE2_FILE, Default boot stage 2 file to use unless overridden by pico_set_boot_stage2 on the TARGET; this setting is useful when explicitly setting the default build from a per board CMake file, group=build
|
||||
# PICO_CMAKE_CONFIG: PICO_DEFAULT_BOOT_STAGE2, Simpler alternative to specifying PICO_DEFAULT_BOOT_STAGE2_FILE where the file is src/rp2_common/boot_stage2/{PICO_DEFAULT_BOOT_STAGE2}.S, default=compile_time_choice, group=build
|
||||
# PICO_CMAKE_CONFIG: PICO_DEFAULT_BOOT_STAGE2_FILE, Default boot stage 2 file to use unless overridden by pico_set_boot_stage2 on the TARGET; this setting is useful when explicitly setting the default build from a per board CMake file, type=string, group=build
|
||||
# PICO_CMAKE_CONFIG: PICO_DEFAULT_BOOT_STAGE2, Simpler alternative to specifying PICO_DEFAULT_BOOT_STAGE2_FILE where the file is src/rp2_common/boot_stage2/{PICO_DEFAULT_BOOT_STAGE2}.S, type=string, default=compile_time_choice, group=build
|
||||
|
||||
if (DEFINED ENV{PICO_DEFAULT_BOOT_STAGE2_FILE})
|
||||
set(PICO_DEFAULT_BOOT_STAGE2_FILE $ENV{PICO_DEFAULT_BOOT_STAGE2_FILE})
|
||||
@ -105,4 +105,4 @@ function(pico_clone_default_boot_stage2 NAME)
|
||||
pico_define_boot_stage2(${NAME} ${PICO_DEFAULT_BOOT_STAGE2_FILE})
|
||||
endfunction()
|
||||
|
||||
pico_promote_common_scope_vars()
|
||||
pico_promote_common_scope_vars()
|
||||
|
@ -18,7 +18,7 @@ if (TARGET tinyusb_device_unmarked)
|
||||
target_link_libraries(pico_stdio_usb INTERFACE
|
||||
tinyusb_device_unmarked
|
||||
)
|
||||
# PICO_CMAKE_CONFIG: PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS, Maximum number of milliseconds to wait during initialization for a CDC connection from the host (negative means indefinite) during initialization, default=0, group=pico_stdio_usb
|
||||
# PICO_CMAKE_CONFIG: PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS, Maximum number of milliseconds to wait during initialization for a CDC connection from the host (negative means indefinite) during initialization, type=int, default=0, group=pico_stdio_usb
|
||||
if (PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS)
|
||||
target_compile_definitions(pico_stdio_usb INTERFACE
|
||||
PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS=${PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS}
|
||||
|
@ -1,8 +1,8 @@
|
||||
# PICO_CMAKE_CONFIG: PICO_STDIO_UART, OPTION: Globally enable stdio UART, default=1, group=pico_stdlib
|
||||
# PICO_CMAKE_CONFIG: PICO_STDIO_UART, OPTION: Globally enable stdio UART, type=bool, default=1, group=pico_stdlib
|
||||
option(PICO_STDIO_UART "Globally enable stdio UART" 1)
|
||||
# PICO_CMAKE_CONFIG: PICO_STDIO_USB, OPTION: Globally enable stdio USB, default=0, group=pico_stdlib
|
||||
# PICO_CMAKE_CONFIG: PICO_STDIO_USB, OPTION: Globally enable stdio USB, type=bool, default=0, group=pico_stdlib
|
||||
option(PICO_STDIO_USB "Globally enable stdio USB" 0)
|
||||
# PICO_CMAKE_CONFIG: PICO_STDIO_SEMIHOSTING, OPTION: Globally enable stdio semihosting, default=0, group=pico_stdlib
|
||||
# PICO_CMAKE_CONFIG: PICO_STDIO_SEMIHOSTING, OPTION: Globally enable stdio semihosting, type=bool, default=0, group=pico_stdlib
|
||||
option(PICO_STDIO_SEMIHOSTING "Globally enable stdio semi-hosting" 0)
|
||||
|
||||
if (NOT TARGET pico_stdlib)
|
||||
|
@ -12,7 +12,7 @@ function(_pico_init_pioasm)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# PICO_CMAKE_CONFIG: PICO_DEFAULT_PIOASM_OUTPUT_FORMAT, default output format used by pioasm when using pico_generate_pio_header, default=c-sdk, group=build
|
||||
# PICO_CMAKE_CONFIG: PICO_DEFAULT_PIOASM_OUTPUT_FORMAT, default output format used by pioasm when using pico_generate_pio_header, type=string, default=c-sdk, group=build
|
||||
function(pico_generate_pio_header TARGET PIO)
|
||||
_pico_init_pioasm()
|
||||
cmake_parse_arguments(pico_generate_pio_header "" "OUTPUT_FORMAT;OUTPUT_DIR" "" ${ARGN} )
|
||||
|
168
tools/extract_build_defines.py
Executable file
168
tools/extract_build_defines.py
Executable file
@ -0,0 +1,168 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
#
|
||||
# Script to scan the Raspberry Pi Pico SDK tree searching for CMake build defines
|
||||
# Outputs a tab separated file of the configuration item:
|
||||
# name location description type default group
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# tools/extract_build_defines.py <root of repo> [output file]
|
||||
#
|
||||
# If not specified, output file will be `pico_build_defines.tsv`
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import csv
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
scandir = sys.argv[1]
|
||||
outfile = sys.argv[2] if len(sys.argv) > 2 else 'pico_build_defines.tsv'
|
||||
|
||||
BUILD_DEFINE_RE = re.compile(r'#\s+PICO_BUILD_DEFINE:\s+(\w+),\s+([^,]+)(?:,\s+(.*))?$')
|
||||
|
||||
all_configs = {}
|
||||
all_attrs = set()
|
||||
all_descriptions = {}
|
||||
|
||||
|
||||
|
||||
def ValidateAttrs(config_attrs, file_path, linenum):
|
||||
_type = config_attrs.get('type')
|
||||
|
||||
# Validate attrs
|
||||
if _type == 'int':
|
||||
_min = _max = _default = None
|
||||
if config_attrs.get('min', None) is not None:
|
||||
value = config_attrs['min']
|
||||
m = re.match(r'^(\d+)e(\d+)$', value.lower())
|
||||
if m:
|
||||
_min = int(m.group(1)) * 10**int(m.group(2))
|
||||
else:
|
||||
_min = int(value, 0)
|
||||
if config_attrs.get('max', None) is not None:
|
||||
value = config_attrs['max']
|
||||
m = re.match(r'^(\d+)e(\d+)$', value.lower())
|
||||
if m:
|
||||
_max = int(m.group(1)) * 10**int(m.group(2))
|
||||
else:
|
||||
_max = int(value, 0)
|
||||
if config_attrs.get('default', None) is not None:
|
||||
if '/' not in config_attrs['default']:
|
||||
try:
|
||||
value = config_attrs['default']
|
||||
m = re.match(r'^(\d+)e(\d+)$', value.lower())
|
||||
if m:
|
||||
_default = int(m.group(1)) * 10**int(m.group(2))
|
||||
else:
|
||||
_default = int(value, 0)
|
||||
except ValueError:
|
||||
pass
|
||||
if _min is not None and _max is not None:
|
||||
if _min > _max:
|
||||
raise Exception('{} at {}:{} has min {} > max {}'.format(config_name, file_path, linenum, config_attrs['min'], config_attrs['max']))
|
||||
if _min is not None and _default is not None:
|
||||
if _min > _default:
|
||||
raise Exception('{} at {}:{} has min {} > default {}'.format(config_name, file_path, linenum, config_attrs['min'], config_attrs['default']))
|
||||
if _default is not None and _max is not None:
|
||||
if _default > _max:
|
||||
raise Exception('{} at {}:{} has default {} > max {}'.format(config_name, file_path, linenum, config_attrs['default'], config_attrs['max']))
|
||||
elif _type == 'bool':
|
||||
assert 'min' not in config_attrs
|
||||
assert 'max' not in config_attrs
|
||||
_default = config_attrs.get('default', None)
|
||||
if _default is not None:
|
||||
if '/' not in _default:
|
||||
if (_default.lower() != '0') and (config_attrs['default'].lower() != '1') and ( _default not in all_configs):
|
||||
logger.info('{} at {}:{} has non-integer default value "{}"'.format(config_name, file_path, linenum, config_attrs['default']))
|
||||
|
||||
elif _type == 'string':
|
||||
assert 'min' not in config_attrs
|
||||
assert 'max' not in config_attrs
|
||||
_default = config_attrs.get('default', None)
|
||||
elif _type == 'list':
|
||||
assert 'min' not in config_attrs
|
||||
assert 'max' not in config_attrs
|
||||
_default = config_attrs.get('default', None)
|
||||
else:
|
||||
raise Exception("Found unknown PICO_BUILD_DEFINE type {} at {}:{}".format(_type, file_path, linenum))
|
||||
|
||||
|
||||
|
||||
|
||||
# Scan all CMakeLists.txt and .cmake 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 == '.cmake':
|
||||
file_path = os.path.join(dirpath, filename)
|
||||
|
||||
with open(file_path, encoding="ISO-8859-1") as fh:
|
||||
linenum = 0
|
||||
for line in fh.readlines():
|
||||
linenum += 1
|
||||
line = line.strip()
|
||||
m = BUILD_DEFINE_RE.match(line)
|
||||
if m:
|
||||
config_name = m.group(1)
|
||||
config_description = m.group(2)
|
||||
_attrs = m.group(3)
|
||||
# allow commas to appear inside brackets by converting them to and from NULL chars
|
||||
_attrs = re.sub(r'(\(.+\))', lambda m: m.group(1).replace(',', '\0'), _attrs)
|
||||
|
||||
if '=' in config_description:
|
||||
raise Exception("For {} at {}:{} the description was set to '{}' - has the description field been omitted?".format(config_name, file_path, linenum, config_description))
|
||||
if config_description in all_descriptions:
|
||||
raise Exception("Found description {} at {}:{} but it was already used at {}:{}".format(config_description, file_path, linenum, os.path.join(scandir, all_descriptions[config_description]['filename']), all_descriptions[config_description]['line_number']))
|
||||
else:
|
||||
all_descriptions[config_description] = {'config_name': config_name, 'filename': os.path.relpath(file_path, scandir), 'line_number': linenum}
|
||||
|
||||
config_attrs = {}
|
||||
prev = None
|
||||
# Handle case where attr value contains a comma
|
||||
for item in _attrs.split(','):
|
||||
if "=" not in item:
|
||||
assert(prev)
|
||||
item = prev + "," + item
|
||||
try:
|
||||
k, v = (i.strip() for i in item.split('='))
|
||||
except ValueError:
|
||||
raise Exception('{} at {}:{} has malformed value {}'.format(config_name, file_path, linenum, item))
|
||||
config_attrs[k] = v.replace('\0', ',')
|
||||
all_attrs.add(k)
|
||||
prev = item
|
||||
#print(file_path, config_name, config_attrs)
|
||||
|
||||
if 'group' not in config_attrs:
|
||||
raise Exception('{} at {}:{} has no group attribute'.format(config_name, file_path, linenum))
|
||||
|
||||
#print(file_path, config_name, config_attrs)
|
||||
if config_name in all_configs:
|
||||
raise Exception("Found {} at {}:{} but it was already declared at {}:{}".format(config_name, file_path, linenum, os.path.join(scandir, all_configs[config_name]['filename']), all_configs[config_name]['line_number']))
|
||||
else:
|
||||
all_configs[config_name] = {'attrs': config_attrs, 'filename': os.path.relpath(file_path, scandir), 'line_number': linenum, 'description': config_description}
|
||||
|
||||
|
||||
for config_name, config_obj in all_configs.items():
|
||||
file_path = os.path.join(scandir, config_obj['filename'])
|
||||
linenum = config_obj['line_number']
|
||||
|
||||
ValidateAttrs(config_obj['attrs'], file_path, linenum)
|
||||
|
||||
with open(outfile, 'w', newline='') as csvfile:
|
||||
fieldnames = ('name', 'location', 'description', 'type') + tuple(sorted(all_attrs - set(['type'])))
|
||||
writer = csv.DictWriter(csvfile, fieldnames=fieldnames, extrasaction='ignore', dialect='excel-tab')
|
||||
|
||||
writer.writeheader()
|
||||
for config_name, config_obj in sorted(all_configs.items()):
|
||||
writer.writerow({'name': config_name, 'location': '/{}:{}'.format(config_obj['filename'], config_obj['line_number']), 'description': config_obj['description'], **config_obj['attrs']})
|
168
tools/extract_cmake_configs.py
Executable file
168
tools/extract_cmake_configs.py
Executable file
@ -0,0 +1,168 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
#
|
||||
# Script to scan the Raspberry Pi Pico SDK tree searching for CMake configuration items
|
||||
# Outputs a tab separated file of the configuration item:
|
||||
# name location description type advanced default group
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# tools/extract_cmake_configs.py <root of repo> [output file]
|
||||
#
|
||||
# If not specified, output file will be `pico_cmake_configs.tsv`
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import csv
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
scandir = sys.argv[1]
|
||||
outfile = sys.argv[2] if len(sys.argv) > 2 else 'pico_cmake_configs.tsv'
|
||||
|
||||
CMAKE_CONFIG_RE = re.compile(r'#\s+PICO_CMAKE_CONFIG:\s+(\w+),\s+([^,]+)(?:,\s+(.*))?$')
|
||||
|
||||
all_configs = {}
|
||||
all_attrs = set()
|
||||
all_descriptions = {}
|
||||
|
||||
|
||||
|
||||
def ValidateAttrs(config_attrs, file_path, linenum):
|
||||
_type = config_attrs.get('type')
|
||||
|
||||
# Validate attrs
|
||||
if _type == 'int':
|
||||
_min = _max = _default = None
|
||||
if config_attrs.get('min', None) is not None:
|
||||
value = config_attrs['min']
|
||||
m = re.match(r'^(\d+)e(\d+)$', value.lower())
|
||||
if m:
|
||||
_min = int(m.group(1)) * 10**int(m.group(2))
|
||||
else:
|
||||
_min = int(value, 0)
|
||||
if config_attrs.get('max', None) is not None:
|
||||
value = config_attrs['max']
|
||||
m = re.match(r'^(\d+)e(\d+)$', value.lower())
|
||||
if m:
|
||||
_max = int(m.group(1)) * 10**int(m.group(2))
|
||||
else:
|
||||
_max = int(value, 0)
|
||||
if config_attrs.get('default', None) is not None:
|
||||
if '/' not in config_attrs['default']:
|
||||
try:
|
||||
value = config_attrs['default']
|
||||
m = re.match(r'^(\d+)e(\d+)$', value.lower())
|
||||
if m:
|
||||
_default = int(m.group(1)) * 10**int(m.group(2))
|
||||
else:
|
||||
_default = int(value, 0)
|
||||
except ValueError:
|
||||
pass
|
||||
if _min is not None and _max is not None:
|
||||
if _min > _max:
|
||||
raise Exception('{} at {}:{} has min {} > max {}'.format(config_name, file_path, linenum, config_attrs['min'], config_attrs['max']))
|
||||
if _min is not None and _default is not None:
|
||||
if _min > _default:
|
||||
raise Exception('{} at {}:{} has min {} > default {}'.format(config_name, file_path, linenum, config_attrs['min'], config_attrs['default']))
|
||||
if _default is not None and _max is not None:
|
||||
if _default > _max:
|
||||
raise Exception('{} at {}:{} has default {} > max {}'.format(config_name, file_path, linenum, config_attrs['default'], config_attrs['max']))
|
||||
elif _type == 'bool':
|
||||
assert 'min' not in config_attrs
|
||||
assert 'max' not in config_attrs
|
||||
_default = config_attrs.get('default', None)
|
||||
if _default is not None:
|
||||
if '/' not in _default:
|
||||
if (_default.lower() != '0') and (config_attrs['default'].lower() != '1') and ( _default not in all_configs):
|
||||
logger.info('{} at {}:{} has non-integer default value "{}"'.format(config_name, file_path, linenum, config_attrs['default']))
|
||||
|
||||
elif _type == 'string':
|
||||
assert 'min' not in config_attrs
|
||||
assert 'max' not in config_attrs
|
||||
_default = config_attrs.get('default', None)
|
||||
elif _type == 'list':
|
||||
assert 'min' not in config_attrs
|
||||
assert 'max' not in config_attrs
|
||||
_default = config_attrs.get('default', None)
|
||||
else:
|
||||
raise Exception("Found unknown PICO_CMAKE_CONFIG type {} at {}:{}".format(_type, file_path, linenum))
|
||||
|
||||
|
||||
|
||||
|
||||
# Scan all CMakeLists.txt and .cmake 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 == '.cmake':
|
||||
file_path = os.path.join(dirpath, filename)
|
||||
|
||||
with open(file_path, encoding="ISO-8859-1") as fh:
|
||||
linenum = 0
|
||||
for line in fh.readlines():
|
||||
linenum += 1
|
||||
line = line.strip()
|
||||
m = CMAKE_CONFIG_RE.match(line)
|
||||
if m:
|
||||
config_name = m.group(1)
|
||||
config_description = m.group(2)
|
||||
_attrs = m.group(3)
|
||||
# allow commas to appear inside brackets by converting them to and from NULL chars
|
||||
_attrs = re.sub(r'(\(.+\))', lambda m: m.group(1).replace(',', '\0'), _attrs)
|
||||
|
||||
if '=' in config_description:
|
||||
raise Exception("For {} at {}:{} the description was set to '{}' - has the description field been omitted?".format(config_name, file_path, linenum, config_description))
|
||||
if config_description in all_descriptions:
|
||||
raise Exception("Found description {} at {}:{} but it was already used at {}:{}".format(config_description, file_path, linenum, os.path.join(scandir, all_descriptions[config_description]['filename']), all_descriptions[config_description]['line_number']))
|
||||
else:
|
||||
all_descriptions[config_description] = {'config_name': config_name, 'filename': os.path.relpath(file_path, scandir), 'line_number': linenum}
|
||||
|
||||
config_attrs = {}
|
||||
prev = None
|
||||
# Handle case where attr value contains a comma
|
||||
for item in _attrs.split(','):
|
||||
if "=" not in item:
|
||||
assert(prev)
|
||||
item = prev + "," + item
|
||||
try:
|
||||
k, v = (i.strip() for i in item.split('='))
|
||||
except ValueError:
|
||||
raise Exception('{} at {}:{} has malformed value {}'.format(config_name, file_path, linenum, item))
|
||||
config_attrs[k] = v.replace('\0', ',')
|
||||
all_attrs.add(k)
|
||||
prev = item
|
||||
#print(file_path, config_name, config_attrs)
|
||||
|
||||
if 'group' not in config_attrs:
|
||||
raise Exception('{} at {}:{} has no group attribute'.format(config_name, file_path, linenum))
|
||||
|
||||
#print(file_path, config_name, config_attrs)
|
||||
if config_name in all_configs:
|
||||
raise Exception("Found {} at {}:{} but it was already declared at {}:{}".format(config_name, file_path, linenum, os.path.join(scandir, all_configs[config_name]['filename']), all_configs[config_name]['line_number']))
|
||||
else:
|
||||
all_configs[config_name] = {'attrs': config_attrs, 'filename': os.path.relpath(file_path, scandir), 'line_number': linenum, 'description': config_description}
|
||||
|
||||
|
||||
for config_name, config_obj in all_configs.items():
|
||||
file_path = os.path.join(scandir, config_obj['filename'])
|
||||
linenum = config_obj['line_number']
|
||||
|
||||
ValidateAttrs(config_obj['attrs'], file_path, linenum)
|
||||
|
||||
with open(outfile, 'w', newline='') as csvfile:
|
||||
fieldnames = ('name', 'location', 'description', 'type') + tuple(sorted(all_attrs - set(['type'])))
|
||||
writer = csv.DictWriter(csvfile, fieldnames=fieldnames, extrasaction='ignore', dialect='excel-tab')
|
||||
|
||||
writer.writeheader()
|
||||
for config_name, config_obj in sorted(all_configs.items()):
|
||||
writer.writerow({'name': config_name, 'location': '/{}:{}'.format(config_obj['filename'], config_obj['line_number']), 'description': config_obj['description'], **config_obj['attrs']})
|
Loading…
x
Reference in New Issue
Block a user