From 74b075d3cff8fea73f931880ace85af5cb621c7b Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 22 Dec 2025 07:03:17 -1000 Subject: [PATCH] [codegen] Add static storage class to global variables for size optimization (#12616) --- esphome/components/lvgl/__init__.py | 2 ++ esphome/components/lvgl/lvcode.py | 4 ++-- esphome/components/mapping/__init__.py | 2 +- esphome/cpp_generator.py | 22 +++++++++++++++------- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/esphome/components/lvgl/__init__.py b/esphome/components/lvgl/__init__.py index 19c258fcd..c9cad1ac9 100644 --- a/esphome/components/lvgl/__init__.py +++ b/esphome/components/lvgl/__init__.py @@ -256,9 +256,11 @@ async def to_code(configs): True, type=lv_font_t.operator("ptr").operator("const"), ) + # static=False because LV_FONT_CUSTOM_DECLARE creates an extern declaration cg.new_variable( globfont_id, MockObj(await lvalid.lv_font.process(default_font), "->").get_lv_font(), + static=False, ) add_define("LV_FONT_DEFAULT", df.DEFAULT_ESPHOME_FONT) else: diff --git a/esphome/components/lvgl/lvcode.py b/esphome/components/lvgl/lvcode.py index c11597131..e2c70642a 100644 --- a/esphome/components/lvgl/lvcode.py +++ b/esphome/components/lvgl/lvcode.py @@ -337,7 +337,7 @@ def lv_Pvariable(type, name) -> MockObj: """ if isinstance(name, str): name = ID(name, True, type) - decl = VariableDeclarationExpression(type, "*", name) + decl = VariableDeclarationExpression(type, "*", name, static=True) CORE.add_global(decl) var = MockObj(name, "->") CORE.register_variable(name, var) @@ -353,7 +353,7 @@ def lv_variable(type, name) -> MockObj: """ if isinstance(name, str): name = ID(name, True, type) - decl = VariableDeclarationExpression(type, "", name) + decl = VariableDeclarationExpression(type, "", name, static=True) CORE.add_global(decl) var = MockObj(name, ".") CORE.register_variable(name, var) diff --git a/esphome/components/mapping/__init__.py b/esphome/components/mapping/__init__.py index 94c7c10a8..a36b414fd 100644 --- a/esphome/components/mapping/__init__.py +++ b/esphome/components/mapping/__init__.py @@ -133,7 +133,7 @@ async def to_code(config): value_type, ) var = MockObj(varid, ".") - decl = VariableDeclarationExpression(varid.type, "", varid) + decl = VariableDeclarationExpression(varid.type, "", varid, static=True) add_global(decl) CORE.register_variable(varid, var) diff --git a/esphome/cpp_generator.py b/esphome/cpp_generator.py index 1a47b346b..ddccb574e 100644 --- a/esphome/cpp_generator.py +++ b/esphome/cpp_generator.py @@ -51,15 +51,19 @@ class AssignmentExpression(Expression): class VariableDeclarationExpression(Expression): - __slots__ = ("type", "modifier", "name") + __slots__ = ("type", "modifier", "name", "static") - def __init__(self, type_, modifier, name): + def __init__( + self, type_: "MockObj", modifier: str, name: ID, *, static: bool = False + ) -> None: self.type = type_ self.modifier = modifier self.name = name + self.static = static - def __str__(self): - return f"{self.type} {self.modifier}{self.name}" + def __str__(self) -> str: + prefix = "static " if self.static else "" + return f"{prefix}{self.type} {self.modifier}{self.name}" class ExpressionList(Expression): @@ -507,13 +511,17 @@ def with_local_variable(id_: ID, rhs: SafeExpType, callback: Callable, *args) -> CORE.add(RawStatement("}")) # output closing curly brace -def new_variable(id_: ID, rhs: SafeExpType, type_: "MockObj" = None) -> "MockObj": +def new_variable( + id_: ID, rhs: SafeExpType, type_: "MockObj" = None, *, static: bool = True +) -> "MockObj": """Declare and define a new variable, not pointer type, in the code generation. :param id_: The ID used to declare the variable. :param rhs: The expression to place on the right hand side of the assignment. :param type_: Manually define a type for the variable, only use this when it's not possible to do so during config validation phase (for example because of template arguments). + :param static: If True (default), declare with static storage class for optimization. + Set to False when the variable must have external linkage (e.g., to match library declarations). :return: The new variable as a MockObj. """ @@ -522,7 +530,7 @@ def new_variable(id_: ID, rhs: SafeExpType, type_: "MockObj" = None) -> "MockObj obj = MockObj(id_, ".") if type_ is not None: id_.type = type_ - decl = VariableDeclarationExpression(id_.type, "", id_) + decl = VariableDeclarationExpression(id_.type, "", id_, static=static) CORE.add_global(decl) assignment = AssignmentExpression(None, "", id_, rhs) CORE.add(assignment) @@ -544,7 +552,7 @@ def Pvariable(id_: ID, rhs: SafeExpType, type_: "MockObj" = None) -> "MockObj": obj = MockObj(id_, "->") if type_ is not None: id_.type = type_ - decl = VariableDeclarationExpression(id_.type, "*", id_) + decl = VariableDeclarationExpression(id_.type, "*", id_, static=True) CORE.add_global(decl) assignment = AssignmentExpression(None, None, id_, rhs) CORE.add(assignment)