Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
__init__.py
00001 """ 00002 mbed SDK 00003 Copyright (c) 2011-2017 ARM Limited 00004 Portions Copyright (c) 2017-2018 Analog Devices, Inc. 00005 00006 Licensed under the Apache License, Version 2.0 (the "License"); 00007 you may not use this file except in compliance with the License. 00008 You may obtain a copy of the License at 00009 00010 http://www.apache.org/licenses/LICENSE-2.0 00011 00012 Unless required by applicable law or agreed to in writing, software 00013 distributed under the License is distributed on an "AS IS" BASIS, 00014 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 See the License for the specific language governing permissions and 00016 limitations under the License. 00017 """ 00018 00019 import copy 00020 import os 00021 import sys 00022 import shutil 00023 import tempfile 00024 00025 from subprocess import Popen, PIPE 00026 00027 from tools.targets import TARGET_MAP 00028 from tools.export.exporters import Exporter 00029 00030 from collections import namedtuple 00031 00032 00033 # Container for CCES option type and value 00034 Option = namedtuple('Option', ['type', 'value']) 00035 00036 """ 00037 Tuple of supported device names 00038 """ 00039 SUPPORTED_DEVICES = ("ADuCM3027", "ADuCM3029", "ADuCM360", "ADuCM4050") 00040 00041 class CCES (Exporter): 00042 """ 00043 mbed exporter for Analog Devices' CrossCore Embedded Studio(TM) 00044 """ 00045 NAME = 'CrossCore Embedded Studio' 00046 TOOLCHAIN = 'GCC_ARM' 00047 00048 @classmethod 00049 def is_target_supported (cls, target_name): 00050 """Query support for a particular target 00051 00052 Positional Arguments: 00053 target_name - the name of the target. 00054 """ 00055 target = TARGET_MAP[target_name] 00056 return (cls.TOOLCHAIN in target.supported_toolchains) \ 00057 and hasattr(target, "device_name") \ 00058 and (target.device_name in SUPPORTED_DEVICES) 00059 00060 @property 00061 def flags (self): 00062 """Returns a dictionary of toolchain flags. 00063 Keys of the dictionary are: 00064 cxx_flags - c++ flags 00065 c_flags - c flags 00066 ld_flags - linker flags 00067 asm_flags - assembler flags 00068 common_flags - common options 00069 00070 Skip macros because headless tools handles them separately 00071 """ 00072 flags = {key + "_flags": copy.deepcopy(value) for key, value \ 00073 in self.toolchain.flags.iteritems()} 00074 config_header = self.config_header_ref 00075 if config_header: 00076 config_header = "\\\"" + self.format_inc_path (config_header.name) \ 00077 + "\\\"" 00078 header_options = self.toolchain.get_config_option(config_header) 00079 flags['c_flags'] += header_options 00080 flags['cxx_flags'] += header_options 00081 return flags 00082 00083 @staticmethod 00084 def format_path (path, prefix): 00085 """ 00086 Formats the given source path relative to the project directory 00087 using the prefix 00088 """ 00089 new_path = path 00090 if new_path.startswith("./"): 00091 new_path = new_path[2:] 00092 return prefix + new_path.replace("\\", "\\\\") 00093 00094 @staticmethod 00095 def format_inc_path (path): 00096 """ 00097 Formats the given include path relative to the project directory 00098 """ 00099 return CCES.format_path(path, "${ProjDirPath}/../") 00100 00101 @staticmethod 00102 def format_src_path (path): 00103 """ 00104 Formats the given source path relative to the project directory 00105 """ 00106 return CCES.format_path(path, "PARENT-1-PROJECT_LOC/") 00107 00108 @staticmethod 00109 def clean_flags (container, flags_to_remove): 00110 """ 00111 Some flags are handled by CCES already, so there's no need 00112 to include them twice. 00113 """ 00114 for flag in flags_to_remove: 00115 if flag in container: 00116 container.remove(flag) 00117 00118 @staticmethod 00119 def parse_flags (flags, options, booleans): 00120 """ 00121 Parse the values in `booleans`, insert them into the 00122 `options` dictionary and remove them from `flags` 00123 """ 00124 for flag, flag_id in booleans.items(): 00125 value = "false" 00126 if flag in flags: 00127 value = "true" 00128 flags.remove(flag) 00129 options[flag_id] = Option("baseId", value) 00130 00131 @staticmethod 00132 def convert_common_options (prefix, options, flags): 00133 """ 00134 Converts the common flags into CCES options and removes them 00135 from the flags list 00136 """ 00137 # remove these flags without converting to option 00138 # since they are added by CCES 00139 remove = ["-c"] 00140 CCES.clean_flags(flags, remove) 00141 00142 value = prefix + "option.dwarfversion.enumerated.v2" 00143 for flag in flags: 00144 if flag.startswith("-gdwarf"): 00145 value = prefix + "option.dwarfversion.enumerated.v" + flag[-1] 00146 flags.remove(flag) 00147 break 00148 option = Option("baseId", value) 00149 options[prefix + "option.dwarfversion"] = option 00150 00151 @staticmethod 00152 def convert_assembler_options (flags): 00153 """ 00154 Converts the assembler flags into CCES options and removes them 00155 from the flags list 00156 """ 00157 options = {} 00158 00159 # remove these flags without converting to option 00160 # since they are added by CCES 00161 remove = ["-x", "assembler-with-cpp"] 00162 CCES.clean_flags(flags, remove) 00163 00164 booleans = {"-v": "arm.assembler.option.verbose", 00165 "-g": "arm.assembler.option.debuginfo"} 00166 00167 CCES.parse_flags(flags, options, booleans) 00168 00169 CCES.convert_common_options("arm.assembler.", options, flags) 00170 00171 return options 00172 00173 @staticmethod 00174 def convert_compiler_options (flags): 00175 """ 00176 Converts the compiler flags into CCES options and removes them 00177 from the flags list 00178 """ 00179 options = {} 00180 00181 enable_optimization = "true" 00182 value = "arm.base.compiler.option.optimization.og" 00183 for flag in flags: 00184 if flag.startswith("-O"): 00185 value = "arm.base.compiler.option.optimization.o" + flag[2:] 00186 if flag[2:] == "0": 00187 enable_optimization = "false" 00188 flags.remove(flag) 00189 break 00190 option = Option("baseId", value) 00191 options["arm.base.compiler.option.optimization"] = option 00192 00193 option = Option("baseId", enable_optimization) 00194 options["arm.base.compiler.option.optimization.enable"] = option 00195 00196 booleans = {"-g": "arm.base.compiler.option.debug", 00197 "-save-temps": \ 00198 "arm.base.compiler.option.savetemps", 00199 "-ffunction-sections": \ 00200 "arm.c.compiler.option.elimination.code", 00201 "-fdata-sections": \ 00202 "arm.c.compiler.option.elimination.data", 00203 "-pedantic": "arm.base.compiler.option.pedantic", 00204 "-pedantic-errors": \ 00205 "arm.base.compiler.option.pedanticerrors", 00206 "-w": "arm.base.compiler.option.inhibitallwarnings", 00207 "-Wall": "arm.base.compiler.option.allwarnings", 00208 "-Wextra": "arm.base.compiler.option.extrawarnings", 00209 "-Werror": "arm.base.compiler.option.warningaserror", 00210 "-Wconversion": \ 00211 "arm.base.compiler.option.conversionwarning"} 00212 00213 CCES.parse_flags(flags, options, booleans) 00214 00215 CCES.convert_common_options("arm.base.compiler.", options, flags) 00216 00217 return options 00218 00219 @staticmethod 00220 def convert_linker_options (flags): 00221 """ 00222 Converts the linker flags into CCES options and removes them 00223 from the flags list 00224 """ 00225 options = {} 00226 00227 booleans = {"-nostartfiles": "arm.linker.option.nostart", 00228 "-nodefaultlibs": "arm.linker.option.nodeflibs", 00229 "-nostdlib": "arm.linker.option.nostdlibs", 00230 "-s": "arm.linker.option.strip", 00231 "-Wl,--gc-sections": "arm.linker.option.elimination"} 00232 00233 CCES.parse_flags(flags, options, booleans) 00234 00235 return options 00236 00237 @staticmethod 00238 def get_cces_path (root): 00239 """ 00240 Returns the path to the CCES executable 00241 """ 00242 cces_path = None 00243 00244 if sys.platform == 'win32' or sys.platform == 'cygwin': 00245 cces_path = os.path.join(root, "Eclipse", "ccesc.exe") 00246 elif sys.platform.startswith('linux'): 00247 cces_path = os.path.join(root, "Eclipse", "cces") 00248 elif sys.platform == 'darwin': 00249 cces_path = os.path.join(root, "MacOS", "cces") 00250 else: 00251 print("Unsupported operating system '%s'" % sys.platform) 00252 return None 00253 00254 return cces_path 00255 00256 @staticmethod 00257 def get_project_create_command (cces_path, workspace, project_name): 00258 """ 00259 Generate the headless tools projectcreate command string 00260 with the given parameters 00261 """ 00262 cmd = [ 00263 "\"%s\"" % cces_path, 00264 "-nosplash", 00265 "-consoleLog", 00266 "-application com.analog.crosscore.headlesstools", 00267 "-data", workspace, 00268 "-project", project_name, 00269 "-command projectcreate", 00270 "-input-file", "cces.json" 00271 ] 00272 return ' '.join(cmd) 00273 00274 @staticmethod 00275 def get_project_build_command (cces_path, workspace, project_name): 00276 """ 00277 Generate the headless tools build command string 00278 with the given parameters 00279 """ 00280 cmd = [ 00281 "\"%s\"" % cces_path, 00282 "-nosplash", 00283 "-consoleLog", 00284 "-application com.analog.crosscore.headlesstools", 00285 "-data", workspace, 00286 "-project", project_name, 00287 "-cleanBuild all" 00288 ] 00289 return ' '.join(cmd) 00290 00291 # override 00292 def generate (self): 00293 """ 00294 Generate the CCES project files using headless builder. 00295 """ 00296 00297 self.resources.win_to_unix() 00298 00299 asm_defines = self.toolchain.get_symbols(True) 00300 c_defines = self.toolchain.get_symbols() 00301 00302 include_dirs = [self.format_inc_path (d) for d \ 00303 in self.resources.inc_dirs if d] 00304 00305 srcs = self.resources.s_sources + \ 00306 self.resources.c_sources + \ 00307 self.resources.cpp_sources + \ 00308 self.resources.headers 00309 00310 srcs_dict = {} 00311 for src in srcs: 00312 srcs_dict[src] = self.format_src_path (src) 00313 00314 ld_script = self.format_inc_path (self.resources.linker_script) 00315 00316 asm_flags = self.flags ['asm_flags'] 00317 c_flags = self.flags ['c_flags'] + self.flags ['common_flags'] 00318 cxx_flags = self.flags ['cxx_flags'] + self.flags ['common_flags'] 00319 00320 libs = [] 00321 for libpath in self.libraries: 00322 lib = os.path.splitext(os.path.basename(libpath))[0] 00323 libs.append(lib[3:]) # skip 'lib' prefix 00324 00325 ld_flags = self.flags ['ld_flags'] + ["-l" + lib for lib \ 00326 in self.toolchain.sys_libs] 00327 00328 proc = self.toolchain.target.device_name 00329 cpu = self.toolchain.target.core.lower() 00330 fpu = None 00331 float_abi = None 00332 00333 # parse toolchain CPU flags 00334 for flag in self.toolchain.cpu: 00335 if flag.startswith("-mcpu="): 00336 cpu = flag[len("-mcpu="):] 00337 elif flag.startswith("-mfpu="): 00338 fpu = flag[len("-mfpu="):] 00339 elif flag.startswith("-mfloat-abi="): 00340 float_abi = flag[len("-mfloat-abi="):] 00341 00342 # remove toolchain CPU flags. We'll handle them separately 00343 # in the generated .json file 00344 self.clean_flags (c_flags, self.toolchain.cpu) 00345 self.clean_flags (cxx_flags, self.toolchain.cpu) 00346 self.clean_flags (ld_flags, self.toolchain.cpu) 00347 00348 ld_opts = self.convert_linker_options (ld_flags) 00349 asm_opts = self.convert_assembler_options (asm_flags) 00350 c_opts = self.convert_compiler_options (c_flags) 00351 cxx_opts = self.convert_compiler_options (cxx_flags) 00352 00353 project = "cces" 00354 json = "cces.json" 00355 local_location = project 00356 00357 jinja_ctx = { 00358 'project' : self.project_name, 00359 'cpu' : cpu, 00360 'proc' : proc, 00361 'family' : "ARM", 00362 'asm_defines' : asm_defines, 00363 'c_defines' : c_defines, 00364 'fpu' : fpu, 00365 'float_abi' : float_abi, 00366 'ld_script' : ld_script, 00367 'local_location' : local_location, 00368 'srcs': srcs_dict, 00369 'include_dirs' : include_dirs, 00370 'ld_opts' : ld_opts, 00371 'ld_flags' : ld_flags, 00372 'asm_opts' : asm_opts, 00373 'asm_flags' : asm_flags, 00374 'c_opts' : c_opts, 00375 'c_flags' : c_flags, 00376 'cxx_opts' : cxx_opts, 00377 'cxx_flags' : cxx_flags, 00378 } 00379 00380 self.gen_file('cces/cces.json.tmpl', jinja_ctx, 00381 json, trim_blocks=True, lstrip_blocks=True) 00382 00383 # generate a readme on how to create the CCES project 00384 # using the generated .json file 00385 00386 cces_paths = { 00387 "Windows" : "%CCES_HOME%\\Eclipse\\ccesc.exe", 00388 "Linux" : "${CCES_HOME}/Eclipse/cces", 00389 "MacOS" : "${CCES_HOME}/MacOS/cces" 00390 } 00391 00392 commands = {"create":{}, "build":{}} 00393 for operating_system, path in cces_paths.items(): 00394 commands["create"][operating_system] = \ 00395 CCES.get_project_create_command(path, \ 00396 "WORKSPACE", project) 00397 commands["build"][operating_system] = \ 00398 CCES.get_project_build_command(path, \ 00399 "WORKSPACE", project) 00400 00401 jinja_ctx = { 00402 'commands' : commands 00403 } 00404 00405 self.gen_file('cces/README.md.tmpl', jinja_ctx, "README.md") 00406 00407 print("CCES files generated.") 00408 00409 00410 @staticmethod 00411 def clean(_): 00412 os.remove('cces.json') 00413 os.remove('README.md') 00414 00415 @staticmethod 00416 def build (project_name, log_name='build_log.txt', cleanup=True): 00417 """ 00418 Build the generated CCES project using headless builder. 00419 """ 00420 # create the project by importing .json file using CCES headless builder 00421 cces_home = os.getenv("CCES_HOME") 00422 if cces_home is None: 00423 print("Failed to build project: " + \ 00424 "'CCES_HOME' environment variable not defined.") 00425 return -1 00426 00427 cces_path = CCES.get_cces_path(cces_home) 00428 if cces_path is None: 00429 return -1 00430 00431 workspace = tempfile.mkdtemp() 00432 00433 cmd = CCES.get_project_create_command(cces_path, workspace, \ 00434 project_name) 00435 print(cmd) 00436 process = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) 00437 out, err = process.communicate() 00438 ret_code = process.returncode 00439 00440 # cleanup workspace 00441 if os.path.exists(workspace): 00442 shutil.rmtree(workspace, True) 00443 CCES.clean(project_name) 00444 00445 # check return code for failure 00446 if ret_code != 0: 00447 for line in out.split("\n"): 00448 print(line) 00449 for line in err.split("\n"): 00450 print(line) 00451 00452 print("Failed to create project. Return code: %d" % ret_code) 00453 return -1 00454 00455 # build the project 00456 workspace = tempfile.mkdtemp() 00457 00458 cmd = CCES.get_project_build_command(cces_path, workspace, project_name) 00459 print(cmd) 00460 process = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) 00461 out, err = process.communicate() 00462 ret_code = process.returncode 00463 00464 if log_name: 00465 with open(log_name, 'w+') as log_file: 00466 log_file.write(out) 00467 log_file.write(err) 00468 if ret_code != 0: 00469 log_file.write("Failed to build project. Return code: %d"\ 00470 % ret_code) 00471 00472 # cleanup workspace 00473 if os.path.exists(workspace): 00474 shutil.rmtree(workspace) 00475 00476 # check return code for failure 00477 if ret_code == 0: 00478 return 0 00479 00480 for line in out.split("\n"): 00481 print(line) 00482 for line in err.split("\n"): 00483 print(line) 00484 00485 print("Failed to build project. Return code: %d" % ret_code) 00486 return -1
Generated on Tue Jul 12 2022 17:12:47 by
