1# 2# File : keil.py 3# This file is part of RT-Thread RTOS 4# COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team 5# 6# This program is free software; you can redistribute it and/or modify 7# it under the terms of the GNU General Public License as published by 8# the Free Software Foundation; either version 2 of the License, or 9# (at your option) any later version. 10# 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15# 16# You should have received a copy of the GNU General Public License along 17# with this program; if not, write to the Free Software Foundation, Inc., 18# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19# 20# Change Logs: 21# Date Author Notes 22# 2015-01-20 Bernard Add copyright information 23# 24 25import os 26import sys 27import string 28 29import xml.etree.ElementTree as etree 30from xml.etree.ElementTree import SubElement 31from utils import _make_path_relative 32from utils import xml_indent 33 34fs_encoding = sys.getfilesystemencoding() 35 36def _get_filetype(fn): 37 if fn.rfind('.cpp') != -1 or fn.rfind('.cxx') != -1: 38 return 8 39 40 if fn.rfind('.c') != -1 or fn.rfind('.C') != -1: 41 return 1 42 43 # assemble file type 44 if fn.rfind('.s') != -1 or fn.rfind('.S') != -1: 45 return 2 46 47 # header type 48 if fn.rfind('.h') != -1: 49 return 5 50 51 if fn.rfind('.lib') != -1: 52 return 4 53 54 # other filetype 55 return 5 56 57def MDK4AddGroupForFN(ProjectFiles, parent, name, filename, project_path): 58 group = SubElement(parent, 'Group') 59 group_name = SubElement(group, 'GroupName') 60 group_name.text = name 61 62 name = os.path.basename(filename) 63 path = os.path.dirname (filename) 64 65 basename = os.path.basename(path) 66 path = _make_path_relative(project_path, path) 67 path = os.path.join(path, name) 68 files = SubElement(group, 'Files') 69 file = SubElement(files, 'File') 70 file_name = SubElement(file, 'FileName') 71 name = os.path.basename(path) 72 73 if name.find('.cpp') != -1: 74 obj_name = name.replace('.cpp', '.o') 75 elif name.find('.c') != -1: 76 obj_name = name.replace('.c', '.o') 77 elif name.find('.s') != -1: 78 obj_name = name.replace('.s', '.o') 79 elif name.find('.S') != -1: 80 obj_name = name.replace('.s', '.o') 81 else: 82 obj_name = name 83 84 if ProjectFiles.count(obj_name): 85 name = basename + '_' + name 86 ProjectFiles.append(obj_name) 87 file_name.text = name.decode(fs_encoding) 88 file_type = SubElement(file, 'FileType') 89 file_type.text = '%d' % _get_filetype(name) 90 file_path = SubElement(file, 'FilePath') 91 92 file_path.text = path.decode(fs_encoding) 93 94def MDK4AddLibToGroup(ProjectFiles, group, name, filename, project_path): 95 name = os.path.basename(filename) 96 path = os.path.dirname (filename) 97 98 basename = os.path.basename(path) 99 path = _make_path_relative(project_path, path) 100 path = os.path.join(path, name) 101 files = SubElement(group, 'Files') 102 file = SubElement(files, 'File') 103 file_name = SubElement(file, 'FileName') 104 name = os.path.basename(path) 105 106 if name.find('.cpp') != -1: 107 obj_name = name.replace('.cpp', '.o') 108 elif name.find('.c') != -1: 109 obj_name = name.replace('.c', '.o') 110 elif name.find('.s') != -1: 111 obj_name = name.replace('.s', '.o') 112 elif name.find('.S') != -1: 113 obj_name = name.replace('.s', '.o') 114 else: 115 obj_name = name 116 117 if ProjectFiles.count(obj_name): 118 name = basename + '_' + name 119 ProjectFiles.append(obj_name) 120 file_name.text = name.decode(fs_encoding) 121 file_type = SubElement(file, 'FileType') 122 file_type.text = '%d' % _get_filetype(name) 123 file_path = SubElement(file, 'FilePath') 124 125 file_path.text = path.decode(fs_encoding) 126 127def MDK4AddGroup(ProjectFiles, parent, name, files, project_path): 128 # don't add an empty group 129 if len(files) == 0: 130 return 131 132 group = SubElement(parent, 'Group') 133 group_name = SubElement(group, 'GroupName') 134 group_name.text = name 135 136 for f in files: 137 fn = f.rfile() 138 name = fn.name 139 path = os.path.dirname(fn.abspath) 140 141 basename = os.path.basename(path) 142 path = _make_path_relative(project_path, path) 143 path = os.path.join(path, name) 144 145 files = SubElement(group, 'Files') 146 file = SubElement(files, 'File') 147 file_name = SubElement(file, 'FileName') 148 name = os.path.basename(path) 149 150 if name.find('.cpp') != -1: 151 obj_name = name.replace('.cpp', '.o') 152 elif name.find('.c') != -1: 153 obj_name = name.replace('.c', '.o') 154 elif name.find('.s') != -1: 155 obj_name = name.replace('.s', '.o') 156 elif name.find('.S') != -1: 157 obj_name = name.replace('.s', '.o') 158 159 if ProjectFiles.count(obj_name): 160 name = basename + '_' + name 161 ProjectFiles.append(obj_name) 162 file_name.text = name # name.decode(fs_encoding) 163 file_type = SubElement(file, 'FileType') 164 file_type.text = '%d' % _get_filetype(name) 165 file_path = SubElement(file, 'FilePath') 166 167 file_path.text = path # path.decode(fs_encoding) 168 169 return group 170 171# The common part of making MDK4/5 project 172def MDK45Project(tree, target, script): 173 project_path = os.path.dirname(os.path.abspath(target)) 174 175 root = tree.getroot() 176 out = open(target, 'w') 177 out.write('<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n') 178 179 CPPPATH = [] 180 CPPDEFINES = [] 181 LINKFLAGS = '' 182 CCFLAGS = '' 183 ProjectFiles = [] 184 185 # add group 186 groups = tree.find('Targets/Target/Groups') 187 if groups is None: 188 groups = SubElement(tree.find('Targets/Target'), 'Groups') 189 groups.clear() # clean old groups 190 for group in script: 191 group_tree = MDK4AddGroup(ProjectFiles, groups, group['name'], group['src'], project_path) 192 193 # for local CPPPATH/CPPDEFINES 194 if (group_tree != None) and ('LOCAL_CPPPATH' in group or 'LOCAL_CCFLAGS' in group or 'LOCAL_CPPDEFINES' in group): 195 GroupOption = SubElement(group_tree, 'GroupOption') 196 GroupArmAds = SubElement(GroupOption, 'GroupArmAds') 197 Cads = SubElement(GroupArmAds, 'Cads') 198 VariousControls = SubElement(Cads, 'VariousControls') 199 MiscControls = SubElement(VariousControls, 'MiscControls') 200 if 'LOCAL_CCFLAGS' in group: 201 MiscControls.text = group['LOCAL_CCFLAGS'] 202 else: 203 MiscControls.text = ' ' 204 Define = SubElement(VariousControls, 'Define') 205 if 'LOCAL_CPPDEFINES' in group: 206 Define.text = ', '.join(set(group['LOCAL_CPPDEFINES'])) 207 else: 208 Define.text = ' ' 209 Undefine = SubElement(VariousControls, 'Undefine') 210 Undefine.text = ' ' 211 IncludePath = SubElement(VariousControls, 'IncludePath') 212 if 'LOCAL_CPPPATH' in group: 213 IncludePath.text = ';'.join([_make_path_relative(project_path, os.path.normpath(i)) for i in group['LOCAL_CPPPATH']]) 214 else: 215 IncludePath.text = ' ' 216 217 # get each include path 218 if 'CPPPATH' in group and group['CPPPATH']: 219 if CPPPATH: 220 CPPPATH += group['CPPPATH'] 221 else: 222 CPPPATH += group['CPPPATH'] 223 224 # get each group's definitions 225 if 'CPPDEFINES' in group and group['CPPDEFINES']: 226 if CPPDEFINES: 227 CPPDEFINES += group['CPPDEFINES'] 228 else: 229 CPPDEFINES = group['CPPDEFINES'] 230 231 # get each group's link flags 232 if 'LINKFLAGS' in group and group['LINKFLAGS']: 233 if LINKFLAGS: 234 LINKFLAGS += ' ' + group['LINKFLAGS'] 235 else: 236 LINKFLAGS += group['LINKFLAGS'] 237 238 if 'LIBS' in group and group['LIBS']: 239 for item in group['LIBS']: 240 lib_path = '' 241 for path_item in group['LIBPATH']: 242 full_path = os.path.join(path_item, item + '.lib') 243 if os.path.isfile(full_path): # has this library 244 lib_path = full_path 245 246 if lib_path != '': 247 if (group_tree != None): 248 MDK4AddLibToGroup(ProjectFiles, group_tree, group['name'], lib_path, project_path) 249 else: 250 MDK4AddGroupForFN(ProjectFiles, groups, group['name'], lib_path, project_path) 251 252 # write include path, definitions and link flags 253 IncludePath = tree.find('Targets/Target/TargetOption/TargetArmAds/Cads/VariousControls/IncludePath') 254 IncludePath.text = ';'.join([_make_path_relative(project_path, os.path.normpath(i)) for i in CPPPATH]) 255 256 Define = tree.find('Targets/Target/TargetOption/TargetArmAds/Cads/VariousControls/Define') 257 Define.text = ', '.join(set(CPPDEFINES)) 258 259 Misc = tree.find('Targets/Target/TargetOption/TargetArmAds/LDads/Misc') 260 Misc.text = LINKFLAGS 261 262 xml_indent(root) 263 out.write(etree.tostring(root, encoding='utf-8').decode()) 264 out.close() 265 266def MDK4Project(target, script): 267 template_tree = etree.parse('template.uvproj') 268 269 MDK45Project(template_tree, target, script) 270 271 # remove project.uvopt file 272 project_uvopt = os.path.abspath(target).replace('uvproj', 'uvopt') 273 if os.path.isfile(project_uvopt): 274 os.unlink(project_uvopt) 275 276 # copy uvopt file 277 if os.path.exists('template.uvopt'): 278 import shutil 279 shutil.copy2('template.uvopt', 'project.uvopt') 280 281def MDK5Project(target, script): 282 283 template_tree = etree.parse('template.uvprojx') 284 285 MDK45Project(template_tree, target, script) 286 287 # remove project.uvopt file 288 project_uvopt = os.path.abspath(target).replace('uvprojx', 'uvoptx') 289 if os.path.isfile(project_uvopt): 290 os.unlink(project_uvopt) 291 # copy uvopt file 292 if os.path.exists('template.uvoptx'): 293 import shutil 294 shutil.copy2('template.uvoptx', 'project.uvoptx') 295 296def MDKProject(target, script): 297 template = open('template.Uv2', "r") 298 lines = template.readlines() 299 300 project = open(target, "w") 301 project_path = os.path.dirname(os.path.abspath(target)) 302 303 line_index = 5 304 # write group 305 for group in script: 306 lines.insert(line_index, 'Group (%s)\r\n' % group['name']) 307 line_index += 1 308 309 lines.insert(line_index, '\r\n') 310 line_index += 1 311 312 # write file 313 314 ProjectFiles = [] 315 CPPPATH = [] 316 CPPDEFINES = [] 317 LINKFLAGS = '' 318 CCFLAGS = '' 319 320 # number of groups 321 group_index = 1 322 for group in script: 323 # print group['name'] 324 325 # get each include path 326 if 'CPPPATH' in group and group['CPPPATH']: 327 if CPPPATH: 328 CPPPATH += group['CPPPATH'] 329 else: 330 CPPPATH += group['CPPPATH'] 331 332 # get each group's definitions 333 if 'CPPDEFINES' in group and group['CPPDEFINES']: 334 if CPPDEFINES: 335 CPPDEFINES += group['CPPDEFINES'] 336 else: 337 CPPDEFINES = group['CPPDEFINES'] 338 339 # get each group's link flags 340 if 'LINKFLAGS' in group and group['LINKFLAGS']: 341 if LINKFLAGS: 342 LINKFLAGS += ' ' + group['LINKFLAGS'] 343 else: 344 LINKFLAGS += group['LINKFLAGS'] 345 346 # generate file items 347 for node in group['src']: 348 fn = node.rfile() 349 name = fn.name 350 path = os.path.dirname(fn.abspath) 351 basename = os.path.basename(path) 352 path = _make_path_relative(project_path, path) 353 path = os.path.join(path, name) 354 if ProjectFiles.count(name): 355 name = basename + '_' + name 356 ProjectFiles.append(name) 357 lines.insert(line_index, 'File %d,%d,<%s><%s>\r\n' 358 % (group_index, _get_filetype(name), path, name)) 359 line_index += 1 360 361 group_index = group_index + 1 362 363 lines.insert(line_index, '\r\n') 364 line_index += 1 365 366 # remove repeat path 367 paths = set() 368 for path in CPPPATH: 369 inc = _make_path_relative(project_path, os.path.normpath(path)) 370 paths.add(inc) #.replace('\\', '/') 371 372 paths = [i for i in paths] 373 CPPPATH = string.join(paths, ';') 374 375 definitions = [i for i in set(CPPDEFINES)] 376 CPPDEFINES = string.join(definitions, ', ') 377 378 while line_index < len(lines): 379 if lines[line_index].startswith(' ADSCINCD '): 380 lines[line_index] = ' ADSCINCD (' + CPPPATH + ')\r\n' 381 382 if lines[line_index].startswith(' ADSLDMC ('): 383 lines[line_index] = ' ADSLDMC (' + LINKFLAGS + ')\r\n' 384 385 if lines[line_index].startswith(' ADSCDEFN ('): 386 lines[line_index] = ' ADSCDEFN (' + CPPDEFINES + ')\r\n' 387 388 line_index += 1 389 390 # write project 391 for line in lines: 392 project.write(line) 393 394 project.close() 395 396def ARMCC_Version(): 397 import rtconfig 398 import subprocess 399 import re 400 401 path = rtconfig.EXEC_PATH 402 path = os.path.join(path, 'armcc.exe') 403 404 if os.path.exists(path): 405 cmd = path 406 else: 407 print('Error: get armcc version failed. Please update the KEIL MDK installation path in rtconfig.py!') 408 return "0.0" 409 410 child = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) 411 stdout, stderr = child.communicate() 412 413 ''' 414 example stdout: 415 Product: MDK Plus 5.24 416 Component: ARM Compiler 5.06 update 5 (build 528) 417 Tool: armcc [4d3621] 418 419 return version: MDK Plus 5.24/ARM Compiler 5.06 update 5 (build 528)/armcc [4d3621] 420 ''' 421 422 version_Product = re.search(r'Product: (.+)', stdout).group(1) 423 version_Product = version_Product[:-1] 424 version_Component = re.search(r'Component: (.*)', stdout).group(1) 425 version_Component = version_Component[:-1] 426 version_Tool = re.search(r'Tool: (.*)', stdout).group(1) 427 version_Tool = version_Tool[:-1] 428 version_str_format = '%s/%s/%s' 429 version_str = version_str_format % (version_Product, version_Component, version_Tool) 430 #print('version_str:' + version_str) 431 return version_str 432