mirror of
https://github.com/ArduPilot/ardupilot
synced 2025-01-03 06:28:27 -04:00
waf: build_summary: add Waf tool
This commit is contained in:
parent
afcabda21c
commit
4f3af94c57
226
Tools/ardupilotwaf/build_summary.py
Normal file
226
Tools/ardupilotwaf/build_summary.py
Normal file
@ -0,0 +1,226 @@
|
||||
#!/usr/bin/env python
|
||||
# encoding: utf-8
|
||||
|
||||
# Copyright (C) 2016 Intel Corporation. All rights reserved.
|
||||
#
|
||||
# This file 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This file 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, see <http://www.gnu.org/licenses/>.
|
||||
'''
|
||||
Waf tool for printing build summary. To be used, this must be loaded in the
|
||||
options(), configure() and build() functions.
|
||||
|
||||
This tool expects toolchain tool to be already loaded.
|
||||
|
||||
The environment variable BUILD_SUMMARY_HEADER can be used to change the default
|
||||
header for the targets' summary table.
|
||||
|
||||
Extra information can be printed by creating assigning a function to
|
||||
bld.extra_build_summary. That function must receive bld as the first argument
|
||||
and this module as the second one.
|
||||
|
||||
If one target's task generator (tg) doesn't have a link_task or places the ELF
|
||||
file at a place different from link_task.outputs[0], then
|
||||
tg.build_summary['binary'] should be set as the Node object or a path relative
|
||||
to bld.bldnode for the binary file. Otherwise, size information won't be
|
||||
printed for that target.
|
||||
'''
|
||||
import sys
|
||||
|
||||
from waflib import Context, Logs, Node
|
||||
from waflib.Configure import conf
|
||||
from waflib.TaskGen import before_method, feature
|
||||
|
||||
MAX_TARGETS = 20
|
||||
|
||||
header_text = {
|
||||
'target': 'Target',
|
||||
'binary_path': 'Binary',
|
||||
'size_text': 'Text',
|
||||
'size_data': 'Data',
|
||||
'size_bss': 'BSS',
|
||||
'size_total': 'Total',
|
||||
}
|
||||
|
||||
def text(label, text=''):
|
||||
text = text.strip()
|
||||
if text:
|
||||
Logs.info('%s%s%s%s%s' % (
|
||||
Logs.colors.NORMAL,
|
||||
Logs.colors.BOLD,
|
||||
label,
|
||||
Logs.colors.NORMAL,
|
||||
text))
|
||||
else:
|
||||
Logs.info('%s%s%s' % (
|
||||
Logs.colors.NORMAL,
|
||||
Logs.colors.BOLD,
|
||||
label
|
||||
))
|
||||
|
||||
def print_table(summary_data_list, header):
|
||||
max_widths = []
|
||||
table = [[] for _ in range(len(summary_data_list))]
|
||||
|
||||
header_row = []
|
||||
for h in header:
|
||||
txt = header_text.get(h, h)
|
||||
header_row.append(txt)
|
||||
max_width = len(txt)
|
||||
for i, row_data in enumerate(summary_data_list):
|
||||
txt = str(row_data.get(h, '-'))
|
||||
table[i].append(txt)
|
||||
|
||||
w = len(txt)
|
||||
if w > max_width:
|
||||
max_width = w
|
||||
max_widths.append(max_width)
|
||||
|
||||
sep = ' '
|
||||
fmts = ['{:<%d}' % w for w in max_widths]
|
||||
header_row = sep.join(fmts).format(*header_row)
|
||||
text(header_row)
|
||||
|
||||
line = ('-' * len(sep)).join('-' * w for w in max_widths)
|
||||
print(line)
|
||||
|
||||
for row in table:
|
||||
fmts = []
|
||||
for j, v in enumerate(row):
|
||||
w = max_widths[j]
|
||||
try:
|
||||
float(v)
|
||||
except ValueError:
|
||||
fmts.append('{:<%d}' % w)
|
||||
else:
|
||||
fmts.append('{:>%d}' % w)
|
||||
row = sep.join(fmts).format(*row)
|
||||
print(row)
|
||||
|
||||
def _build_summary(bld):
|
||||
Logs.info('')
|
||||
text('BUILD SUMMARY')
|
||||
text('Build directory: ', bld.bldnode.abspath())
|
||||
|
||||
targets_suppressed = False
|
||||
if bld.targets == '*':
|
||||
taskgens = bld.get_all_task_gen()
|
||||
if len(taskgens) > MAX_TARGETS and not bld.options.summary_all:
|
||||
targets_suppressed = True
|
||||
taskgens = taskgens[:MAX_TARGETS]
|
||||
else:
|
||||
targets = bld.targets.split(',')
|
||||
if len(targets) > MAX_TARGETS and not bld.options.summary_all:
|
||||
targets_suppressed = True
|
||||
targets = targets[:MAX_TARGETS]
|
||||
taskgens = [bld.get_tgen_by_name(t) for t in targets]
|
||||
|
||||
nodes = []
|
||||
filtered_taskgens = []
|
||||
for tg in taskgens:
|
||||
if not hasattr(tg, 'build_summary'):
|
||||
tg.init_summary_data()
|
||||
|
||||
n = tg.build_summary.get('binary', None)
|
||||
if not n:
|
||||
t = getattr(tg, 'link_task', None)
|
||||
if not t:
|
||||
continue
|
||||
n = t.outputs[0]
|
||||
tg.build_summary['binary'] = n
|
||||
|
||||
nodes.append(n)
|
||||
filtered_taskgens.append(tg)
|
||||
taskgens = filtered_taskgens
|
||||
|
||||
l = bld.size_summary(nodes)
|
||||
for i, data in enumerate(l):
|
||||
taskgens[i].build_summary.update(data)
|
||||
|
||||
summary_data_list = [tg.build_summary for tg in taskgens]
|
||||
print_table(summary_data_list, bld.env.BUILD_SUMMARY_HEADER)
|
||||
|
||||
if targets_suppressed:
|
||||
Logs.info('')
|
||||
Logs.pprint(
|
||||
'NORMAL',
|
||||
'Note: Some targets were suppressed. Use --summary-all if you ' +
|
||||
'want information of all targets.',
|
||||
)
|
||||
|
||||
if hasattr(bld, 'extra_build_summary'):
|
||||
bld.extra_build_summary(bld, sys.modules[__name__])
|
||||
|
||||
def _parse_size_output(s):
|
||||
lines = s.splitlines()[1:]
|
||||
l = []
|
||||
for line in lines:
|
||||
row = line.strip().split()
|
||||
l.append(dict(
|
||||
size_text=int(row[0]),
|
||||
size_data=int(row[1]),
|
||||
size_bss=int(row[2]),
|
||||
size_total=int(row[3]),
|
||||
))
|
||||
return l
|
||||
|
||||
@conf
|
||||
def size_summary(bld, nodes):
|
||||
l = []
|
||||
for n in nodes:
|
||||
path = n
|
||||
if isinstance(n, Node.Node):
|
||||
path = n.path_from(bld.bldnode)
|
||||
l.append(dict(binary_path=path))
|
||||
|
||||
if bld.env.SIZE:
|
||||
cmd = [bld.env.get_flat('SIZE')] + [d['binary_path'] for d in l]
|
||||
out = bld.cmd_and_log(
|
||||
cmd,
|
||||
cwd=bld.bldnode.abspath(),
|
||||
quiet=Context.BOTH,
|
||||
)
|
||||
parsed = _parse_size_output(out)
|
||||
for i, data in enumerate(parsed):
|
||||
l[i].update(data)
|
||||
|
||||
return l
|
||||
|
||||
@feature('cprogram', 'cxxprogram')
|
||||
@before_method('process_rule')
|
||||
def init_summary_data(self):
|
||||
self.build_summary = dict(target=self.name)
|
||||
|
||||
def options(opt):
|
||||
g = opt.ap_groups['build']
|
||||
|
||||
g.add_option('--summary-all',
|
||||
action='store_true',
|
||||
help='''
|
||||
Print build summary for all targets. By default, only information about the
|
||||
first %d targets will be printed.
|
||||
''' % MAX_TARGETS)
|
||||
|
||||
def configure(cfg):
|
||||
cfg.find_toolchain_program('size', mandatory=False)
|
||||
|
||||
if not cfg.env.BUILD_SUMMARY_HEADER:
|
||||
cfg.env.BUILD_SUMMARY_HEADER = [
|
||||
'target',
|
||||
'size_text',
|
||||
'size_data',
|
||||
'size_bss',
|
||||
'size_total',
|
||||
]
|
||||
|
||||
def build(bld):
|
||||
bld.add_post_fun(_build_summary)
|
Loading…
Reference in New Issue
Block a user