keil.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  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. import os
  25. import sys
  26. import string
  27. import xml.etree.ElementTree as etree
  28. from xml.etree.ElementTree import SubElement
  29. from utils import _make_path_relative
  30. from utils import xml_indent
  31. fs_encoding = sys.getfilesystemencoding()
  32. def _get_filetype(fn):
  33. if fn.rfind('.cpp') != -1 or fn.rfind('.cxx') != -1:
  34. return 8
  35. if fn.rfind('.c') != -1 or fn.rfind('.C') != -1:
  36. return 1
  37. # assemble file type
  38. if fn.rfind('.s') != -1 or fn.rfind('.S') != -1:
  39. return 2
  40. # header type
  41. if fn.rfind('.h') != -1:
  42. return 5
  43. if fn.rfind('.lib') != -1:
  44. return 4
  45. # other filetype
  46. return 5
  47. def MDK4AddGroupForFN(ProjectFiles, parent, name, filename, project_path):
  48. group = SubElement(parent, 'Group')
  49. group.text = name
  50. group_name = SubElement(group, 'GroupName')
  51. group_name.text = name
  52. name = os.path.basename(filename)
  53. path = os.path.dirname (filename)
  54. basename = os.path.basename(path)
  55. path = _make_path_relative(project_path, path)
  56. path = os.path.join(path, name)
  57. files = SubElement(group, 'Files')
  58. file = SubElement(files, 'File')
  59. file_name = SubElement(file, 'FileName')
  60. name = os.path.basename(path)
  61. if name.find('.cpp') != -1:
  62. obj_name = name.replace('.cpp', '.o')
  63. elif name.find('.c') != -1:
  64. obj_name = name.replace('.c', '.o')
  65. elif name.find('.s') != -1:
  66. obj_name = name.replace('.s', '.o')
  67. elif name.find('.S') != -1:
  68. obj_name = name.replace('.s', '.o')
  69. else:
  70. obj_name = name
  71. if ProjectFiles.count(obj_name):
  72. name = basename + '_' + name
  73. ProjectFiles.append(obj_name)
  74. file_name.text = name.decode(fs_encoding)
  75. file_type = SubElement(file, 'FileType')
  76. file_type.text = '%d' % _get_filetype(name)
  77. file_path = SubElement(file, 'FilePath')
  78. file_path.text = path.decode(fs_encoding)
  79. def MDK4AddLibToGroup(ProjectFiles, group, name, filename, project_path):
  80. name = os.path.basename(filename)
  81. path = os.path.dirname (filename)
  82. basename = os.path.basename(path)
  83. path = _make_path_relative(project_path, path)
  84. path = os.path.join(path, name)
  85. files = SubElement(group, 'Files')
  86. file = SubElement(files, 'File')
  87. file_name = SubElement(file, 'FileName')
  88. name = os.path.basename(path)
  89. if name.find('.cpp') != -1:
  90. obj_name = name.replace('.cpp', '.o')
  91. elif name.find('.c') != -1:
  92. obj_name = name.replace('.c', '.o')
  93. elif name.find('.s') != -1:
  94. obj_name = name.replace('.s', '.o')
  95. elif name.find('.S') != -1:
  96. obj_name = name.replace('.s', '.o')
  97. else:
  98. obj_name = name
  99. if ProjectFiles.count(obj_name):
  100. name = basename + '_' + name
  101. ProjectFiles.append(obj_name)
  102. file_name.text = name.decode(fs_encoding)
  103. file_type = SubElement(file, 'FileType')
  104. file_type.text = '%d' % _get_filetype(name)
  105. file_path = SubElement(file, 'FilePath')
  106. file_path.text = path.decode(fs_encoding)
  107. def MDK4AddGroup(ProjectFiles, parent, name, files, project_path):
  108. # don't add an empty group
  109. if len(files) == 0:
  110. return
  111. group = SubElement(parent, 'Group')
  112. group_name = SubElement(group, 'GroupName')
  113. group_name.text = name
  114. for f in files:
  115. fn = f.rfile()
  116. name = fn.name
  117. path = os.path.dirname(fn.abspath)
  118. basename = os.path.basename(path)
  119. path = _make_path_relative(project_path, path)
  120. path = os.path.join(path, name)
  121. files = SubElement(group, 'Files')
  122. file = SubElement(files, 'File')
  123. file_name = SubElement(file, 'FileName')
  124. name = os.path.basename(path)
  125. if name.find('.cpp') != -1:
  126. obj_name = name.replace('.cpp', '.o')
  127. elif name.find('.c') != -1:
  128. obj_name = name.replace('.c', '.o')
  129. elif name.find('.s') != -1:
  130. obj_name = name.replace('.s', '.o')
  131. elif name.find('.S') != -1:
  132. obj_name = name.replace('.s', '.o')
  133. if ProjectFiles.count(obj_name):
  134. name = basename + '_' + name
  135. ProjectFiles.append(obj_name)
  136. file_name.text = name # name.decode(fs_encoding)
  137. file_type = SubElement(file, 'FileType')
  138. file_type.text = '%d' % _get_filetype(name)
  139. file_path = SubElement(file, 'FilePath')
  140. file_path.text = path # path.decode(fs_encoding)
  141. return group
  142. # The common part of making MDK4/5 project
  143. def MDK45Project(tree, target, script):
  144. project_path = os.path.dirname(os.path.abspath(target))
  145. root = tree.getroot()
  146. out = open(target, 'w')
  147. out.write('<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n')
  148. CPPPATH = []
  149. CPPDEFINES = []
  150. LINKFLAGS = ''
  151. CCFLAGS = ''
  152. ProjectFiles = []
  153. # add group
  154. groups = tree.find('Targets/Target/Groups')
  155. if groups is None:
  156. groups = SubElement(tree.find('Targets/Target'), 'Groups')
  157. groups.clear() # clean old groups
  158. for group in script:
  159. group_tree = MDK4AddGroup(ProjectFiles, groups, group['name'], group['src'], project_path)
  160. # for local CPPPATH/CPPDEFINES
  161. if (group_tree != None) and ('LOCAL_CPPPATH' in group or 'LOCAL_CCFLAGS' in group or 'LOCAL_CPPDEFINES' in group):
  162. GroupOption = SubElement(group_tree, 'GroupOption')
  163. GroupArmAds = SubElement(GroupOption, 'GroupArmAds')
  164. Cads = SubElement(GroupArmAds, 'Cads')
  165. VariousControls = SubElement(Cads, 'VariousControls')
  166. MiscControls = SubElement(VariousControls, 'MiscControls')
  167. if 'LOCAL_CCFLAGS' in group:
  168. MiscControls.text = group['LOCAL_CCFLAGS']
  169. else:
  170. MiscControls.text = ' '
  171. Define = SubElement(VariousControls, 'Define')
  172. if 'LOCAL_CPPDEFINES' in group:
  173. Define.text = ', '.join(set(group['LOCAL_CPPDEFINES']))
  174. else:
  175. Define.text = ' '
  176. Undefine = SubElement(VariousControls, 'Undefine')
  177. Undefine.text = ' '
  178. IncludePath = SubElement(VariousControls, 'IncludePath')
  179. if 'LOCAL_CPPPATH' in group:
  180. IncludePath.text = ';'.join([_make_path_relative(project_path, os.path.normpath(i)) for i in group['LOCAL_CPPPATH']])
  181. else:
  182. IncludePath.text = ' '
  183. # get each include path
  184. if 'CPPPATH' in group and group['CPPPATH']:
  185. if CPPPATH:
  186. CPPPATH += group['CPPPATH']
  187. else:
  188. CPPPATH += group['CPPPATH']
  189. # get each group's definitions
  190. if 'CPPDEFINES' in group and group['CPPDEFINES']:
  191. if CPPDEFINES:
  192. CPPDEFINES += group['CPPDEFINES']
  193. else:
  194. CPPDEFINES = group['CPPDEFINES']
  195. # get each group's link flags
  196. if 'LINKFLAGS' in group and group['LINKFLAGS']:
  197. if LINKFLAGS:
  198. LINKFLAGS += ' ' + group['LINKFLAGS']
  199. else:
  200. LINKFLAGS += group['LINKFLAGS']
  201. if 'LIBS' in group and group['LIBS']:
  202. for item in group['LIBS']:
  203. lib_path = ''
  204. for path_item in group['LIBPATH']:
  205. full_path = os.path.join(path_item, item + '.lib')
  206. if os.path.isfile(full_path): # has this library
  207. lib_path = full_path
  208. if lib_path != '':
  209. need_create = 1
  210. for neighbor in groups.iter('Group'):
  211. if neighbor.text == group['name']:
  212. MDK4AddLibToGroup(ProjectFiles, neighbor, group['name'], lib_path, project_path)
  213. need_create = 0
  214. break
  215. if (need_create != 0):
  216. MDK4AddGroupForFN(ProjectFiles, groups, group['name'], lib_path, project_path)
  217. # write include path, definitions and link flags
  218. IncludePath = tree.find('Targets/Target/TargetOption/TargetArmAds/Cads/VariousControls/IncludePath')
  219. IncludePath.text = ';'.join([_make_path_relative(project_path, os.path.normpath(i)) for i in CPPPATH])
  220. Define = tree.find('Targets/Target/TargetOption/TargetArmAds/Cads/VariousControls/Define')
  221. Define.text = ', '.join(set(CPPDEFINES))
  222. Misc = tree.find('Targets/Target/TargetOption/TargetArmAds/LDads/Misc')
  223. Misc.text = LINKFLAGS
  224. xml_indent(root)
  225. out.write(etree.tostring(root, encoding='utf-8').decode())
  226. out.close()
  227. def MDK4Project(target, script):
  228. template_tree = etree.parse('template.uvproj')
  229. MDK45Project(template_tree, target, script)
  230. # remove project.uvopt file
  231. project_uvopt = os.path.abspath(target).replace('uvproj', 'uvopt')
  232. if os.path.isfile(project_uvopt):
  233. os.unlink(project_uvopt)
  234. # copy uvopt file
  235. if os.path.exists('template.uvopt'):
  236. import shutil
  237. shutil.copy2('template.uvopt', 'project.uvopt')
  238. def MDK5Project(target, script):
  239. template_tree = etree.parse('template.uvprojx')
  240. MDK45Project(template_tree, target, script)
  241. # remove project.uvopt file
  242. project_uvopt = os.path.abspath(target).replace('uvprojx', 'uvoptx')
  243. if os.path.isfile(project_uvopt):
  244. os.unlink(project_uvopt)
  245. # copy uvopt file
  246. if os.path.exists('template.uvoptx'):
  247. import shutil
  248. shutil.copy2('template.uvoptx', 'project.uvoptx')
  249. def MDKProject(target, script):
  250. template = open('template.Uv2', "r")
  251. lines = template.readlines()
  252. project = open(target, "w")
  253. project_path = os.path.dirname(os.path.abspath(target))
  254. line_index = 5
  255. # write group
  256. for group in script:
  257. lines.insert(line_index, 'Group (%s)\r\n' % group['name'])
  258. line_index += 1
  259. lines.insert(line_index, '\r\n')
  260. line_index += 1
  261. # write file
  262. ProjectFiles = []
  263. CPPPATH = []
  264. CPPDEFINES = []
  265. LINKFLAGS = ''
  266. CCFLAGS = ''
  267. # number of groups
  268. group_index = 1
  269. for group in script:
  270. # print group['name']
  271. # get each include path
  272. if 'CPPPATH' in group and group['CPPPATH']:
  273. if CPPPATH:
  274. CPPPATH += group['CPPPATH']
  275. else:
  276. CPPPATH += group['CPPPATH']
  277. # get each group's definitions
  278. if 'CPPDEFINES' in group and group['CPPDEFINES']:
  279. if CPPDEFINES:
  280. CPPDEFINES += group['CPPDEFINES']
  281. else:
  282. CPPDEFINES = group['CPPDEFINES']
  283. # get each group's link flags
  284. if 'LINKFLAGS' in group and group['LINKFLAGS']:
  285. if LINKFLAGS:
  286. LINKFLAGS += ' ' + group['LINKFLAGS']
  287. else:
  288. LINKFLAGS += group['LINKFLAGS']
  289. # generate file items
  290. for node in group['src']:
  291. fn = node.rfile()
  292. name = fn.name
  293. path = os.path.dirname(fn.abspath)
  294. basename = os.path.basename(path)
  295. path = _make_path_relative(project_path, path)
  296. path = os.path.join(path, name)
  297. if ProjectFiles.count(name):
  298. name = basename + '_' + name
  299. ProjectFiles.append(name)
  300. lines.insert(line_index, 'File %d,%d,<%s><%s>\r\n'
  301. % (group_index, _get_filetype(name), path, name))
  302. line_index += 1
  303. group_index = group_index + 1
  304. lines.insert(line_index, '\r\n')
  305. line_index += 1
  306. # remove repeat path
  307. paths = set()
  308. for path in CPPPATH:
  309. inc = _make_path_relative(project_path, os.path.normpath(path))
  310. paths.add(inc) #.replace('\\', '/')
  311. paths = [i for i in paths]
  312. CPPPATH = string.join(paths, ';')
  313. definitions = [i for i in set(CPPDEFINES)]
  314. CPPDEFINES = string.join(definitions, ', ')
  315. while line_index < len(lines):
  316. if lines[line_index].startswith(' ADSCINCD '):
  317. lines[line_index] = ' ADSCINCD (' + CPPPATH + ')\r\n'
  318. if lines[line_index].startswith(' ADSLDMC ('):
  319. lines[line_index] = ' ADSLDMC (' + LINKFLAGS + ')\r\n'
  320. if lines[line_index].startswith(' ADSCDEFN ('):
  321. lines[line_index] = ' ADSCDEFN (' + CPPDEFINES + ')\r\n'
  322. line_index += 1
  323. # write project
  324. for line in lines:
  325. project.write(line)
  326. project.close()
  327. def ARMCC_Version():
  328. import rtconfig
  329. import subprocess
  330. import re
  331. path = rtconfig.EXEC_PATH
  332. path = os.path.join(path, 'armcc.exe')
  333. if os.path.exists(path):
  334. cmd = path
  335. else:
  336. print('Error: get armcc version failed. Please update the KEIL MDK installation path in rtconfig.py!')
  337. return "0.0"
  338. child = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
  339. stdout, stderr = child.communicate()
  340. '''
  341. example stdout:
  342. Product: MDK Plus 5.24
  343. Component: ARM Compiler 5.06 update 5 (build 528)
  344. Tool: armcc [4d3621]
  345. return version: MDK Plus 5.24/ARM Compiler 5.06 update 5 (build 528)/armcc [4d3621]
  346. '''
  347. version_Product = re.search(r'Product: (.+)', stdout).group(1)
  348. version_Product = version_Product[:-1]
  349. version_Component = re.search(r'Component: (.*)', stdout).group(1)
  350. version_Component = version_Component[:-1]
  351. version_Tool = re.search(r'Tool: (.*)', stdout).group(1)
  352. version_Tool = version_Tool[:-1]
  353. version_str_format = '%s/%s/%s'
  354. version_str = version_str_format % (version_Product, version_Component, version_Tool)
  355. #print('version_str:' + version_str)
  356. return version_str