mirror of
https://github.com/esphome/esphome.git
synced 2025-07-06 07:03:16 +01:00
125 lines
4.2 KiB
Python
125 lines
4.2 KiB
Python
import json
|
|
from pathlib import Path
|
|
import re
|
|
import subprocess
|
|
|
|
|
|
def load_idedata(environment, temp_folder, platformio_ini):
|
|
build_environment = environment.replace("-tidy", "")
|
|
build_dir = Path(temp_folder) / f"build-{build_environment}"
|
|
Path(build_dir).mkdir(exist_ok=True)
|
|
Path(build_dir / "platformio.ini").write_text(
|
|
Path(platformio_ini).read_text(encoding="utf-8"), encoding="utf-8"
|
|
)
|
|
esphome_dir = Path(build_dir / "esphome")
|
|
esphome_dir.mkdir(exist_ok=True)
|
|
Path(esphome_dir / "main.cpp").write_text(
|
|
"""
|
|
#include <zephyr/kernel.h>
|
|
int main() { return 0;}
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
zephyr_dir = Path(build_dir / "zephyr")
|
|
zephyr_dir.mkdir(exist_ok=True)
|
|
Path(zephyr_dir / "prj.conf").write_text(
|
|
"""
|
|
CONFIG_NEWLIB_LIBC=y
|
|
""",
|
|
encoding="utf-8",
|
|
)
|
|
subprocess.run(["pio", "run", "-e", build_environment, "-d", build_dir], check=True)
|
|
|
|
def extract_include_paths(command):
|
|
include_paths = []
|
|
include_pattern = re.compile(r'("-I\s*[^"]+)|(-isystem\s*[^\s]+)|(-I\s*[^\s]+)')
|
|
for match in include_pattern.findall(command):
|
|
split_strings = re.split(
|
|
r"\s*-\s*(?:I|isystem)", list(filter(lambda x: x, match))[0]
|
|
)
|
|
include_paths.append(split_strings[1])
|
|
return include_paths
|
|
|
|
def extract_defines(command):
|
|
defines = []
|
|
define_pattern = re.compile(r"-D\s*([^\s]+)")
|
|
for match in define_pattern.findall(command):
|
|
if match not in ("_ASMLANGUAGE"):
|
|
defines.append(match)
|
|
return defines
|
|
|
|
def find_cxx_path(commands):
|
|
for entry in commands:
|
|
command = entry["command"]
|
|
cxx_path = command.split()[0]
|
|
if not cxx_path.endswith("++"):
|
|
continue
|
|
return cxx_path
|
|
|
|
def get_builtin_include_paths(compiler):
|
|
result = subprocess.run(
|
|
[compiler, "-E", "-x", "c++", "-", "-v"],
|
|
input="",
|
|
text=True,
|
|
stderr=subprocess.PIPE,
|
|
stdout=subprocess.DEVNULL,
|
|
check=True,
|
|
)
|
|
include_paths = []
|
|
start_collecting = False
|
|
for line in result.stderr.splitlines():
|
|
if start_collecting:
|
|
if line.startswith(" "):
|
|
include_paths.append(line.strip())
|
|
else:
|
|
break
|
|
if "#include <...> search starts here:" in line:
|
|
start_collecting = True
|
|
return include_paths
|
|
|
|
def extract_cxx_flags(command):
|
|
flags = []
|
|
# Extracts CXXFLAGS from the command string, excluding includes and defines.
|
|
flag_pattern = re.compile(
|
|
r"(-O[0-3s]|-g|-std=[^\s]+|-Wall|-Wextra|-Werror|--[^\s]+|-f[^\s]+|-m[^\s]+|-imacros\s*[^\s]+)"
|
|
)
|
|
for match in flag_pattern.findall(command):
|
|
flags.append(match.replace("-imacros ", "-imacros"))
|
|
return flags
|
|
|
|
def transform_to_idedata_format(compile_commands):
|
|
cxx_path = find_cxx_path(compile_commands)
|
|
idedata = {
|
|
"includes": {
|
|
"toolchain": get_builtin_include_paths(cxx_path),
|
|
"build": set(),
|
|
},
|
|
"defines": set(),
|
|
"cxx_path": cxx_path,
|
|
"cxx_flags": set(),
|
|
}
|
|
|
|
for entry in compile_commands:
|
|
command = entry["command"]
|
|
exec = command.split()[0]
|
|
if exec != cxx_path:
|
|
continue
|
|
|
|
idedata["includes"]["build"].update(extract_include_paths(command))
|
|
idedata["defines"].update(extract_defines(command))
|
|
idedata["cxx_flags"].update(extract_cxx_flags(command))
|
|
|
|
# Convert sets to lists for JSON serialization
|
|
idedata["includes"]["build"] = list(idedata["includes"]["build"])
|
|
idedata["defines"] = list(idedata["defines"])
|
|
idedata["cxx_flags"] = list(idedata["cxx_flags"])
|
|
|
|
return idedata
|
|
|
|
compile_commands = json.loads(
|
|
Path(
|
|
build_dir / ".pio" / "build" / build_environment / "compile_commands.json"
|
|
).read_text(encoding="utf-8")
|
|
)
|
|
return transform_to_idedata_format(compile_commands)
|