nuttx/tools/ide_exporter.py
Xiang Xiao 68951e8d72 Remove exra whitespace from files (#189)
* Remove multiple newlines at the end of files
* Remove the whitespace from the end of lines
2020-01-31 09:24:49 -06:00

1012 lines
34 KiB
Python
Executable File

#!/usr/bin/env python
############################################################################
# tools/ide_exporter.py
#
# Copyright (C) 2016 Kha Vo. All rights reserved.
# Author: Kha Vo <canhkha@gmail.com>
#
# Based on convert_make2file_list.py and add_source_in_iar.py
# Author: avyhovanec@yahoo.com
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
from __future__ import print_function
import os
import subprocess
import re
import sys
import argparse
from lxml import etree as ET
from copy import deepcopy
HELP = """
ide_exporter.pyis a tool for generation nuttx iar/keil workspace
usage: ide_exporter.py [-h] [-v] [-o OUT_DIR] [-d]
build_log {iar,uvision_gcc,uvision_armcc} template_dir
positional arguments:
build_log Log file from make V=1
{iar,uvision_gcc,uvision_armcc}
The target IDE: iar, uvision_gcc, (uvision_armcc is
experimental)
template_dir Directory that contains IDEs template projects
template_nuttx.eww : iar template workspace
template_nuttx_main.ewp : iar template project
template_nuttx_lib.ewp : iar library project
or
template_nuttx.uvmpw : uVision template workspace
template_nuttx_main.uvproj : uVision template project
template_nuttx_lib.uvproj : uVision library project
optional arguments:
-h, --help show this help message and exit
-v, --version show program's version number and exit
-o OUT_DIR, --output OUT_DIR
Output directory
-d, --dump Dump project structure tree
"""
IAR = 'iar'
UVISION_GCC = 'uvision_gcc'
UVISION_ARMCC = 'uvision_armcc'
COMPILE_PREFIX_LIST = ('CC: ', 'AS: ', 'CXX:')
LIB_PREFIX_LIST = ('AR: ')
LINK_PREFIX_LIST = ('LD: ')
MAKE_ENTER_DIR = 'Entering directory'
PREFIX_LEN = 4
IAR_EXT_REMAP = {r'gnu/(\w+)\.S$' : r'iar/\g<1>.S'}
ARMCC_EXT_REMAP = {r'gnu/(\w+)\.S$' : r'armcc/\g<1>.S',
r'(\w+)\.a$': r'\g<1>.lib'}
UVISION_GCC_EXT_REMAP = {}
# file ext to FileTye in uVision project
UVISION_FILE_TYPE_MAP = {'.c': '1', '.S' : '1', '.cxx' : '8', '.lib' : '4', '.a' : '4'}
# tags convention: tag[0] = root_tags, create if doesn't exist
# tag[1] = (sub_tag,) tag without text, create new
# tag[2] = (leaf_tag,) with text, create new
IAR_PRJ_SETTINGS = {'group_tags' : ('', ('group',), ('name', )),
'file_tags' :('', ('file',), ('name', )),
'rel_base' : '$PROJ_DIR$/',
'cleared_nodes' : ('group', 'file', ),
'include_pnodes' : (".//*[name='CCIncludePath2']", ".//*[name='AUserIncludes']"),
'include_tag' : 'state',
'output_path' : {'exe' : 'Obj', 'obj' : 'Obj', 'lst' : 'Lst'},
'ext_remap' : IAR_EXT_REMAP,}
IAR_WSP_SETTINGS = {'group_tags': ('',),
'file_tags':('', ('project', ), ('path',)),
'rel_base':'$WS_DIR$/',
'cleared_nodes': ('project', )}
UVISION_ARMCC_PRJ_SETTINGS = {'root_group':'',
'group_tags': ('.//Targets/Target/Groups', ('Group', ), ('GroupName', )),
'file_tags':('Files', ('File', ), ('FileName', 'FileType', 'FilePath', )),
'rel_base':'',
'cleared_nodes': ('.//Group', ),
'include_pnodes' : ".//VariousControls/IncludePath",
'output_path' : {'exe' : 'Obj', 'obj' : 'Obj', 'lst' : 'Lst'},
'ext_remap' : ARMCC_EXT_REMAP,
'uv_file_type' : UVISION_FILE_TYPE_MAP}
UVISION_GCC_PRJ_SETTINGS = {'root_group':'',
'group_tags': ('.//Targets/Target/Groups', ('Group', ), ('GroupName', )),
'file_tags':('Files', ('File', ), ('FileName', 'FileType', 'FilePath', )),
'rel_base':'',
'cleared_nodes': ('.//Group', ),
'include_pnodes' : ".//VariousControls/IncludePath",
'saved_tags' : ('.//FileOption', ),
'output_path' : {'exe' : 'Obj', 'obj' : 'Obj', 'lst' : 'Lst'},
'ext_remap' : UVISION_GCC_EXT_REMAP,
'uv_file_type' : UVISION_FILE_TYPE_MAP,
'c_misc' : ('.//Carm', '-fno-builtin -Wall -Wstrict-prototypes -Wshadow -Wundef -g'),
'cxx_misc' : ('.//Carm', '-fno-builtin -fno-exceptions -fcheck-new -fno-rtti -Wall -Wshadow -Wundef -g'),
'ld_misc' : ('.//LDarm', '--entry=__start -lgcc'),
'cxx_def' : ('.//Carm', ''),}
UVISION_WSP_SETTINGS = {'group_tags': ('',),
'file_tags':('', ('project', ), ('PathAndName', )),
'rel_base':'',
'cleared_nodes': ('project', )}
LIB_EXTS = ('.a', '.lib')
ASM_EXTS = ('.s', '.S')
def get_common_dir(dir_list):
""" Get common parent directory of a given directory list
"""
com_dir = dir_list[0]
found = False
while found == False:
found = True
com_dir = os.path.split(com_dir)[0]
for directory in dir_list:
if com_dir not in directory:
found = False
break
if found:
return com_dir
else:
return "/" #return root
class SourceInfo(object):
"""Source file information
Attributes:
src: source file
include: List of including dir in compiled command
flags: other compiled flags
"""
def __init__(self, src, include=None, flags=''):
self.include = []
if include is not None:
self.include = include
self.src = src
self.flags = flags
self.include = include
@staticmethod
def get_common_src_dir(sinfo_list):
""" Get Common directory from list of source code
"""
source_list = [info.src for info in sinfo_list]
com_dir = get_common_dir(source_list)
return com_dir
@staticmethod
def get_including_set(sinfo_list):
""" Get including set from list of source code
"""
include_set = set()
for sinfo in sinfo_list:
for inc in sinfo.include:
if inc != '':
include_set.add(inc)
return include_set
class IdeProject(object):
"""Base IDE project class.
make_src_nodes(self, source, group = None, parent_node = None):
make_include(self, sources, parent_node = None):
make_output_dir(self, target):
These functions need to override
Attributes:
root: root of its etree
ewp_ET: Its etree
settings: specific IDE setting
proj_dir: base directory, files path are often relative from this
rel_base: base directory symbol,
"""
def __init__(self, proj, settings, out_dir=None, use_gcc=False):
self.proj_dir = os.path.split(proj)[0]
if (out_dir is not None) and os.path.exists(out_dir):
self.proj_dir = out_dir
self.root = None
self.ewp_ET = None
self.settings = {}
self.rel_base = ''
if settings is not None:
self.settings = settings
self.use_gcc = use_gcc
self.rel_base = self.settings.get('rel_base', '')
self.saved_nodes = {} #some inside nodes need to save before clear all sources
try:
#Read template project xml structure
parser = ET.XMLParser(remove_blank_text=True) # use parser to make pretty print works
self.ewp_ET = ET.parse(proj, parser)
self.root = self.ewp_ET.getroot()
# Save some template nodes before clear
for tag in self.settings.get('saved_tags', []):
n = self.root.find(tag)
self.saved_nodes[tag] = deepcopy(n)
self.clear_src_nodes() # Clear all source node in template file
except Exception as e:
print("ERR: {0}".format(str(e)))
raise Exception("Can't init IdeProject object")
def get_relpath(self, dest):
""" Get relative path from its base directory
"""
return self.rel_base + os.path.relpath(dest, self.proj_dir)
def get_output_dir(self):
"""
"""
out_paths = self.settings.get('output_path', {})
return out_paths.get('exe', '')
def get_obj_dir(self):
"""
"""
out_paths = self.settings.get('output_path', {})
return out_paths.get('obj', '')
def get_lst_dir(self):
"""
"""
out_paths = self.settings.get('output_path', {})
return out_paths.get('lst', '')
def write(self, ofile):
""" Write etree to file
"""
self.ewp_ET.write(ofile, pretty_print=True, xml_declaration=True, encoding='UTF-8')
def remove_nodes(self, element, remove_list):
"""Delete nodes in list from the xlm tree
Args:
element: root node of etree
remove_list: tuple of all node that need to remove
Returns:
Remove nodes from xlm tree
Raises:
None
"""
try:
for node in remove_list:
p = element.find(node)
while p is not None:
c = p.getparent()
c.remove(p)
p = element.find(node)
except Exception as e:
print(str(e))
def clear_src_nodes(self):
""" Remove all predefined node in settings from its etree
"""
self.remove_nodes(self.root, self.settings.get('cleared_nodes', []))
def make_nodes(self, parent_node, tags, *args):
""" Create node(s) by using tag convention
Return most inner parent nodes
"""
if parent_node is None:
parent_node = self.root
head = None
root = None
#print "Create tags: ", tags
if len(tags) == 3:
# Check root, create if not exist
root_tag = tags[0]
if root_tag != '':
root = parent_node.find(root_tag)
if root is None:
root = ET.SubElement(parent_node, root_tag.split('/')[-1])
else:
root = parent_node
p_node = root
# Create middle sub nodes
sub_tags = tags[1]
if len(sub_tags) > 0:
head = ET.Element(sub_tags[0])
p_node = head
for tag in sub_tags[1:]:
p_node = ET.SubElement(p_node, tag)
# Create leaf node with input text
for src_tag, text in zip(tags[2], args):
e = ET.SubElement(p_node, src_tag)
e.text = text
if head is not None:
root.append(head)
else:
raise Exception('Wrong tag convention')
return p_node
def make_group(self, parent_node, *args):
""" Create group of source/lib tags
Tags info are get from settings
Args:
parent_node :
*args : nodes' text
return:
Return group node
"""
tags = self.settings.get('group_tags', [])
return self.make_nodes(parent_node, tags, *args)
def make_file(self, parent_node, *args):
""" Create group of source/lib tags
Tags info are get from settings
"""
tags = self.settings.get('file_tags', [])
return self.make_nodes(parent_node, tags, *args)
def make_src_nodes(self, source, group=None, parent_node=None):
""" Create xlm nodes for list of source file
Args:
sources: list of SourceInfo
group : group name that contains all of these source
parent_node : etree fake root node
Returns:
"""
pass
def make_include(self, sources, parent_node=None):
""" Create including nodes from source info for project
Args:
sources: list of SourceInfo
parent_node: etree fake root node
Returns:
"""
pass
def make_output_dir(self, target):
""" Update output directory setting for project
Args:
target: project output target name
Returns:
"""
pass
def add_misc(self, mtype, misc=''):
pass
def add_define(self, dtype, symbols):
pass
def set_link_libs(self, lib_dir, libs):
pass
def set_mcu(self, mcu):
pass
def set_core(self, core):
pass
@staticmethod
def factory(objtype, xml_file, out_dir=None):
""" Factory to create obj by derived type
"""
return objtype(xml_file, out_dir=out_dir)
class IARWorkspace(IdeProject):
"""IAR workspace class.
Depend on its settings only.
Use default add node from base to add sub library project
Attributes:
"""
def __init__(self, proj, out_dir=None):
super(IARWorkspace, self).__init__(proj, IAR_WSP_SETTINGS, out_dir)
class IARProject(IdeProject):
"""IAR project class.
Add some specific logics to create source, include and output setting
"""
def __init__(self, proj, settings=IAR_PRJ_SETTINGS, out_dir=None):
super(IARProject, self).__init__(proj, settings, out_dir)
def make_include(self, sources, parent_node=None):
""" Create including nodes from source info for project
IAR sample including nodes
<option>
<name>CCIncludePath2</name>
<state>$PROJ_DIR$\nuttx\include\</state>
</option>
Args:
sources: list of SourceInfo
parent_node: etree fake root node
Returns:
"""
if parent_node is None:
parent_node = self.root
include_set = SourceInfo.get_including_set(sources)
# Adding dir to user include node, tags is from setting
include_nodes = self.settings['include_pnodes']
for path in include_nodes:
for p in parent_node.iterfind(path): # ex: ".//*[name='CCIncludePath2']"
#print(n.tag, n.text)
for inc in include_set:
state = ET.SubElement(p, self.settings['include_tag'])
# In cygwin, we need to convert windows path to relative
if sys.platform == 'cygwin':
inc = subprocess.check_output(['cygpath', '-u', inc])
inc = inc[:-1] #remove /n
state.text = self.get_relpath(inc)
def make_src_nodes(self, sources, group=None, parent_node=None):
""" Create nodes for list of source file
Args:
sources: list of SourceInfo
group: group name that contains all of these source
parent_node: etree fake root node
Returns:
"""
if parent_node is None:
parent_node = self.root
source_list = [info.src for info in sources]
com_dir = get_common_dir(source_list)
com_dir_name = os.path.split(com_dir)[1]
if group is None:
group = com_dir_name
# Create group node to contain all source files
group_node = self.make_group(parent_node, group)
# Add source files to group as sub node
for src in source_list:
fname = self.get_relpath(src) # make ref path from $PROJ_DIR$ to file
ext_remap = self.settings.get('ext_remap', {})
for ext, replacement in ext_remap.items():
fname = re.sub(ext, replacement, fname)
self.make_file(group_node, fname)
def make_output_dir(self, target):
""" Update output directory setting for IAR project
Args:
target: project's target name
Returns:
"""
sub_dir = '$PROJ_FNAME$'
exe_path = self.get_output_dir()
lst_path = self.get_output_dir()
obj_path = self.get_output_dir()
dirs = (exe_path, obj_path, lst_path)
tags = ('.//*[name="ExePath"]', './/*[name="ObjPath"]', './/*[name="ListPath"]')
for path, tag in zip(dirs, tags):
if path != '':
p = self.root.findall(tag)
for n in p:
self.remove_nodes(n, ('state', ))
e = ET.SubElement(n, 'state')
e.text = sub_dir + '/' + path
class UVisionWorkspace(IdeProject):
"""uVision workspace class.
Depend on its settings only.
Use default add node from base to add sub library project
Attributes:
"""
def __init__(self, proj, out_dir=None):
super(UVisionWorkspace, self).__init__(proj, UVISION_WSP_SETTINGS, out_dir)
class UVisionProject(IdeProject):
"""uVision project class.
Add some specific logics to create source, include and output setting
"""
def __init__(self, proj, settings=UVISION_ARMCC_PRJ_SETTINGS, out_dir=None, use_gcc=False):
super(UVisionProject, self).__init__(proj, settings, out_dir, use_gcc)
self.use_gcc = use_gcc
def make_include(self, sources, parent_node=None):
""" Create including nodes from source info for uVision project
uVision sample including nodes:
<VariousControls>
<IncludePath>../../../../apps/examples/hello;../../../../apps/examples/nsh>
</VariousControls>
Args:
sources: list of SourceInfo
parent_node: etree fake root node
Returns:
"""
if parent_node is None:
parent_node = self.root
include_set = SourceInfo.get_including_set(sources)
incs = []
for inc in include_set:
# In cygwin, we need to convert windows path to relative
if sys.platform == 'cygwin':
inc = subprocess.check_output(['cygpath', '-u', inc])
inc = inc[:-1] #remove /n
inc = self.get_relpath(inc)
incs.append(inc)
inc_text = ';'.join(incs)
# Adding dir to user include node (both ASM & CC)
for n in parent_node.iterfind(self.settings['include_pnodes']):
n.text = inc_text
def make_src_nodes(self, sources, group=None, parent_node=None):
""" Create nodes for list of source file
Sample uVision file:
<Groups>
<Group>
<GroupName>board</GroupName>
<Files>
<File>
<FileName>stm32_boot.c</FileName>
<FileType>1</FileType>
<FilePath>../../../arch/arm/src/board/stm32_boot.c</FilePath>
</File>
</Files>
</Group>
</Groups>
Args:
sources: list of SourceInfo
group: group name that contains all of these source
parent_node: etree fake root node
Returns:
"""
if parent_node is None:
parent_node = self.root
source_list = [info.src for info in sources]
com_dir = get_common_dir(source_list)
com_dir_name = os.path.split(com_dir)[1]
if group is None:
group = com_dir_name
# Create group node to contain all source files
group_node = self.make_group(parent_node, group) # return <Group> node
# Add source files to group as sub node
for src in source_list:
fname = self.get_relpath(src)
ext = os.path.splitext(fname)[1]
# get uVison FileType
uv_file_type = self.settings.get('uv_file_type', {})
ftype = uv_file_type.get(ext, '0')
# Translate source to new format/location if need
ext_remap = self.settings.get('ext_remap', {})
for find, replacement in ext_remap.items():
fname = re.sub(find, replacement, fname)
name = os.path.split(fname)[1]
file_node = self.make_file(group_node, name, ftype, fname)
# Make exception for .S file (treat as C source with D__ASSEMBLY__)
if (self.use_gcc) and (ext in ASM_EXTS):
asm_opt_node = self.saved_nodes.get('.//FileOption')
if asm_opt_node is not None:
file_node.append(deepcopy(asm_opt_node))
def make_output_dir(self, target):
""" Update output directory setting for IAR project
Args:
target: project's target name
Returns:
"""
exe_path = self.get_output_dir()
if exe_path != '':
p = self.root.find('.//OutputDirectory')
if p is not None:
p.text = '\\'.join(('.', target, exe_path, ''))
lst_path = self.get_lst_dir()
if lst_path != '':
p = self.root.find('.//ListingPath')
if p is not None:
p.text = '\\'.join(('.', target, lst_path, ''))
p = self.root.find('.//OutputName')
if p is not None:
p.text = re.sub(r'^lib(.*)$', r'\g<1>', target) # prevent liblibapps.a
def add_misc(self, mtype, misc=''):
misc_info = self.settings.get(mtype)
if misc_info is not None:
tag, default = misc_info
if misc == '':
misc = default
n = self.root.find(tag)
if n is not None:
m = n.find('.//MiscControls')
if m is not None:
m.text = (m.text or '') + ' ' + misc
def add_define(self, dtype, symbols):
def_info = self.settings.get(dtype)
if def_info is not None:
tag, default = def_info
n = self.root.find(tag)
if n is not None:
m = n.find('.//Define')
if m is not None:
m.text = (m.text or '') + ' ' + symbols
def set_link_libs(self, libs, lib_dir='.\\lib'):
if self.use_gcc:
# need to add static lib in group so that linker does not throw errors
# http://eli.thegreenplace.net/2013/07/09/library-order-in-static-linking
mist_text = ' -Wl,--start-group'
for sinfo in libs:
lib = os.path.split(sinfo.src)[1]
name, ext = os.path.splitext(lib)
mist_text += ' -l' + name[3:] #remove lib in 'libAAA'
mist_text += ' -Wl,--end-group'
misc_info = self.settings.get('ld_misc')
if misc_info is not None:
tag, default = misc_info
n = self.root.find(tag)
if n is not None:
m = n.find('.//Misc')
if m is not None:
m.text += mist_text
m = n.find('.//IncludeDir')
if m is not None:
m.text = lib_dir
def set_mcu(self, mcu):
#TODO:
pass
def set_core(self, core):
#TODO:
pass
class UVisionARMCCProject(UVisionProject):
"""uVision for ARMCC project class.
Add some specific logics to create source, include and output setting
"""
def __init__(self, proj, out_dir=None):
super(UVisionARMCCProject, self).__init__(proj, UVISION_ARMCC_PRJ_SETTINGS, out_dir)
class UVisionGCCProject(UVisionProject):
"""uVision for GCC project class.
Add some specific logics to create source, include and output setting
"""
def __init__(self, proj, settings=UVISION_GCC_PRJ_SETTINGS, out_dir=None, use_gcc=True):
super(UVisionGCCProject, self).__init__(proj, settings, out_dir, use_gcc)
def get_project_structure(lines):
"""Get project structure from make log file.
Loop through make log to figure the project structure
Args:
lines: A list of line from make log file (make V=1)
Returns:
A dict mapping library/target to its source list
{
'libc.a': [
{'src':/mynuttx/nuttx/libc/string/lib_strcat.c', 'include' : ['.', 'others include', ], 'flags': ''},
{'src':/mynuttx/nuttx/libc/string/lib_memcpy.c', 'include' : ['.', 'others include', ], 'flags': ''},
],
}
Source list is in full path form
Raises:
An error occurred when can't parse lib/target name
"""
group_dict = {}
src_list = []
make_path = ''
src_path = ''
ar_cmd = ''
cc_cmd = ''
for line in lines:
_lp = line[:PREFIX_LEN]
if _lp in COMPILE_PREFIX_LIST:
src_path = os.path.join(make_path, line[PREFIX_LEN:].strip())
cc_cmd = line.strip()
elif _lp in LIB_PREFIX_LIST:
ar_cmd = line.strip()
elif _lp in LINK_PREFIX_LIST:
match = re.search(_lp + r'(\w+)', line)
if match:
target = match.group(1)
if target not in group_dict:
group_dict[target] = []
for src in src_list:
group_dict[target].append(src)
elif MAKE_ENTER_DIR in line: # Get current make directory
match = re.search(r"'(.+)'\n$", line)
if match:
make_path = match.group(1)
elif cc_cmd != '': # Get include dirs and flags
incs = [make_path]
match = re.findall(r'(-I|-isystem) "(.+?)"', line)
if match:
incs += [p[1] for p in match]
# TODO: parse and other compile flags
src_info = SourceInfo(src_path, incs)
src_list.append(src_info)
cc_cmd = ''
src_path = ''
elif ar_cmd != '': #put all compiled files to library source list
match = re.search(r'(\w+?\.a)', line)
if match:
lib_name = match.group(1) # get library name
if lib_name not in group_dict:
group_dict[lib_name] = [] # create empty source info list
lib_objs = re.findall(r'(\w+?)\.o', line) # Get all obj name in libs (without ext)
#print("OBJ in .a: ", lib_objs)
remain_src_list = []
for sinfo in src_list:
obj = os.path.basename(sinfo.src)
obj = os.path.splitext(obj)[0] # Get the obj name (without ext) from source file name
#print("OBJ from file: ", obj)
if obj in lib_objs: # make sure the lib include this obj
group_dict[lib_name].append(sinfo)
#print('Put' + sinfo.src + "to lib: " + lib_name)
else:
remain_src_list.append(sinfo)
#print('Remain' + sinfo.src + " not in lib: " + lib_name)
src_list = remain_src_list
ar_cmd = ""
else:
raise AssertionError("Can't parse lib name ", line)
return group_dict
def dump_project_struct(project_structure):
"""Dump project structure
Print project structure
Args:
A dict mapping library/target to its source list
{
'libc.a': [
{'src':/mynuttx/nuttx/libc/string/lib_strcat.c', 'include' : ['.', 'others include', ], 'flags': ''},
{'src':/mynuttx/nuttx/libc/string/lib_memcpy.c', 'include' : ['.', 'others include', ], 'flags': ''},
],
}
Returns:
Raises:
None
"""
for lib, sinfo_list in project_structure.items():
print(lib)
for sinfo in sinfo_list:
print('\t' + sinfo.src)
IAR_EXPORT = {'main': {'t' : IARProject, 'file' : 'template_nuttx_main.ewp'},
'lib': {'t' : IARProject, 'file' : 'template_nuttx_lib.ewp'},
'workspace': {'t' : IARWorkspace, 'file' : 'template_nuttx.eww'}}
UVISION_ARMCC_EXPORT = {'main': {'t' : UVisionProject, 'file' : 'template_nuttx_main.uvproj'},
'lib': {'t' : UVisionProject, 'file' : 'template_nuttx_lib.uvproj'},
'workspace': {'t' : UVisionWorkspace, 'file' : 'template_nuttx.uvmpw'}}
UVISION_GCC_EXPORT = {'main': {'t' : UVisionGCCProject, 'file' : 'template_nuttx_main.uvproj'},
'lib': {'t' : UVisionGCCProject, 'file' : 'template_nuttx_lib.uvproj'},
'workspace': {'t' : UVisionWorkspace, 'file' : 'template_nuttx.uvmpw'}}
IDE_CONFIG_DICT = {IAR : IAR_EXPORT,
UVISION_GCC : UVISION_GCC_EXPORT,
UVISION_ARMCC : UVISION_ARMCC_EXPORT}
if __name__ == '__main__':
parser = argparse.ArgumentParser(version='1.1')
parser.add_argument('build_log',
help='Log file from make V=1',
type=argparse.FileType('rt'))
parser.add_argument('ide',
choices=[IAR, UVISION_GCC, UVISION_ARMCC],
help="The target IDE: iar, uvision_gcc, (uvision_armcc is experimental)")
parser.add_argument('template_dir',
help='Directory that contains IDEs template projects')
parser.add_argument('-o', '--output',
action='store',
dest='out_dir',
help="Output directory")
parser.add_argument('-d', '--dump',
action='store_true',
dest='dump', default=False,
help="Dump project structure tree")
options = parser.parse_args()
fmake_log = options.build_log
# read log file
lines = fmake_log.readlines()
fmake_log.close()
# get project structure
project = get_project_structure(lines)
if options.dump:
dump_project_struct(project)
templ_dir = options.template_dir
if not os.path.exists(templ_dir):
print(templ_dir + " does not exist")
exit(1)
prj_dir = templ_dir
if options.out_dir is not None:
prj_dir = os.path.abspath(options.out_dir)
try:
if not os.path.exists(prj_dir):
os.makedirs(prj_dir)
except Exception as e:
print("ERR: {0}".format(str(e)))
exit(1)
ide_config = IDE_CONFIG_DICT[options.ide]
xml_file = os.path.join(templ_dir, ide_config['workspace']['file'])
ws_ext = os.path.splitext(xml_file)[1]
ws = IdeProject.factory(ide_config['workspace']['t'], xml_file, prj_dir)
target = {'libs':[], 'sources': []}
# Create nuttx iar library projects
for lib, group_src_list in project.items():
lib_name, lib_ext = os.path.splitext(lib)
if len(group_src_list) < 1:
print(lib_name, group_src_list)
elif lib_ext in LIB_EXTS:
xml_file = os.path.join(templ_dir, ide_config['lib']['file'])
lib_prj = IdeProject.factory(ide_config['lib']['t'], xml_file, prj_dir)
#print lib_name, group_src_list
lib_prj.make_src_nodes(group_src_list)
lib_prj.make_include(group_src_list)
lib_prj.make_output_dir(lib_name)
if lib_name == 'libxx':
lib_prj.add_misc('cxx_misc')
lib_prj.add_define('cxx_def', 'CONFIG_WCHAR_BUILTIN')
else:
lib_prj.add_misc('c_misc')
# save main xml project to file
xml_ext = os.path.splitext(xml_file)[1]
prj_fname = os.path.join(prj_dir, lib_name + xml_ext)
lib_prj.write(prj_fname)
print("Exported " + prj_fname)
# Add library project to workspace
ws.make_file(ws.root, ws.get_relpath(prj_fname))
# Store output library file to ref from main project later
exe_dir = lib_prj.get_output_dir()
lib_fname = os.path.join(prj_dir, lib_name, exe_dir, lib)
target['libs'].append(SourceInfo(lib_fname))
else:
# Save name and source list for main project
target['name'] = lib
target['sources'] = group_src_list
# Create nuttx main project
xml_file = os.path.join(templ_dir, ide_config['main']['file'])
main_prj = IdeProject.factory(ide_config['main']['t'], xml_file, prj_dir)
main_prj.make_src_nodes(target['sources'])
main_prj.make_include(target['sources'])
if main_prj.use_gcc:
target['libs'].append(SourceInfo('libgcc.a')) # need add libgcc in ld
main_prj.set_link_libs(target['libs'])
else:
main_prj.make_src_nodes(target['libs'], group='libs')
main_prj.make_output_dir(target['name'])
# save main xml project to file
xml_ext = os.path.splitext(xml_file)[1]
prj_fname = os.path.join(prj_dir, target['name'] + '_main' + xml_ext)
main_prj.write(prj_fname)
print("Exported " + prj_fname)
# Add main project to workspace
ws.make_file(ws.root, ws.get_relpath(prj_fname))
# Write nuttx workspace
ww_fname = os.path.join(prj_dir, 'nuttx' + ws_ext)
ws.write(ww_fname)
print("Exported " + ww_fname)