123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- import os
- import hashlib
- import pathlib
- from platformio import fs
- Import("env")
- try:
- import protobuf
- except ImportError:
- env.Execute(
- env.VerboseAction(
- # We need to speicify protobuf version. In other case got next (on Ubuntu 20.04):
- # Requirement already satisfied: protobuf in /usr/lib/python3/dist-packages (3.6.1)
- '$PYTHONEXE -m pip install "protobuf>=3.19.1"',
- "Installing Protocol Buffers dependencies",
- )
- )
- try:
- import grpc_tools.protoc
- except ImportError:
- env.Execute(
- env.VerboseAction(
- '$PYTHONEXE -m pip install "grpcio-tools>=1.43.0"',
- "Installing GRPC dependencies",
- )
- )
- nanopb_root = os.path.join(os.getcwd(), '..')
- project_dir = env.subst("$PROJECT_DIR")
- build_dir = env.subst("$BUILD_DIR")
- generated_src_dir = os.path.join(build_dir, 'nanopb', 'generated-src')
- generated_build_dir = os.path.join(build_dir, 'nanopb', 'generated-build')
- md5_dir = os.path.join(build_dir, 'nanopb', 'md5')
- nanopb_protos = env.GetProjectOption("custom_nanopb_protos", "")
- nanopb_plugin_options = env.GetProjectOption("custom_nanopb_options", "")
- if not nanopb_protos:
- print("[nanopb] No generation needed.")
- else:
- if isinstance(nanopb_plugin_options, (list, tuple)):
- nanopb_plugin_options = " ".join(nanopb_plugin_options)
- nanopb_plugin_options = nanopb_plugin_options.split()
- protos_files = fs.match_src_files(project_dir, nanopb_protos)
- if not len(protos_files):
- print("[nanopb] ERROR: No files matched pattern:")
- print(f"custom_nanopb_protos: {nanopb_protos}")
- exit(1)
- protoc_generator = os.path.join(nanopb_root, 'generator', 'protoc')
- nanopb_options = ""
- nanopb_options += f" --nanopb_out={generated_src_dir}"
- for opt in nanopb_plugin_options:
- nanopb_options += (" --nanopb_opt=" + opt)
- try:
- os.makedirs(generated_src_dir)
- except FileExistsError:
- pass
- try:
- os.makedirs(md5_dir)
- except FileExistsError:
- pass
- # Collect include dirs based on
- proto_include_dirs = set()
- for proto_file in protos_files:
- proto_file_abs = os.path.join(project_dir, proto_file)
- proto_dir = os.path.dirname(proto_file_abs)
- proto_include_dirs.add(proto_dir)
- for proto_include_dir in proto_include_dirs:
- nanopb_options += (" --proto_path=" + proto_include_dir)
- nanopb_options += (" --nanopb_opt=-I" + proto_include_dir)
- for proto_file in protos_files:
- proto_file_abs = os.path.join(project_dir, proto_file)
- proto_file_path_abs = os.path.dirname(proto_file_abs)
- proto_file_basename = os.path.basename(proto_file_abs)
- proto_file_without_ext = os.path.splitext(proto_file_basename)[0]
- proto_file_md5_abs = os.path.join(md5_dir, proto_file_basename + '.md5')
- proto_file_current_md5 = hashlib.md5(pathlib.Path(proto_file_abs).read_bytes()).hexdigest()
- options_file = proto_file_without_ext + ".options"
- options_file_abs = os.path.join(proto_file_path_abs, options_file)
- options_file_md5_abs = None
- options_file_current_md5 = None
- if pathlib.Path(options_file_abs).exists():
- options_file_md5_abs = os.path.join(md5_dir, options_file + '.md5')
- options_file_current_md5 = hashlib.md5(pathlib.Path(options_file_abs).read_bytes()).hexdigest()
- else:
- options_file = None
- header_file = proto_file_without_ext + ".pb.h"
- source_file = proto_file_without_ext + ".pb.c"
- header_file_abs = os.path.join(generated_src_dir, source_file)
- source_file_abs = os.path.join(generated_src_dir, header_file)
- need_generate = False
- # Check proto file md5
- try:
- last_md5 = pathlib.Path(proto_file_md5_abs).read_text()
- if last_md5 != proto_file_current_md5:
- need_generate = True
- except FileNotFoundError:
- need_generate = True
- if options_file:
- # Check options file md5
- try:
- last_md5 = pathlib.Path(options_file_md5_abs).read_text()
- if last_md5 != options_file_current_md5:
- need_generate = True
- except FileNotFoundError:
- need_generate = True
- options_info = f"{options_file}" if options_file else "no options"
- if not need_generate:
- print(f"[nanopb] Skipping '{proto_file}' ({options_info})")
- else:
- print(f"[nanopb] Processing '{proto_file}' ({options_info})")
- cmd = protoc_generator + " " + nanopb_options + " " + proto_file_basename
- result = env.Execute(cmd)
- if result != 0:
- print(f"[nanopb] ERROR: ({result}) processing cmd: '{cmd}'")
- exit(1)
- pathlib.Path(proto_file_md5_abs).write_text(proto_file_current_md5)
- if options_file:
- pathlib.Path(options_file_md5_abs).write_text(options_file_current_md5)
- #
- # Add generated includes and sources to build environment
- #
- env.Append(CPPPATH=[generated_src_dir])
- env.BuildSources(generated_build_dir, generated_src_dir)
|