Files
xiaozhi-esp32/managed_components/lvgl__lvgl/scripts/preprocess_lv_conf_internal.py
2025-09-05 13:25:11 +08:00

193 lines
5.6 KiB
Python

#!/usr/bin/env python3
#
# Preprocess the lv_conf_internal.h to generate a header file
# containing the evaluated definitions. This output will be used to
# generate the cmake variables
#
# Author: David TRUAN (david.truan@edgemtech.ch)
# Author: Erik Tagirov (erik.tagirov@edgemtech.ch)
#
import sys
import subprocess
import os
import argparse
import re
import importlib.util
def get_args():
parser = argparse.ArgumentParser(description="Preprocess a C header file and remove indentation.")
parser.add_argument("--input", help="Path to the input C header file", required=True)
parser.add_argument("--tmp_file", help="Path to save the preprocessed output", required=True)
parser.add_argument("--output", help="Path to save the cleaned output with removed indentation", required=True)
parser.add_argument("--workfolder", help="Path used to create a python environnement", required=True)
parser.add_argument(
"--defs",
nargs='+',
default=[],
help="Definitions to be added to pcpp (flag -D)"
)
parser.add_argument(
"--include",
nargs='+',
default=[],
help="Paths to include directories for the preprocessor (flag -I)"
)
return parser.parse_args()
def preprocess_file(pcpp_exe, input_file, tmp_file, output_file, include_dirs, defs):
try:
pcpp_command = [pcpp_exe, "-o", tmp_file, "--passthru-defines", "--line-directive=", input_file]
for include_path in include_dirs:
pcpp_command.append(f"-I{include_path}")
for definition in defs:
pcpp_command.append(f"-D{definition}")
subprocess.run(pcpp_command, check=True)
print(f"Preprocessing completed. Output saved to {tmp_file}")
except subprocess.CalledProcessError as e:
print(f"Error during preprocessing: {e}")
exit(1)
# Read the temporary files and return an array of lines
def read_lines(tmp_file):
try:
with open(tmp_file, "r") as f:
lines = f.readlines()
except Exception as e:
print(f"Failed to pre-process file: {e}")
exit(1)
return lines
def remove_indentation(lines):
clean_lines = []
try:
for line in lines:
stripped = line.lstrip()
# Remove extra spaces after #
if stripped.startswith("#"):
stripped = re.sub(r"^#\s+", "#", stripped)
clean_lines.append(stripped)
except Exception as e:
print(f"Error during indentation removal: {e}")
exit(1)
return clean_lines
# This is required - to avoid include errors when Kconfig is used and
# LVGL is installed on the system - i.e when lvgl.h is used as a system include
def add_include_guards(lines):
lines.insert(0, "#define LV_CONF_H\n\n")
lines.insert(0, "#ifndef LV_CONF_H\n")
lines.append("#endif /* END LV_CONF_H */\n")
return lines
def init_venv(venv_path):
"""
Creates a virtual env named .venv in the `workfolder` directory
It is usually set to the path of the build directory.
If the .venv already exists it enters the venv
Returns the path to the venv
"""
try:
if os.path.exists(venv_path) == False:
# Create venv
subprocess.check_call([sys.executable, "-m", "venv", venv_path])
# Enter venv
venv_path = os.path.join(venv_path, ".venv")
subprocess.check_call([sys.executable, "-m", "venv", venv_path])
except subprocess.CalledProcessError as e:
print(f"Error during the setup of python venv: {e}")
exit(1)
return venv_path
def install_pcpp_in_venv(venv_path):
"""
Install pcpp a python implementation of the C pre-processor
On success - Returns the path to pcpp, None on failure
"""
if sys.platform == "win32":
venv_pip = os.path.join(venv_path, "Scripts", "pip.exe")
venv_pcpp = os.path.join(venv_path, "Scripts", "pcpp.exe")
else:
venv_pip = os.path.join(venv_path, "bin", "pip")
venv_pcpp = os.path.join(venv_path, "bin", "pcpp")
if os.path.exists(venv_pcpp) == False:
# Install pcpp
try:
subprocess.check_call([venv_pip, "install", "pcpp"])
except subprocess.CalledProcessError as e:
print(f"Failed to install PCPP: {e}")
return None
else:
print("PCPP is already installed in venv")
return venv_pcpp
def main():
args = get_args()
# Check if PCPP is already present on the system
# if it's not - create a python venv inside the workfolder directory
# and install it there
res = subprocess.run(["which", "pcpp"], capture_output=True)
if res.returncode == 0:
pcpp_exe = res.stdout.decode().replace("\n", "")
print(f"Found PCPP: {pcpp_exe}")
else:
print("Failed to locate pcpp - installing it")
venv_path = init_venv(args.workfolder)
pcpp_exe = install_pcpp_in_venv(venv_path)
if pcpp_exe is None:
exit(1)
preprocess_file(pcpp_exe, args.input, args.tmp_file, args.output, args.include, args.defs)
lines = read_lines(args.tmp_file)
lines = remove_indentation(lines)
lines = add_include_guards(lines)
# Write the resulting output header file with include guards and no indentation
try:
with open(args.output, "w") as f:
f.writelines(lines)
except Exception as e:
print(f"Writing resulting file failed: {e}")
exit(1)
print(f"Expanded configuration header saved to {args.output}")
os.remove(args.tmp_file)
print(f"Temporary preprocessed file {args.tmp_file} removed.")
if __name__ == "__main__":
main()