BA
/
BaBoRo1
Embed:
(wiki syntax)
Show/hide line numbers
__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 config_header = self.toolchain.get_config_header() 00073 flags = {key + "_flags": copy.deepcopy(value) for key, value \ 00074 in self.toolchain.flags.iteritems()} 00075 if config_header: 00076 config_header = os.path.relpath(config_header, \ 00077 self.resources.file_basepath[config_header]) 00078 config_header = "\\\"" + self.format_inc_path (config_header) \ 00079 + "\\\"" 00080 header_options = self.toolchain.get_config_option(config_header) 00081 flags['c_flags'] += header_options 00082 flags['cxx_flags'] += header_options 00083 return flags 00084 00085 @staticmethod 00086 def format_path (path, prefix): 00087 """ 00088 Formats the given source path relative to the project directory 00089 using the prefix 00090 """ 00091 new_path = path 00092 if new_path.startswith("./"): 00093 new_path = new_path[2:] 00094 return prefix + new_path.replace("\\", "\\\\") 00095 00096 @staticmethod 00097 def format_inc_path (path): 00098 """ 00099 Formats the given include path relative to the project directory 00100 """ 00101 return CCES.format_path(path, "${ProjDirPath}/../") 00102 00103 @staticmethod 00104 def format_src_path (path): 00105 """ 00106 Formats the given source path relative to the project directory 00107 """ 00108 return CCES.format_path(path, "PARENT-1-PROJECT_LOC/") 00109 00110 @staticmethod 00111 def clean_flags (container, flags): 00112 """ 00113 Some flags are handled by CCES already, so there's no need 00114 to include them twice. 00115 """ 00116 for flag in container: 00117 if flag in flags: 00118 flags.remove(flag) 00119 00120 @staticmethod 00121 def parse_flags (flags, options, booleans): 00122 """ 00123 Parse the values in `booleans`, insert them into the 00124 `options` dictionary and remove them from `flags` 00125 """ 00126 for flag, flag_id in booleans.items(): 00127 value = "false" 00128 if flag in flags: 00129 value = "true" 00130 flags.remove(flag) 00131 options[flag_id] = Option("baseId", value) 00132 00133 @staticmethod 00134 def convert_common_options (prefix, options, flags): 00135 """ 00136 Converts the common flags into CCES options and removes them 00137 from the flags list 00138 """ 00139 # remove these flags without converting to option 00140 # since they are added by CCES 00141 remove = ["-c"] 00142 CCES.clean_flags(flags, remove) 00143 00144 value = prefix + "option.dwarfversion.enumerated.v2" 00145 for flag in flags: 00146 if flag.startswith("-gdwarf"): 00147 value = prefix + "option.dwarfversion.enumerated.v" + flag[-1] 00148 flags.remove(flag) 00149 break 00150 option = Option("baseId", value) 00151 options[prefix + "option.dwarfversion"] = option 00152 00153 @staticmethod 00154 def convert_assembler_options (flags): 00155 """ 00156 Converts the assembler flags into CCES options and removes them 00157 from the flags list 00158 """ 00159 options = {} 00160 00161 # remove these flags without converting to option 00162 # since they are added by CCES 00163 remove = ["-x", "assembler-with-cpp"] 00164 CCES.clean_flags(flags, remove) 00165 00166 booleans = {"-v": "arm.assembler.option.verbose", 00167 "-g": "arm.assembler.option.debuginfo"} 00168 00169 CCES.parse_flags(flags, options, booleans) 00170 00171 CCES.convert_common_options("arm.assembler.", options, flags) 00172 00173 return options 00174 00175 @staticmethod 00176 def convert_compiler_options (flags): 00177 """ 00178 Converts the compiler flags into CCES options and removes them 00179 from the flags list 00180 """ 00181 options = {} 00182 00183 enable_optimization = "true" 00184 value = "arm.base.compiler.option.optimization.og" 00185 for flag in flags: 00186 if flag.startswith("-O"): 00187 value = "arm.base.compiler.option.optimization.o" + flag[2:] 00188 if flag[2:] == "0": 00189 enable_optimization = "false" 00190 flags.remove(flag) 00191 break 00192 option = Option("baseId", value) 00193 options["arm.base.compiler.option.optimization"] = option 00194 00195 option = Option("baseId", enable_optimization) 00196 options["arm.base.compiler.option.optimization.enable"] = option 00197 00198 booleans = {"-g": "arm.base.compiler.option.debug", 00199 "-save-temps": \ 00200 "arm.base.compiler.option.savetemps", 00201 "-ffunction-sections": \ 00202 "arm.c.compiler.option.elimination.code", 00203 "-fdata-sections": \ 00204 "arm.c.compiler.option.elimination.data", 00205 "-pedantic": "arm.base.compiler.option.pedantic", 00206 "-pedantic-errors": \ 00207 "arm.base.compiler.option.pedanticerrors", 00208 "-w": "arm.base.compiler.option.inhibitallwarnings", 00209 "-Wall": "arm.base.compiler.option.allwarnings", 00210 "-Wextra": "arm.base.compiler.option.extrawarnings", 00211 "-Werror": "arm.base.compiler.option.warningaserror", 00212 "-Wconversion": \ 00213 "arm.base.compiler.option.conversionwarning"} 00214 00215 CCES.parse_flags(flags, options, booleans) 00216 00217 CCES.convert_common_options("arm.base.compiler.", options, flags) 00218 00219 return options 00220 00221 @staticmethod 00222 def convert_linker_options (flags): 00223 """ 00224 Converts the linker flags into CCES options and removes them 00225 from the flags list 00226 """ 00227 options = {} 00228 00229 booleans = {"-nostartfiles": "arm.linker.option.nostart", 00230 "-nodefaultlibs": "arm.linker.option.nodeflibs", 00231 "-nostdlib": "arm.linker.option.nostdlibs", 00232 "-s": "arm.linker.option.strip", 00233 "-Wl,--gc-sections": "arm.linker.option.elimination"} 00234 00235 CCES.parse_flags(flags, options, booleans) 00236 00237 return options 00238 00239 @staticmethod 00240 def get_cces_path (root): 00241 """ 00242 Returns the path to the CCES executable 00243 """ 00244 cces_path = None 00245 00246 if sys.platform == 'win32' or sys.platform == 'cygwin': 00247 cces_path = os.path.join(root, "Eclipse", "ccesc.exe") 00248 elif sys.platform.startswith('linux'): 00249 cces_path = os.path.join(root, "Eclipse", "cces") 00250 elif sys.platform == 'darwin': 00251 cces_path = os.path.join(root, "MacOS", "cces") 00252 else: 00253 print("Unsupported operating system '%s'" % sys.platform) 00254 return None 00255 00256 return cces_path 00257 00258 @staticmethod 00259 def get_project_create_command (cces_path, workspace, project_name): 00260 """ 00261 Generate the headless tools projectcreate command string 00262 with the given parameters 00263 """ 00264 cmd = [ 00265 "\"%s\"" % cces_path, 00266 "-nosplash", 00267 "-consoleLog", 00268 "-application com.analog.crosscore.headlesstools", 00269 "-data", workspace, 00270 "-project", project_name, 00271 "-command projectcreate", 00272 "-input-file", "cces.json" 00273 ] 00274 return ' '.join(cmd) 00275 00276 @staticmethod 00277 def get_project_build_command (cces_path, workspace, project_name): 00278 """ 00279 Generate the headless tools build command string 00280 with the given parameters 00281 """ 00282 cmd = [ 00283 "\"%s\"" % cces_path, 00284 "-nosplash", 00285 "-consoleLog", 00286 "-application com.analog.crosscore.headlesstools", 00287 "-data", workspace, 00288 "-project", project_name, 00289 "-cleanBuild all" 00290 ] 00291 return ' '.join(cmd) 00292 00293 # override 00294 def generate (self): 00295 """ 00296 Generate the CCES project files using headless builder. 00297 """ 00298 00299 self.resources.win_to_unix() 00300 00301 asm_defines = self.toolchain.get_symbols(True) 00302 c_defines = self.toolchain.get_symbols() 00303 00304 include_dirs = [self.format_inc_path (d) for d \ 00305 in self.resources.inc_dirs if d] 00306 00307 srcs = self.resources.s_sources + \ 00308 self.resources.c_sources + \ 00309 self.resources.cpp_sources + \ 00310 self.resources.headers 00311 00312 srcs_dict = {} 00313 for src in srcs: 00314 srcs_dict[src] = self.format_src_path (src) 00315 00316 ld_script = self.format_inc_path (self.resources.linker_script) 00317 00318 asm_flags = self.flags ['asm_flags'] 00319 c_flags = self.flags ['c_flags'] + self.flags ['common_flags'] 00320 cxx_flags = self.flags ['cxx_flags'] + self.flags ['common_flags'] 00321 00322 libs = [] 00323 for libpath in self.resources.libraries: 00324 lib = os.path.splitext(os.path.basename(libpath))[0] 00325 libs.append(lib[3:]) # skip 'lib' prefix 00326 00327 ld_flags = self.flags ['ld_flags'] + ["-l" + lib for lib \ 00328 in self.toolchain.sys_libs] 00329 00330 proc = self.toolchain.target.device_name 00331 cpu = self.toolchain.target.core.lower() 00332 fpu = None 00333 float_abi = None 00334 00335 # parse toolchain CPU flags 00336 for flag in self.toolchain.cpu: 00337 if flag.startswith("-mcpu="): 00338 cpu = flag[len("-mcpu="):] 00339 elif flag.startswith("-mfpu="): 00340 fpu = flag[len("-mfpu="):] 00341 elif flag.startswith("-mfloat-abi="): 00342 float_abi = flag[len("-mfloat-abi="):] 00343 00344 # remove toolchain CPU flags. We'll handle them separately 00345 # in the generated .json file 00346 self.clean_flags (c_flags, self.toolchain.cpu) 00347 self.clean_flags (cxx_flags, self.toolchain.cpu) 00348 self.clean_flags (ld_flags, self.toolchain.cpu) 00349 00350 ld_opts = self.convert_linker_options (ld_flags) 00351 asm_opts = self.convert_assembler_options (asm_flags) 00352 c_opts = self.convert_compiler_options (c_flags) 00353 cxx_opts = self.convert_compiler_options (cxx_flags) 00354 00355 project = "cces" 00356 json = "cces.json" 00357 local_location = project 00358 00359 jinja_ctx = { 00360 'project' : self.project_name, 00361 'cpu' : cpu, 00362 'proc' : proc, 00363 'family' : "ARM", 00364 'asm_defines' : asm_defines, 00365 'c_defines' : c_defines, 00366 'fpu' : fpu, 00367 'float_abi' : float_abi, 00368 'ld_script' : ld_script, 00369 'local_location' : local_location, 00370 'srcs': srcs_dict, 00371 'include_dirs' : include_dirs, 00372 'ld_opts' : ld_opts, 00373 'ld_flags' : ld_flags, 00374 'asm_opts' : asm_opts, 00375 'asm_flags' : asm_flags, 00376 'c_opts' : c_opts, 00377 'c_flags' : c_flags, 00378 'cxx_opts' : cxx_opts, 00379 'cxx_flags' : cxx_flags, 00380 } 00381 00382 self.gen_file('cces/cces.json.tmpl', jinja_ctx, 00383 json, trim_blocks=True, lstrip_blocks=True) 00384 00385 # generate a readme on how to create the CCES project 00386 # using the generated .json file 00387 00388 cces_paths = { 00389 "Windows" : "%CCES_HOME%\\Eclipse\\ccesc.exe", 00390 "Linux" : "${CCES_HOME}/Eclipse/cces", 00391 "MacOS" : "${CCES_HOME}/MacOS/cces" 00392 } 00393 00394 commands = {"create":{}, "build":{}} 00395 for operating_system, path in cces_paths.items(): 00396 commands["create"][operating_system] = \ 00397 CCES.get_project_create_command(path, \ 00398 "WORKSPACE", project) 00399 commands["build"][operating_system] = \ 00400 CCES.get_project_build_command(path, \ 00401 "WORKSPACE", project) 00402 00403 jinja_ctx = { 00404 'commands' : commands 00405 } 00406 00407 self.gen_file('cces/README.md.tmpl', jinja_ctx, "README.md") 00408 00409 print("CCES files generated.") 00410 00411 00412 @staticmethod 00413 def clean (_): 00414 os.remove('cces.json') 00415 os.remove('README.md') 00416 00417 @staticmethod 00418 def build (project_name, log_name='build_log.txt', cleanup=True): 00419 """ 00420 Build the generated CCES project using headless builder. 00421 """ 00422 # create the project by importing .json file using CCES headless builder 00423 cces_home = os.getenv("CCES_HOME") 00424 if cces_home is None: 00425 print("Failed to build project: " + \ 00426 "'CCES_HOME' environment variable not defined.") 00427 return -1 00428 00429 cces_path = CCES.get_cces_path(cces_home) 00430 if cces_path is None: 00431 return -1 00432 00433 workspace = tempfile.mkdtemp() 00434 00435 cmd = CCES.get_project_create_command(cces_path, workspace, \ 00436 project_name) 00437 print(cmd) 00438 process = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) 00439 out, err = process.communicate() 00440 ret_code = process.returncode 00441 00442 # cleanup workspace 00443 if os.path.exists(workspace): 00444 shutil.rmtree(workspace, True) 00445 CCES.clean(project_name) 00446 00447 # check return code for failure 00448 if ret_code != 0: 00449 for line in out.split("\n"): 00450 print(line) 00451 for line in err.split("\n"): 00452 print(line) 00453 00454 print("Failed to create project. Return code: %d" % ret_code) 00455 return -1 00456 00457 # build the project 00458 workspace = tempfile.mkdtemp() 00459 00460 cmd = CCES.get_project_build_command(cces_path, workspace, project_name) 00461 print(cmd) 00462 process = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE) 00463 out, err = process.communicate() 00464 ret_code = process.returncode 00465 00466 if log_name: 00467 with open(log_name, 'w+') as log_file: 00468 log_file.write(out) 00469 log_file.write(err) 00470 if ret_code != 0: 00471 log_file.write("Failed to build project. Return code: %d"\ 00472 % ret_code) 00473 00474 # cleanup workspace 00475 if os.path.exists(workspace): 00476 shutil.rmtree(workspace) 00477 00478 # check return code for failure 00479 if ret_code == 0: 00480 return 0 00481 00482 for line in out.split("\n"): 00483 print(line) 00484 for line in err.split("\n"): 00485 print(line) 00486 00487 print("Failed to build project. Return code: %d" % ret_code) 00488 return -1
Generated on Tue Jul 12 2022 12:21:33 by
