xref: /nrf52832-nimble/rt-thread/tools/keil.py (revision 104654410c56c573564690304ae786df310c91fc)
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