1 # Copyright (c) 2013, 2015-2017 ARM Limited
4 # The license below extends only to copyright in the software and shall
5 # not be construed as granting a license to any other intellectual
6 # property including but not limited to intellectual property relating
7 # to a hardware implementation of the functionality of the software
8 # licensed hereunder. You may use the software subject to the license
9 # terms below provided that you ensure that this notice is replicated
10 # unmodified and in its entirety in all distributions of the software,
11 # modified or unmodified, in source code or in binary form.
13 # Copyright (c) 2011 Advanced Micro Devices, Inc.
14 # Copyright (c) 2009 The Hewlett-Packard Development Company
15 # Copyright (c) 2004-2005 The Regents of The University of Michigan
16 # All rights reserved.
18 # Redistribution and use in source and binary forms, with or without
19 # modification, are permitted provided that the following conditions are
20 # met: redistributions of source code must retain the above copyright
21 # notice, this list of conditions and the following disclaimer;
22 # redistributions in binary form must reproduce the above copyright
23 # notice, this list of conditions and the following disclaimer in the
24 # documentation and/or other materials provided with the distribution;
25 # neither the name of the copyright holders nor the names of its
26 # contributors may be used to endorse or promote products derived from
27 # this software without specific prior written permission.
29 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 from __future__
import print_function
47 from gem5_scons
.util
import get_termcap
50 termcap
= get_termcap()
52 def strip_build_path(path
, env
):
55 variant_base
= env
['BUILDROOT'] + os
.path
.sep
56 if path
.startswith(variant_base
):
57 path
= path
[len(variant_base
):]
58 elif path
.startswith(build_base
):
59 path
= path
[len(build_base
):]
62 # Generate a string of the form:
63 # common/path/prefix/src1, src2 -> tgt1, tgt2
64 # to print while building.
65 class Transform(object):
66 # all specific color settings should be here and nowhere else
67 tool_color
= termcap
.Normal
68 pfx_color
= termcap
.Yellow
69 srcs_color
= termcap
.Yellow
+ termcap
.Bold
70 arrow_color
= termcap
.Blue
+ termcap
.Bold
71 tgts_color
= termcap
.Yellow
+ termcap
.Bold
73 def __init__(self
, tool
, max_sources
=99):
74 self
.format
= self
.tool_color
+ (" [%8s] " % tool
) \
75 + self
.pfx_color
+ "%s" \
76 + self
.srcs_color
+ "%s" \
77 + self
.arrow_color
+ " -> " \
78 + self
.tgts_color
+ "%s" \
80 self
.max_sources
= max_sources
82 def __call__(self
, target
, source
, env
, for_signature
=None):
83 # truncate source list according to max_sources param
84 source
= source
[0:self
.max_sources
]
86 return strip_build_path(str(f
), env
)
88 srcs
= list(map(strip
, source
))
91 tgts
= list(map(strip
, target
))
92 # surprisingly, os.path.commonprefix is a dumb char-by-char string
93 # operation that has nothing to do with paths.
94 com_pfx
= os
.path
.commonprefix(srcs
+ tgts
)
95 com_pfx_len
= len(com_pfx
)
97 # do some cleanup and sanity checking on common prefix
98 if com_pfx
[-1] == ".":
99 # prefix matches all but file extension: ok
100 # back up one to change 'foo.cc -> o' to 'foo.cc -> .o'
101 com_pfx
= com_pfx
[0:-1]
102 elif com_pfx
[-1] == "/":
103 # common prefix is directory path: OK
106 src0_len
= len(srcs
[0])
107 tgt0_len
= len(tgts
[0])
108 if src0_len
== com_pfx_len
:
109 # source is a substring of target, OK
111 elif tgt0_len
== com_pfx_len
:
112 # target is a substring of source, need to back up to
113 # avoid empty string on RHS of arrow
114 sep_idx
= com_pfx
.rfind(".")
116 com_pfx
= com_pfx
[0:sep_idx
]
119 elif src0_len
> com_pfx_len
and srcs
[0][com_pfx_len
] == ".":
120 # still splitting at file extension: ok
123 # probably a fluke; ignore it
125 # recalculate length in case com_pfx was modified
126 com_pfx_len
= len(com_pfx
)
128 f
= list(map(lambda s
: s
[com_pfx_len
:], files
))
130 return self
.format
% (com_pfx
, fmt(srcs
), fmt(tgts
))
132 # The width warning and error messages should be wrapped at.
135 # If stdout is not attached to a terminal, default to 80 columns.
136 if not sys
.stdout
.isatty():
139 # This should work in python 3.3 and above.
140 if text_width
is None:
143 text_width
= shutil
.get_terminal_size().columns
147 # This should work if the curses python module is installed.
148 if text_width
is None:
152 _
, text_width
= curses
.initscr().getmaxyx()
158 # If all else fails, default to 80 columns.
159 if text_width
is None:
162 def print_message(prefix
, color
, message
, **kwargs
):
163 prefix_len
= len(prefix
)
164 if text_width
> prefix_len
:
165 wrap_width
= text_width
- prefix_len
166 padding
= ' ' * prefix_len
168 # First split on newlines.
169 lines
= message
.split('\n')
170 # Then wrap each line to the required width.
173 wrapped_lines
.extend(textwrap
.wrap(line
, wrap_width
))
174 # Finally add the prefix and padding on extra lines, and glue it all
176 message
= prefix
+ ('\n' + padding
).join(wrapped_lines
)
178 # We have very small terminal, indent formatting doesn't help.
179 message
= prefix
+ message
180 # Add in terminal escape sequences.
181 message
= color
+ termcap
.Bold
+ message
+ termcap
.Normal
182 # Actually print the message.
183 print(message
, **kwargs
)
187 def summarize_warnings():
190 print(termcap
.Yellow
+ termcap
.Bold
+
191 '*** Summary of Warnings ***' +
193 list(map(print, all_warnings
))
195 def warning(*args
, **kwargs
):
196 message
= ' '.join(args
)
197 printed
= print_message('Warning: ', termcap
.Yellow
, message
, **kwargs
)
198 all_warnings
.append(printed
)
200 def error(*args
, **kwargs
):
201 message
= ' '.join(args
)
202 print_message('Error: ', termcap
.Red
, message
, **kwargs
)
205 __all__
= ['Transform', 'warning', 'error']