diff --git a/builder/frameworks/base.py b/builder/frameworks/base.py index 4cef734..9d4011b 100644 --- a/builder/frameworks/base.py +++ b/builder/frameworks/base.py @@ -3,7 +3,7 @@ from os.path import join import click -from ltchiptool import Family, get_version +from ltchiptool import Family from platformio.platform.base import PlatformBase from platformio.platform.board import PlatformBoardConfig from SCons.Errors import UserError @@ -14,11 +14,10 @@ board: PlatformBoardConfig = env.BoardConfig() platform: PlatformBase = env.PioPlatform() family: Family = env["FAMILY_OBJ"] -# Print information about installed core versions -lt_version: str = env.ReadLTVersion(platform.get_dir(), platform.version) -print("PLATFORM VERSIONS:") -print(" - libretuya @", lt_version) -print(" - ltchiptool @", get_version()) +# Print information about versions and custom options +env.PrintInfo(platform) +# Apply custom header options +env.ApplyCustomOptions(platform) # TODO remove include path prepending ("!<...>") # Move common core sources (env.AddCoreSources()) and Arduino libs @@ -114,7 +113,7 @@ queue.AppendPublic( ], CPPDEFINES=[ ("LIBRETUYA", 1), - ("LT_VERSION", lt_version), + ("LT_VERSION", env["LT_VERSION"]), ("LT_BOARD", "${VARIANT}"), ("LT_VARIANT_H", r"\"${VARIANT}.h\""), ("F_CPU", board.get("build.f_cpu")), diff --git a/builder/main.py b/builder/main.py index cf4f202..b3223c8 100644 --- a/builder/main.py +++ b/builder/main.py @@ -51,6 +51,8 @@ env.Replace( env.ConfigureEnvironment(platform, board) # Flash layout defines env.AddFlashLayout(board) +# Parse custom options +env.ParseCustomOptions(platform) # Family builders details: # - call env.AddLibrary("lib name", "base dir", [sources]) to add lib sources diff --git a/builder/utils/env.py b/builder/utils/env.py index 55ebf2b..f50281d 100644 --- a/builder/utils/env.py +++ b/builder/utils/env.py @@ -2,10 +2,12 @@ import json import sys +from os import makedirs from os.path import isdir, join from subprocess import PIPE, Popen +from typing import Dict -from ltchiptool import Family +from ltchiptool import Family, get_version from platformio.platform.base import PlatformBase from platformio.platform.board import PlatformBoardConfig from SCons.Script import DefaultEnvironment, Environment @@ -13,7 +15,7 @@ from SCons.Script import DefaultEnvironment, Environment env: Environment = DefaultEnvironment() -def env_read_version(env: Environment, platform_dir: str, version: str): +def read_version(platform_dir: str, version: str): if not isdir(join(platform_dir, ".git")): sys.stderr.write("Warning! Non-Git installations are NOT SUPPORTED.\n") return version @@ -61,6 +63,7 @@ def env_configure( LT_DIR=platform.get_dir(), CORES_DIR=join("${LT_DIR}", "cores"), COMMON_DIR=join("${LT_DIR}", "cores", "common"), + LT_VERSION=read_version(platform.get_dir(), platform.version), # Build directories & paths VARIANTS_DIR=join("${LT_DIR}", "boards", "variants"), FAMILY_DIR=join("${LT_DIR}", "cores", "${FAMILY_NAME}"), @@ -86,5 +89,90 @@ def env_configure( return family +def env_print_info(env: Environment, platform: PlatformBase): + TAB = " " * 4 + + def dump(k, v, indent=""): + k = k.replace("#", ".") + if isinstance(v, dict): + print(f"{indent} - {k}:") + for k, v in v.items(): + dump(k, v, indent + TAB) + elif isinstance(v, list): + print(f"{indent} - {k}:") + for k, v in enumerate(v): + dump(k, v, indent + TAB) + else: + print(f"{indent} - {k} = {v}") + + # Print information about installed core versions + print("PLATFORM VERSIONS:") + print(" - libretuya @", env["LT_VERSION"]) + print(" - ltchiptool @", get_version()) + # Print custom platformio.ini options + if platform.custom_opts: + print("CUSTOM OPTIONS:") + for k, v in platform.custom_opts.items(): + dump(k, v) + + +def env_parse_custom_options(env: Environment, platform: PlatformBase): + opts = platform.custom_opts.get("options", None) + if not opts: + return + headers = { + "lwip": "lwipopts.h", + "freertos": "FreeRTOSConfig.h", + } + for header, options in list(opts.items()): + if not isinstance(options, str): + raise TypeError("Options value should be str") + options = options.strip().splitlines() + opts_dict = {} + for line in options: + if "=" not in line: + raise ValueError(f"Invalid option: {line}") + k, _, v = line.partition("=") + k = k.strip() + v = v.strip() + opts_dict[k] = v + # replace predefined header names + opts.pop(header) + header = headers.get(header, header) + header = header.replace(".", "#") + opts[header] = opts_dict + + +def env_apply_custom_options(env: Environment, platform: PlatformBase): + opts = platform.custom_opts.get("options", None) + if not opts: + return + header_dir = join("${BUILD_DIR}", "include") + real_dir = env.subst(header_dir) + makedirs(real_dir, exist_ok=True) + + for header, options in opts.items(): + header: str + options: Dict[str, str] + # open the header file for writing + header = header.replace("#", ".") + f = open(join(real_dir, header), "w") + f.write(f'#include_next "{header}"\n' "\n" "#pragma once\n" "\n") + # write all #defines + for k, v in options.items(): + f.write( + f"// {k} = {v}\n" + f"#ifdef {k}\n" + f"#undef {k}\n" + f"#endif\n" + f"#define {k} {v}\n" + ) + f.close() + # prepend newly created headers before any other + env.Prepend(CPPPATH=[header_dir]) + + env.AddMethod(env_configure, "ConfigureEnvironment") -env.AddMethod(env_read_version, "ReadLTVersion") +env.AddMethod(env_print_info, "PrintInfo") +env.AddMethod(env_parse_custom_options, "ParseCustomOptions") +env.AddMethod(env_apply_custom_options, "ApplyCustomOptions") diff --git a/platform.py b/platform.py index 5d7d543..18256a1 100644 --- a/platform.py +++ b/platform.py @@ -1,6 +1,7 @@ # Copyright (c) Kuba SzczodrzyƄski 2022-04-20. import importlib +import json import platform import sys from os import system @@ -110,6 +111,11 @@ class LibretuyaPlatform(PlatformBase): self.custom_opts = {} self.versions = {} + def print(self, *args, **kwargs): + if not self.verbose: + return + print(*args, **kwargs) + def get_package_spec(self, name, version=None): # make PlatformIO detach existing package versions instead of overwriting # TODO this is an ugly hack, it moves old packages to dirs like "library-lwip@src-21d717f2feaca73533f129ce05c9f4d4" @@ -121,6 +127,10 @@ class LibretuyaPlatform(PlatformBase): def configure_default_packages(self, options, targets): from ltchiptool.util.dict import RecursiveDict + self.verbose = ( + "-v" in sys.argv or "--verbose" in sys.argv or "PIOVERBOSE=1" in sys.argv + ) + pioframework = options.get("pioframework") or ["base"] if not pioframework: return @@ -131,7 +141,13 @@ class LibretuyaPlatform(PlatformBase): for key, value in options.items(): if not key.startswith("custom_"): continue - self.custom_opts[key[7:]] = value + key = key[7:] + parent, sep, child = key.partition(".") + if parent == "options": + # allow only one level of nesting ('child' may be a header name, which contains a dot) + child = child.replace(".", "#") + self.custom_opts[parent + sep + child] = value + self.print("Custom options:", json.dumps(self.custom_opts, indent="\t")) # update framework names to their new values since v1.0.0 if framework.endswith("-sdk"):