keil.py 14.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
#
# File      : keil.py
# This file is part of RT-Thread RTOS
# COPYRIGHT (C) 2006 - 2015, RT-Thread Development Team
#
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License along
#  with this program; if not, write to the Free Software Foundation, Inc.,
#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Change Logs:
# Date           Author       Notes
# 2015-01-20     Bernard      Add copyright information
#

25 26 27 28 29 30 31 32 33 34 35 36
import os
import sys
import string

import xml.etree.ElementTree as etree
from xml.etree.ElementTree import SubElement
from utils import _make_path_relative
from utils import xml_indent

fs_encoding = sys.getfilesystemencoding()

def _get_filetype(fn):
37 38 39
    if fn.rfind('.cpp') != -1 or fn.rfind('.cxx') != -1:
        return 8

40
    if fn.rfind('.c') != -1 or fn.rfind('.C') != -1:
41 42 43 44 45 46 47 48 49 50
        return 1

    # assemble file type
    if fn.rfind('.s') != -1 or fn.rfind('.S') != -1:
        return 2

    # header type
    if fn.rfind('.h') != -1:
        return 5

51 52 53
    if fn.rfind('.lib') != -1:
        return 4

54 55 56
    # other filetype
    return 5

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
def MDK4AddGroupForFN(ProjectFiles, parent, name, filename, project_path):
    group = SubElement(parent, 'Group')
    group_name = SubElement(group, 'GroupName')
    group_name.text = name

    name = os.path.basename(filename)
    path = os.path.dirname (filename)

    basename = os.path.basename(path)
    path = _make_path_relative(project_path, path)
    path = os.path.join(path, name)
    files = SubElement(group, 'Files')
    file = SubElement(files, 'File')
    file_name = SubElement(file, 'FileName')
    name = os.path.basename(path)
72 73 74 75 76 77 78 79 80

    if name.find('.cpp') != -1:
        obj_name = name.replace('.cpp', '.o')
    elif name.find('.c') != -1:
        obj_name = name.replace('.c', '.o')
    elif name.find('.s') != -1:
        obj_name = name.replace('.s', '.o')
    elif name.find('.S') != -1:
        obj_name = name.replace('.s', '.o')
81 82
    else:
        obj_name = name
83 84

    if ProjectFiles.count(obj_name):
85
        name = basename + '_' + name
86
    ProjectFiles.append(obj_name)
87 88 89 90
    file_name.text = name.decode(fs_encoding)
    file_type = SubElement(file, 'FileType')
    file_type.text = '%d' % _get_filetype(name)
    file_path = SubElement(file, 'FilePath')
B
Bright Pan 已提交
91

92 93
    file_path.text = path.decode(fs_encoding)

94 95
    return group

96
def MDK4AddLibToGroup(ProjectFiles, group, name, filename, project_path):
B
Bright Pan 已提交
97 98 99 100 101 102 103 104 105 106
    name = os.path.basename(filename)
    path = os.path.dirname (filename)

    basename = os.path.basename(path)
    path = _make_path_relative(project_path, path)
    path = os.path.join(path, name)
    files = SubElement(group, 'Files')
    file = SubElement(files, 'File')
    file_name = SubElement(file, 'FileName')
    name = os.path.basename(path)
107 108 109 110 111 112 113 114 115

    if name.find('.cpp') != -1:
        obj_name = name.replace('.cpp', '.o')
    elif name.find('.c') != -1:
        obj_name = name.replace('.c', '.o')
    elif name.find('.s') != -1:
        obj_name = name.replace('.s', '.o')
    elif name.find('.S') != -1:
        obj_name = name.replace('.s', '.o')
116 117
    else:
        obj_name = name
118 119

    if ProjectFiles.count(obj_name):
B
Bright Pan 已提交
120
        name = basename + '_' + name
121
    ProjectFiles.append(obj_name)
B
Bright Pan 已提交
122 123 124 125 126 127 128
    file_name.text = name.decode(fs_encoding)
    file_type = SubElement(file, 'FileType')
    file_type.text = '%d' % _get_filetype(name)
    file_path = SubElement(file, 'FilePath')

    file_path.text = path.decode(fs_encoding)

129 130
    return group

131
def MDK4AddGroup(ProjectFiles, parent, name, files, project_path):
B
Bright Pan 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
    # don't add an empty group
    if len(files) == 0:
        return

    group = SubElement(parent, 'Group')
    group_name = SubElement(group, 'GroupName')
    group_name.text = name

    for f in files:
        fn = f.rfile()
        name = fn.name
        path = os.path.dirname(fn.abspath)

        basename = os.path.basename(path)
        path = _make_path_relative(project_path, path)
        path = os.path.join(path, name)

        files = SubElement(group, 'Files')
        file = SubElement(files, 'File')
        file_name = SubElement(file, 'FileName')
        name = os.path.basename(path)
153 154 155 156 157 158 159 160 161 162 163

        if name.find('.cpp') != -1:
            obj_name = name.replace('.cpp', '.o')
        elif name.find('.c') != -1:
            obj_name = name.replace('.c', '.o')
        elif name.find('.s') != -1:
            obj_name = name.replace('.s', '.o')
        elif name.find('.S') != -1:
            obj_name = name.replace('.s', '.o')

        if ProjectFiles.count(obj_name):
B
Bright Pan 已提交
164
            name = basename + '_' + name
165
        ProjectFiles.append(obj_name)
166
        file_name.text = name # name.decode(fs_encoding)
B
Bright Pan 已提交
167 168 169 170
        file_type = SubElement(file, 'FileType')
        file_type.text = '%d' % _get_filetype(name)
        file_path = SubElement(file, 'FilePath')

171
        file_path.text = path # path.decode(fs_encoding)
B
Bright Pan 已提交
172

173
    return group
B
Bright Pan 已提交
174

175 176 177
# The common part of making MDK4/5 project 
def MDK45Project(tree, target, script):
    project_path = os.path.dirname(os.path.abspath(target))
B
Bright Pan 已提交
178 179

    root = tree.getroot()
180
    out = open(target, 'w')
B
Bright Pan 已提交
181 182 183 184 185 186 187 188 189 190 191 192
    out.write('<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n')

    CPPPATH = []
    CPPDEFINES = []
    LINKFLAGS = ''
    CCFLAGS = ''
    ProjectFiles = []

    # add group
    groups = tree.find('Targets/Target/Groups')
    if groups is None:
        groups = SubElement(tree.find('Targets/Target'), 'Groups')
193
    groups.clear() # clean old groups
B
Bright Pan 已提交
194
    for group in script:
195 196 197
        group_tree = MDK4AddGroup(ProjectFiles, groups, group['name'], group['src'], project_path)

        # for local CPPPATH/CPPDEFINES
198
        if (group_tree != None) and ('LOCAL_CPPPATH' in group or 'LOCAL_CCFLAGS' in group or 'LOCAL_CPPDEFINES' in group):
199 200 201 202 203
            GroupOption     = SubElement(group_tree,  'GroupOption')
            GroupArmAds     = SubElement(GroupOption, 'GroupArmAds')
            Cads            = SubElement(GroupArmAds, 'Cads')
            VariousControls = SubElement(Cads, 'VariousControls')
            MiscControls    = SubElement(VariousControls, 'MiscControls')
204
            if 'LOCAL_CCFLAGS' in group:
205 206 207 208
                MiscControls.text = group['LOCAL_CCFLAGS']
            else:
                MiscControls.text = ' '
            Define          = SubElement(VariousControls, 'Define')
209
            if 'LOCAL_CPPDEFINES' in group:
210 211 212 213 214 215
                Define.text     = ', '.join(set(group['LOCAL_CPPDEFINES']))
            else:
                Define.text     = ' '
            Undefine        = SubElement(VariousControls, 'Undefine')
            Undefine.text   = ' '
            IncludePath     = SubElement(VariousControls, 'IncludePath')
216
            if 'LOCAL_CPPPATH' in group:
217 218 219
                IncludePath.text = ';'.join([_make_path_relative(project_path, os.path.normpath(i)) for i in group['LOCAL_CPPPATH']])
            else:
                IncludePath.text = ' '
B
Bright Pan 已提交
220 221

        # get each include path
222
        if 'CPPPATH' in group and group['CPPPATH']:
B
Bright Pan 已提交
223 224 225 226 227 228
            if CPPPATH:
                CPPPATH += group['CPPPATH']
            else:
                CPPPATH += group['CPPPATH']

        # get each group's definitions
229
        if 'CPPDEFINES' in group and group['CPPDEFINES']:
B
Bright Pan 已提交
230 231 232
            if CPPDEFINES:
                CPPDEFINES += group['CPPDEFINES']
            else:
B
Bernard Xiong 已提交
233
                CPPDEFINES = group['CPPDEFINES']
B
Bright Pan 已提交
234 235

        # get each group's link flags
236
        if 'LINKFLAGS' in group and group['LINKFLAGS']:
B
Bright Pan 已提交
237 238 239 240 241
            if LINKFLAGS:
                LINKFLAGS += ' ' + group['LINKFLAGS']
            else:
                LINKFLAGS += group['LINKFLAGS']

242
        if 'LIBS' in group and group['LIBS']:
B
Bright Pan 已提交
243 244 245 246 247 248
            for item in group['LIBS']:
                lib_path = ''
                for path_item in group['LIBPATH']:
                    full_path = os.path.join(path_item, item + '.lib')
                    if os.path.isfile(full_path): # has this library
                        lib_path = full_path
249
                        break
B
Bright Pan 已提交
250 251

                if lib_path != '':
252 253 254 255
                    if group_tree != None:
                        MDK4AddLibToGroup(ProjectFiles, group_tree, group['name'], lib_path, project_path)
                    else:
                        group_tree = MDK4AddGroupForFN(ProjectFiles, groups, group['name'], lib_path, project_path)
B
Bright Pan 已提交
256 257 258

    # write include path, definitions and link flags
    IncludePath = tree.find('Targets/Target/TargetOption/TargetArmAds/Cads/VariousControls/IncludePath')
259
    IncludePath.text = ';'.join([_make_path_relative(project_path, os.path.normpath(i)) for i in CPPPATH])
B
Bright Pan 已提交
260 261

    Define = tree.find('Targets/Target/TargetOption/TargetArmAds/Cads/VariousControls/Define')
262
    Define.text = ', '.join(set(CPPDEFINES))
B
Bright Pan 已提交
263 264 265 266 267

    Misc = tree.find('Targets/Target/TargetOption/TargetArmAds/LDads/Misc')
    Misc.text = LINKFLAGS

    xml_indent(root)
268
    out.write(etree.tostring(root, encoding='utf-8').decode())
B
Bright Pan 已提交
269 270
    out.close()

271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
def MDK4Project(target, script):
    template_tree = etree.parse('template.uvproj')

    MDK45Project(template_tree, target, script)

    # remove project.uvopt file
    project_uvopt = os.path.abspath(target).replace('uvproj', 'uvopt')
    if os.path.isfile(project_uvopt):
        os.unlink(project_uvopt)

    # copy uvopt file
    if os.path.exists('template.uvopt'):
        import shutil
        shutil.copy2('template.uvopt', 'project.uvopt')

def MDK5Project(target, script):

    template_tree = etree.parse('template.uvprojx')

    MDK45Project(template_tree, target, script)

    # remove project.uvopt file
    project_uvopt = os.path.abspath(target).replace('uvprojx', 'uvoptx')
    if os.path.isfile(project_uvopt):
        os.unlink(project_uvopt)
B
Bright Pan 已提交
296 297 298 299 300
    # copy uvopt file
    if os.path.exists('template.uvoptx'):
        import shutil
        shutil.copy2('template.uvoptx', 'project.uvoptx')

301
def MDKProject(target, script):
302
    template = open('template.Uv2', "r")
303 304
    lines = template.readlines()

305
    project = open(target, "w")
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
    project_path = os.path.dirname(os.path.abspath(target))

    line_index = 5
    # write group
    for group in script:
        lines.insert(line_index, 'Group (%s)\r\n' % group['name'])
        line_index += 1

    lines.insert(line_index, '\r\n')
    line_index += 1

    # write file

    ProjectFiles = []
    CPPPATH = []
    CPPDEFINES = []
    LINKFLAGS = ''
    CCFLAGS = ''

    # number of groups
    group_index = 1
    for group in script:
        # print group['name']

        # get each include path
331
        if 'CPPPATH' in group and group['CPPPATH']:
332 333 334 335 336 337
            if CPPPATH:
                CPPPATH += group['CPPPATH']
            else:
                CPPPATH += group['CPPPATH']

        # get each group's definitions
338
        if 'CPPDEFINES' in group and group['CPPDEFINES']:
339 340
            if CPPDEFINES:
                CPPDEFINES += group['CPPDEFINES']
B
Bernard Xiong 已提交
341 342
            else:
                CPPDEFINES = group['CPPDEFINES']
343 344

        # get each group's link flags
345
        if 'LINKFLAGS' in group and group['LINKFLAGS']:
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399
            if LINKFLAGS:
                LINKFLAGS += ' ' + group['LINKFLAGS']
            else:
                LINKFLAGS += group['LINKFLAGS']

        # generate file items
        for node in group['src']:
            fn = node.rfile()
            name = fn.name
            path = os.path.dirname(fn.abspath)
            basename = os.path.basename(path)
            path = _make_path_relative(project_path, path)
            path = os.path.join(path, name)
            if ProjectFiles.count(name):
                name = basename + '_' + name
            ProjectFiles.append(name)
            lines.insert(line_index, 'File %d,%d,<%s><%s>\r\n'
                % (group_index, _get_filetype(name), path, name))
            line_index += 1

        group_index = group_index + 1

    lines.insert(line_index, '\r\n')
    line_index += 1

    # remove repeat path
    paths = set()
    for path in CPPPATH:
        inc = _make_path_relative(project_path, os.path.normpath(path))
        paths.add(inc) #.replace('\\', '/')

    paths = [i for i in paths]
    CPPPATH = string.join(paths, ';')

    definitions = [i for i in set(CPPDEFINES)]
    CPPDEFINES = string.join(definitions, ', ')

    while line_index < len(lines):
        if lines[line_index].startswith(' ADSCINCD '):
            lines[line_index] = ' ADSCINCD (' + CPPPATH + ')\r\n'

        if lines[line_index].startswith(' ADSLDMC ('):
            lines[line_index] = ' ADSLDMC (' + LINKFLAGS + ')\r\n'

        if lines[line_index].startswith(' ADSCDEFN ('):
            lines[line_index] = ' ADSCDEFN (' + CPPDEFINES + ')\r\n'

        line_index += 1

    # write project
    for line in lines:
        project.write(line)

    project.close()
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436

def ARMCC_Version():
    import rtconfig
    import subprocess
    import re

    path = rtconfig.EXEC_PATH
    path = os.path.join(path, 'armcc.exe')

    if os.path.exists(path):
        cmd = path
    else:
        print('Error: get armcc version failed. Please update the KEIL MDK installation path in rtconfig.py!')
        return "0.0"

    child = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
    stdout, stderr = child.communicate()

    '''
    example stdout: 
    Product: MDK Plus 5.24
    Component: ARM Compiler 5.06 update 5 (build 528)
    Tool: armcc [4d3621]

    return version: MDK Plus 5.24/ARM Compiler 5.06 update 5 (build 528)/armcc [4d3621]
    '''

    version_Product = re.search(r'Product: (.+)', stdout).group(1)
    version_Product = version_Product[:-1]
    version_Component = re.search(r'Component: (.*)', stdout).group(1)
    version_Component = version_Component[:-1]
    version_Tool = re.search(r'Tool: (.*)', stdout).group(1)
    version_Tool = version_Tool[:-1]
    version_str_format = '%s/%s/%s'
    version_str = version_str_format % (version_Product, version_Component, version_Tool)
    #print('version_str:' + version_str)
    return version_str