1#
2# File      : codelite.py
3# This file is part of RT-Thread RTOS
4# COPYRIGHT (C) 2006 - 2020, 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# 2020-10-14     LiuMin       Add copyright information
23#
24
25import os
26import sys
27import string
28import uuid
29import utils
30from xml.etree.ElementTree import SubElement
31from utils import _make_path_relative
32from utils import xml_indent
33
34# Add parent directory to path to import building
35sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
36import building
37
38import xml.etree.ElementTree as etree
39
40fs_encoding = sys.getfilesystemencoding()
41
42def CLSetCFlags(root, flags):
43    node = root.find('Settings').find('Configuration').find('Compiler')
44    node.attrib['C_Options'] = flags
45
46def CLSetCxxFlags(root, flags):
47    node = root.find('Settings').find('Configuration').find('Compiler')
48    node.attrib['Options'] = flags
49
50def CLSetAsFlags(root, flags):
51    node = root.find('Settings').find('Configuration').find('Compiler')
52    node.attrib['Assembler'] = flags
53
54def CLAddIncludePath(root, path):
55    node = root.find('Settings').find('Configuration').find('Compiler')
56    node = SubElement(node, 'IncludePath')
57    node.attrib['Value'] = path
58
59def CLAddPreprocessor(root, value):
60    node = root.find('Settings').find('Configuration').find('Compiler')
61    node = SubElement(node, 'Preprocessor')
62    node.attrib['Value'] = value
63
64
65def CLSetLdFlags(root, flags):
66    node = root.find('Settings').find('Configuration').find('Linker')
67    node.attrib['Options'] = flags
68
69def CLAddLibrary_path(root, path):
70    node = root.find('Settings').find('Configuration').find('Linker')
71    node = SubElement(node, 'LibraryPath')
72    node.attrib['Value'] = path
73
74def CLAddLibrary(root, lib):
75    node = root.find('Settings').find('Configuration').find('Linker')
76    node = SubElement(node, 'Library')
77    node.attrib['Value'] = lib
78
79def CLAddFile(root, file_path):
80    file_path = file_path.replace('\\', '/')
81
82    dir_list = file_path.split('/')
83    dir_list.pop()
84    if not len(dir_list):
85        dir_list.append(os.path.abspath('.').replace('\\', '/').split('/')[-1])
86
87    parent = root
88    for dir_name in dir_list:
89        if dir_name == '..':
90            continue
91
92        node = None
93        nodes = parent.findall('VirtualDirectory')
94        for iter in nodes:
95            if iter.attrib['Name'] == dir_name:
96                node = iter
97                break
98        if node is None:
99            node = SubElement(parent, 'VirtualDirectory')
100            node.attrib['Name'] = dir_name
101        parent = node
102
103    if parent != root:
104        node = SubElement(parent, 'File')
105        node.attrib['Name'] = file_path
106
107def CLAddHeaderFiles(parent, program, project_path):
108    utils.source_ext = []
109    utils.source_ext = ["h"]
110    for item in program:
111        utils.walk_children(item)
112    utils.source_list.sort()
113
114    for f in utils.source_list:
115        path = _make_path_relative(project_path, f)
116        CLAddFile(parent, path)
117
118def CLAddCFiles(parent, files, project_path):
119    for f in files:
120        fn = f.rfile()
121        name = fn.name
122        path = os.path.dirname(fn.abspath)
123
124        path = _make_path_relative(project_path, path)
125        path = os.path.join(path, name)
126        CLAddFile(parent, path)
127
128
129
130def CLGenWorkspace(project_name, project_path):
131    if os.path.isfile('codelite_template.workspace'):
132        tree = etree.parse('codelite_template.workspace')
133    else:
134        tree = etree.parse(os.path.join(os.path.dirname(__file__), 'codelite_template.workspace'))
135
136    root = tree.getroot()
137    root.attrib['Name'] = project_name
138
139    node = root.find('Project')
140    node.attrib['Name'] = project_name
141    node.attrib['Path'] = project_name + '.project'
142
143    node = root.find('BuildMatrix').find('WorkspaceConfiguration').find('Project')
144    node.attrib['Name'] = project_name
145
146    out = open(project_name + '.workspace', 'w')
147    out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
148    xml_indent(root)
149    out.write(etree.tostring(root, encoding='utf-8'))
150    out.close()
151
152def TargetCodelite(script, program):
153    project_name = os.path.abspath('.').replace('\\', '/').split('/')[-1]
154    #project_name.replace('-', '_')
155    project_path = os.path.abspath('.')
156    CLGenWorkspace(project_name, project_path)
157
158    if os.path.isfile('codelite_template.project'):
159        tree = etree.parse('codelite_template.project')
160    else:
161        tree = etree.parse(os.path.join(os.path.dirname(__file__), 'codelite_template.project'))
162
163    root = tree.getroot()
164    root.attrib['Name'] = project_name
165
166    out = open(project_name + '.project', 'w')
167    out.write('<?xml version="1.0" encoding="UTF-8"?>\n')
168
169    # add files
170    for group in script:
171        CLAddCFiles(root, group['src'], project_path)
172    # add header file
173    CLAddHeaderFiles(root, program, project_path)
174
175    # SECTION 2.
176    # write head include path
177
178    if 'CPPPATH' in building.Env:
179        cpp_path = building.Env['CPPPATH']
180        paths  = set()
181        for path in cpp_path:
182            inc = _make_path_relative(project_path, os.path.normpath(path))
183            paths.add(inc) #.replace('\\', '/')
184
185        paths = [i for i in paths]
186        paths.sort()
187
188        # write include path, definitions
189        for elem in tree.iter(tag='Compiler'):
190            break
191
192        for path in paths:
193            CLAddIncludePath(root, path)
194
195
196        #print building.Env.get('LIBPATH', [])
197        #print building.Env.get('LIBS', [])
198
199        CLSetCFlags(root, building.Env.get('CFLAGS', []))
200        CLSetCxxFlags(root, building.Env.get('CFLAGS', []))
201
202        asflags = building.Env.get('ASFLAGS', [])
203        asflags = asflags.replace('-ffunction-sections', '')
204        asflags = asflags.replace('-fdata-sections', '')
205        asflags = asflags.replace('-x', '')
206        asflags = asflags.replace('-Wa,', '')
207        asflags = asflags.replace('assembler-with-cpp', '')
208        CLSetAsFlags(root, asflags)
209        CLSetLdFlags(root, building.Env.get('LINKFLAGS', []))
210
211        for macro in building.Env.get('CPPDEFINES', []):
212            for d in macro:
213                CLAddPreprocessor(root, d)
214
215    xml_indent(root)
216    out.write(etree.tostring(root, encoding='utf-8'))
217    out.close()
218