1import logging 2import os 3import shutil 4import subprocess 5import sys 6 7from .common import BuildError, BuildItem, BuildSystem 8 9try: 10 from typing import Any, Optional 11except ImportError: 12 pass 13 14BUILD_SYSTEM_CMAKE = 'cmake' 15IDF_PY = os.path.join(os.environ['IDF_PATH'], 'tools', 'idf.py') 16 17# While ESP-IDF component CMakeLists files can be identified by the presence of 'idf_component_register' string, 18# there is no equivalent for the project CMakeLists files. This seems to be the best option... 19CMAKE_PROJECT_LINE = r'include($ENV{IDF_PATH}/tools/cmake/project.cmake)' 20 21 22class CMakeBuildSystem(BuildSystem): 23 NAME = BUILD_SYSTEM_CMAKE 24 25 @classmethod 26 def build(cls, build_item): # type: (BuildItem) -> None 27 build_path, work_path, extra_cmakecache_items = cls.build_prepare(build_item) 28 # Prepare the build arguments 29 args = [ 30 sys.executable, 31 IDF_PY, 32 '-B', 33 build_path, 34 '-C', 35 work_path, 36 '-DIDF_TARGET=' + build_item.target, 37 ] 38 if extra_cmakecache_items: 39 for key, val in extra_cmakecache_items.items(): 40 args.append('-D{}={}'.format(key, val)) 41 if 'TEST_EXCLUDE_COMPONENTS' in extra_cmakecache_items \ 42 and 'TEST_COMPONENTS' not in extra_cmakecache_items: 43 args.append('-DTESTS_ALL=1') 44 if build_item.verbose: 45 args.append('-v') 46 if 'CONFIG_APP_BUILD_BOOTLOADER' in extra_cmakecache_items: 47 # In case if secure_boot is enabled then for bootloader build need to add `bootloader` cmd 48 args.append('bootloader') 49 args.append('build') 50 cmdline = format(' '.join(args)) 51 logging.info('Running {}'.format(cmdline)) 52 53 if build_item.dry_run: 54 return 55 56 log_file = None 57 build_stdout = sys.stdout 58 build_stderr = sys.stderr 59 if build_item.build_log_path: 60 logging.info('Writing build log to {}'.format(build_item.build_log_path)) 61 log_file = open(build_item.build_log_path, 'w') 62 build_stdout = log_file 63 build_stderr = log_file 64 65 try: 66 subprocess.check_call(args, stdout=build_stdout, stderr=build_stderr) 67 except subprocess.CalledProcessError as e: 68 raise BuildError('Build failed with exit code {}'.format(e.returncode)) 69 else: 70 # Also save the sdkconfig file in the build directory 71 shutil.copyfile( 72 os.path.join(work_path, 'sdkconfig'), 73 os.path.join(build_path, 'sdkconfig'), 74 ) 75 build_item.size_json_fp = build_item.get_size_json_fp() 76 finally: 77 if log_file: 78 log_file.close() 79 80 @staticmethod 81 def _read_cmakelists(app_path): # type: (str) -> Optional[str] 82 cmakelists_path = os.path.join(app_path, 'CMakeLists.txt') 83 if not os.path.exists(cmakelists_path): 84 return None 85 with open(cmakelists_path, 'r') as cmakelists_file: 86 return cmakelists_file.read() 87 88 @staticmethod 89 def is_app(path): # type: (str) -> bool 90 cmakelists_file_content = CMakeBuildSystem._read_cmakelists(path) 91 if not cmakelists_file_content: 92 return False 93 if CMAKE_PROJECT_LINE not in cmakelists_file_content: 94 return False 95 return True 96 97 @classmethod 98 def supported_targets(cls, app_path): # type: (str) -> Any 99 return cls._supported_targets(app_path) 100