Compute source folders exclusions.

pull/3561/head
Liviu Ionescu 2017-01-12 18:10:56 +02:00
parent e717c781b0
commit 9e84338178
3 changed files with 190 additions and 14 deletions

View File

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<?fileVersion 4.0.0?>
<!-- Generated by the GNU ARM Eclipse exporter from an mBed project. -->
<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<cconfiguration id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.{{debug_config_uid}}">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.{{debug_config_uid}}" moduleId="org.eclipse.cdt.core.settings" name="Debug">
@ -156,7 +158,7 @@
</toolChain>
</folderInfo>
<sourceEntries>
<entry excluding="mbed-os" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
<entry excluding="{{excluded_folders}}" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
</sourceEntries>
</configuration>
</storageModule>
@ -313,7 +315,7 @@
</toolChain>
</folderInfo>
<sourceEntries>
<entry excluding="mbed-os" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
<entry excluding="{{excluded_folders}}" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name=""/>
</sourceEntries>
</configuration>
</storageModule>

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated by the GNU ARM Eclipse exporter from an mBed project. -->
<projectDescription>
<name>{{name}}</name>
<comment>This file was automagically generated by mbed.org. For more information, see http://mbed.org/handbook/Exporting-To-GNU-ARM-Eclipse</comment>

View File

@ -13,22 +13,38 @@ distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Title: GNU ARM Eclipse (http://gnuarmeclipse.github.io) exporter.
Description: Creates a managed build project that can be imported by
the GNU ARM Eclipse plug-ins.
Author: Liviu Ionescu <ilg@livius.net>
"""
from tools.export.exporters import Exporter
from os.path import splitext, basename, relpath
from os.path import splitext, basename, relpath, dirname
from random import randint
import os
import copy
from tools.targets import TARGET_MAP
from tools.utils import NotSupportedException
class UID:
"""
Helper class, used to generate unique ids required by .cproject symbols.
"""
@property
def id(self):
return "%0.9u" % randint(0, 999999999)
# Global UID generator instance.
# Passed to the template engine, and referred as {{u.id}}.
# Each invocation generates a new number.
u = UID()
class GNUARMEclipse(Exporter):
NAME = 'GNU ARM Eclipse'
TOOLCHAIN = 'GCC_ARM'
@ -39,6 +55,9 @@ class GNUARMEclipse(Exporter):
@staticmethod
def filter_dot(s):
"""
Remove the './' prefix, if present.
"""
if s == None:
return None
if s[:2] == './':
@ -54,6 +73,9 @@ class GNUARMEclipse(Exporter):
ld_flags - linker flags
asm_flags - assembler flags
common_flags - common options
The difference from the parent function is that it does not
add macro definitions, since they are passed separately.
"""
config_header = self.toolchain.get_config_header()
flags = {key + "_flags": copy.deepcopy(value) for key, value
@ -66,9 +88,129 @@ class GNUARMEclipse(Exporter):
config_header)
return flags
def dump_tree(self, node, depth=0):
for k in node.keys():
n = node[k]
pn = n['parent']['name'] if 'parent' in n.keys() else ''
print ' ' * depth, n['name'], n['is_used'], pn
if len(n['children'].keys()) != 0:
self.dump_tree(n['children'], depth + 1)
def dump_paths(self, node, depth=0):
for k in node.keys():
n = node[k]
x = []
ni = n
while True:
x.insert(0, ni['name'])
if 'parent' not in ni:
break
ni = ni['parent']
path = '/'.join(x)
print path, n['is_used']
self.dump_paths(n['children'], depth + 1)
def recurse_excludings(self, node):
"""
Recurse the tree and collect all unused folders; descend
the hierarchy only for used nodes.
"""
for k in node.keys():
n = node[k]
if n['is_used'] == False:
x = []
ni = n
while True:
x.insert(0, ni['name'])
if 'parent' not in ni:
break
ni = ni['parent']
path = '/'.join(x)
# print path
self.excluded_folders.append(path)
else:
self.recurse_excludings(n['children'])
def add_source_folder_to_tree(self, path, is_used=False):
"""
Decompose a path in an array of folder names and create the tree.
On the second pass the nodes should be already there; mark them
as used.
"""
# print path, is_used
a = path.split(os.sep)
n = self.source_tree
p = None
for s in a:
if s[0] == '.':
continue
if s not in n.keys():
nn = {}
nn['name'] = s
nn['children'] = {}
if p != None:
nn['parent'] = p
n[s] = nn
n[s]['is_used'] = is_used
p = n[s]
n = n[s]['children']
def compute_exclusions(self):
"""
With the project root as the only source folder known to CDT,
based on the list of source files, compute the folders to not
be included in the build.
The steps are:
- get the list of source folders, as dirname(source_file)
- compute the top folders (subfolders of the project folders)
- iterate all subfolders and add them to a tree, with all
nodes markes as 'not used'
- iterate the source folders and mark them as 'used' in the
tree, including all intermediate nodes
- recurse the tree and collect all unused folders; descend
the hierarchy only for used nodes
"""
source_folders = [self.filter_dot(s) for s in set(dirname(
src) for src in self.resources.c_sources + self.resources.cpp_sources + self.resources.s_sources)]
source_folders.remove('.')
# print 'source folders'
# print source_folders
top_folders = [f for f in set(s.split(os.sep)[0]
for s in source_folders)]
# print 'top folders'
# print top_folders
self.source_tree = {}
for top_folder in top_folders:
for root, dirs, files in os.walk(top_folder):
if len(dirs) == 0:
self.add_source_folder_to_tree(root)
for folder in source_folders:
self.add_source_folder_to_tree(folder, True)
# print
# print self.source_tree
# self.dump_paths(self.source_tree)
# print 'excludings'
self.excluded_folders = []
self.recurse_excludings(self.source_tree)
def generate(self):
"""
Override the parent method with code generation.
"""
if not self.resources.linker_script:
raise NotSupportedException("No linker script found.")
# TODO: Check if this is needed.
# self.resources.win_to_unix()
libraries = []
print self.resources.libraries
for lib in self.resources.libraries:
l, _ = splitext(basename(lib))
libraries.append(l[3:])
@ -88,7 +230,7 @@ class GNUARMEclipse(Exporter):
core = self.toolchain.target.core
try:
# cortex-m0, cortex-m0-small-multiply, cortex-m0plus,
# cortex-m0, cortex-m0-small-multiply, cortex-m0plus,
# cortex-m0plus-small-multiply, cortex-m1, cortex-m1-small-multiply,
# cortex-m3, cortex-m4, cortex-m7.
target_mcpu = MCPUS[core]['mcpu']
@ -101,16 +243,21 @@ class GNUARMEclipse(Exporter):
if target_fpu_unit != None:
target_fpu_abi = 'hard'
except AttributeError:
# TODO filter out projects with toolchain core not supported,
# instead of raising an exception.
raise NotSupportedException('Target core {0} not supported.'.format(core))
raise NotSupportedException(
'Target core {0} not supported.'.format(core))
# TODO: clarify how to use objects; enabling this adds another
# object 'main.o'.
objects = [] # self.resources.objects
print self.resources.objects
# TODO: get the list from existing .cproject
build_folders = ['Debug', 'Release']
objects = [self.filter_dot(s) for s in self.resources.objects]
for bf in build_folders:
objects = [o for o in objects if not o.startswith(bf + '/')]
print 'objects'
print objects
f = self.flags
print 'common_flags'
@ -124,10 +271,16 @@ class GNUARMEclipse(Exporter):
print 'ld_flags'
print f['ld_flags']
source_folders = [self.filter_dot(s) for s in set(dirname(
src) for src in self.resources.c_sources + self.resources.cpp_sources + self.resources.s_sources)]
source_folders.remove('.')
self.compute_exclusions()
asm_defines = self.toolchain.get_symbols(True)
c_defines = self.toolchain.get_symbols()
cpp_defines = self.toolchain.get_symbols()
include_paths = [self.filter_dot(s) for s in self.resources.inc_dirs]
library_paths = [self.filter_dot(s) for s in self.resources.lib_dirs]
@ -136,6 +289,7 @@ class GNUARMEclipse(Exporter):
ctx = {
'name': self.project_name,
'excluded_folders': '|'.join(self.excluded_folders),
'include_paths': include_paths,
'library_paths': library_paths,
'object_files': objects,
@ -166,7 +320,26 @@ class GNUARMEclipse(Exporter):
'u': u,
}
# ctx.update(f)
self.gen_file('gnuarmeclipse/.project.tmpl', ctx, '.project')
self.gen_file('gnuarmeclipse/.cproject.tmpl', ctx, '.cproject')
@staticmethod
def build(project_name, log_name="build_log.txt", cleanup=True):
"""
Build GNU ARM Eclipse project.
"""
ret_code = 0
# TODO: add code to run the build in a headless configuration.
# Cleanup the exported and built files
if cleanup:
os.remove('.project')
os.remove('.cproject')
if ret_code !=0:
# Seems like something went wrong.
return -1
else:
return 0