mirror of
https://github.com/esphome/esphome.git
synced 2026-10-07 11:26:39 +00:00
[host] Build natively with ninja instead of PlatformIO (#19214)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
co-authored by
J. Nick Koston
parent
bb7af14012
commit
32e11c4f4a
+10
-11
@@ -22,8 +22,8 @@ from esphome.__main__ import command_compile, parse_args
|
||||
from esphome.config import validate_config
|
||||
from esphome.const import CONF_PLATFORM
|
||||
from esphome.core import CORE
|
||||
from esphome.host.toolchain import get_elf_path
|
||||
from esphome.loader import get_component, get_platform
|
||||
from esphome.platformio.toolchain import get_idedata
|
||||
from tests.testing_helpers import ComponentManifestOverride, set_testing_manifest
|
||||
|
||||
# This must coincide with the version in /platformio.ini
|
||||
@@ -220,7 +220,7 @@ def create_host_config(
|
||||
friendly_name: str,
|
||||
libraries: str | list[str],
|
||||
includes: list[str],
|
||||
platformio_options: dict,
|
||||
build_flags: list[str],
|
||||
) -> dict:
|
||||
"""Create an ESPHome host configuration for C++ builds.
|
||||
|
||||
@@ -229,7 +229,7 @@ def create_host_config(
|
||||
friendly_name: Human-readable name
|
||||
libraries: PlatformIO library specification(s)
|
||||
includes: List of include folders for the build
|
||||
platformio_options: Dict of platformio_options to set
|
||||
build_flags: Compiler/linker flags for the build
|
||||
|
||||
Returns:
|
||||
Configuration dict for ESPHome
|
||||
@@ -239,7 +239,7 @@ def create_host_config(
|
||||
"name": config_name,
|
||||
"friendly_name": friendly_name,
|
||||
"libraries": libraries,
|
||||
"platformio_options": platformio_options,
|
||||
"build_flags": build_flags,
|
||||
"includes": includes,
|
||||
},
|
||||
HOST_KEY: {},
|
||||
@@ -403,13 +403,12 @@ def compile_and_get_binary(
|
||||
return EXIT_COMPILE_ERROR, None
|
||||
|
||||
# After a successful compilation, locate the executable:
|
||||
idedata = get_idedata(config)
|
||||
if idedata is None:
|
||||
program_path = get_elf_path()
|
||||
if not program_path.is_file():
|
||||
print("Cannot find executable")
|
||||
return EXIT_NO_EXECUTABLE, None
|
||||
|
||||
program_path: str = idedata.raw["prog_path"]
|
||||
return EXIT_OK, program_path
|
||||
return EXIT_OK, str(program_path)
|
||||
|
||||
|
||||
def build_and_run(
|
||||
@@ -419,7 +418,7 @@ def build_and_run(
|
||||
config_prefix: str,
|
||||
friendly_name: str,
|
||||
libraries: str | list[str],
|
||||
platformio_options: dict,
|
||||
build_flags: list[str],
|
||||
main_entry: str,
|
||||
label: str = "build",
|
||||
build_only: bool = False,
|
||||
@@ -438,7 +437,7 @@ def build_and_run(
|
||||
config_prefix: Prefix for the config name (e.g. "cpptests", "cppbench")
|
||||
friendly_name: Human-readable name for the config
|
||||
libraries: PlatformIO library specification(s)
|
||||
platformio_options: PlatformIO options dict
|
||||
build_flags: Compiler/linker flags for the build
|
||||
main_entry: Name of the main entry file (e.g. "main.cpp")
|
||||
label: Label for log messages
|
||||
build_only: If True, print binary path and return without running
|
||||
@@ -488,7 +487,7 @@ def build_and_run(
|
||||
config_name: str = f"{config_prefix}-" + hash_components(components)
|
||||
|
||||
config = create_host_config(
|
||||
config_name, friendly_name, libraries, includes, platformio_options
|
||||
config_name, friendly_name, libraries, includes, build_flags
|
||||
)
|
||||
|
||||
exit_code, program_path = compile_and_get_binary(
|
||||
|
||||
+11
-19
@@ -25,19 +25,14 @@ CORE_BENCHMARKS_DIR: Path = Path(root_path) / "tests" / "benchmarks" / "core"
|
||||
# allow benchmarks to compile on the host platform.
|
||||
STUBS_DIR: Path = Path(root_path) / "tests" / "benchmarks" / "stubs"
|
||||
|
||||
PLATFORMIO_OPTIONS = {
|
||||
"build_flags": [
|
||||
"-Os", # match firmware optimization level (detects inlining regressions)
|
||||
"-g", # debug symbols for profiling
|
||||
"-ffunction-sections", # required for dead-code stripping with -Os
|
||||
"-fdata-sections", # required for dead-code stripping with -Os
|
||||
"-DUSE_BENCHMARK", # disable WarnIfComponentBlockingGuard in finish()
|
||||
f"-I{STUBS_DIR}", # stub headers for ESP32-only components
|
||||
],
|
||||
# Use deep+ LDF mode to ensure PlatformIO detects the benchmark
|
||||
# library dependency from nested includes.
|
||||
"lib_ldf_mode": "deep+",
|
||||
}
|
||||
BUILD_FLAGS = [
|
||||
"-Os", # match firmware optimization level (detects inlining regressions)
|
||||
"-g", # debug symbols for profiling
|
||||
"-ffunction-sections", # required for dead-code stripping with -Os
|
||||
"-fdata-sections", # required for dead-code stripping with -Os
|
||||
"-DUSE_BENCHMARK", # disable WarnIfComponentBlockingGuard in finish()
|
||||
f"-I{STUBS_DIR}", # stub headers for ESP32-only components
|
||||
]
|
||||
|
||||
|
||||
def run_benchmarks(selected_components: list[str], build_only: bool = False) -> int:
|
||||
@@ -46,7 +41,7 @@ def run_benchmarks(selected_components: list[str], build_only: bool = False) ->
|
||||
# containing {"lib_path": "/path/to/google_benchmark"}.
|
||||
lib_config_json = os.environ.get("BENCHMARK_LIB_CONFIG")
|
||||
|
||||
pio_options = PLATFORMIO_OPTIONS
|
||||
build_flags = BUILD_FLAGS
|
||||
if lib_config_json:
|
||||
lib_config = json.loads(lib_config_json)
|
||||
benchmark_lib = f"benchmark=symlink://{lib_config['lib_path']}"
|
||||
@@ -61,10 +56,7 @@ def run_benchmarks(selected_components: list[str], build_only: bool = False) ->
|
||||
"-DCODSPEED_ANALYSIS",
|
||||
f'-DCODSPEED_ROOT_DIR=\\"{project_root}\\"',
|
||||
]
|
||||
pio_options = {
|
||||
**PLATFORMIO_OPTIONS,
|
||||
"build_flags": PLATFORMIO_OPTIONS["build_flags"] + codspeed_flags,
|
||||
}
|
||||
build_flags = BUILD_FLAGS + codspeed_flags
|
||||
else:
|
||||
benchmark_lib = PLATFORMIO_GOOGLE_BENCHMARK_LIB
|
||||
|
||||
@@ -77,7 +69,7 @@ def run_benchmarks(selected_components: list[str], build_only: bool = False) ->
|
||||
config_prefix="cppbench",
|
||||
friendly_name="CPP Benchmarks",
|
||||
libraries=benchmark_lib,
|
||||
platformio_options=pio_options,
|
||||
build_flags=build_flags,
|
||||
main_entry="main.cpp",
|
||||
label="benchmarks",
|
||||
build_only=build_only,
|
||||
|
||||
+11
-19
@@ -15,24 +15,16 @@ from helpers import get_all_components, root_path
|
||||
# Path to /tests/components
|
||||
COMPONENTS_TESTS_DIR: Path = Path(root_path) / "tests" / "components"
|
||||
|
||||
PLATFORMIO_OPTIONS = {
|
||||
"build_type": "debug",
|
||||
"build_unflags": [
|
||||
"-Os", # remove size-opt flag
|
||||
],
|
||||
"build_flags": [
|
||||
"-Og", # optimize for debug
|
||||
"-DESPHOME_DEBUG", # enable debug assertions
|
||||
# Enable the address and undefined behavior sanitizers
|
||||
"-fsanitize=address",
|
||||
"-fsanitize=undefined",
|
||||
"-fno-omit-frame-pointer",
|
||||
],
|
||||
"debug_build_flags": [ # only for debug builds
|
||||
"-g3", # max debug info
|
||||
"-ggdb3",
|
||||
],
|
||||
}
|
||||
BUILD_FLAGS = [
|
||||
"-Og", # optimize for debug
|
||||
"-g3", # max debug info
|
||||
"-ggdb3",
|
||||
"-DESPHOME_DEBUG", # enable debug assertions
|
||||
# Enable the address and undefined behavior sanitizers
|
||||
"-fsanitize=address",
|
||||
"-fsanitize=undefined",
|
||||
"-fno-omit-frame-pointer",
|
||||
]
|
||||
|
||||
|
||||
def run_tests(selected_components: list[str]) -> int:
|
||||
@@ -47,7 +39,7 @@ def run_tests(selected_components: list[str]) -> int:
|
||||
config_prefix="cpptests",
|
||||
friendly_name="CPP Unit Tests",
|
||||
libraries=PLATFORMIO_GOOGLE_TEST_LIB,
|
||||
platformio_options=PLATFORMIO_OPTIONS,
|
||||
build_flags=BUILD_FLAGS,
|
||||
main_entry="main.cpp",
|
||||
label="unit tests",
|
||||
)
|
||||
|
||||
@@ -111,14 +111,25 @@ INTEGRATION_TESTS_SPLIT_THRESHOLD = 10
|
||||
INTEGRATION_TESTS_SPLIT_BUCKETS = 5
|
||||
INTEGRATION_TESTS_TARGET_BUCKET_WEIGHT = 360.0
|
||||
|
||||
# platformio and aioesphomeapi (requirements.txt), the pytest stack
|
||||
# (requirements_test.txt) and the fixture every session compiles; a change
|
||||
# to any runs the full matrix
|
||||
# aioesphomeapi (requirements.txt), the pytest stack (requirements_test.txt)
|
||||
# and the native host build backend every test compiles with; a change to
|
||||
# any runs the full matrix
|
||||
INTEGRATION_TESTS_TRIGGER_FILES = frozenset(
|
||||
{
|
||||
"requirements.txt",
|
||||
"requirements_test.txt",
|
||||
"tests/integration/fixtures/cache_init.yaml",
|
||||
"esphome/arduino/library.py",
|
||||
"esphome/build_gen/build_tool.py",
|
||||
"esphome/build_gen/host.py",
|
||||
"esphome/build_helpers/ccache.py",
|
||||
"esphome/build_helpers/idedata.py",
|
||||
"esphome/build_helpers/native.py",
|
||||
"esphome/build_helpers/ninja.py",
|
||||
"esphome/build_helpers/ninja_gen.py",
|
||||
"esphome/build_helpers/tools_cache.py",
|
||||
"esphome/framework_helpers.py",
|
||||
"esphome/host/toolchain.py",
|
||||
"esphome/platformio/library.py",
|
||||
}
|
||||
)
|
||||
|
||||
@@ -240,7 +251,7 @@ def determine_integration_tests(branch: str | None = None) -> tuple[bool, list[s
|
||||
- conftest.py, types.py, const.py, entity_utils.py, state_utils.py, etc.
|
||||
|
||||
4. A file in INTEGRATION_TESTS_TRIGGER_FILES changed
|
||||
- The dependency pins and the session init fixture affect every test
|
||||
- The dependency pins and the host build backend affect every test
|
||||
|
||||
Returns (run_all=False, [test_files...]) when:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user