blob: 2c11213684c5befa2ea6f8b093a127d633982be4 [file] [log] [blame]
Alexandre Ramesb78f1392016-07-01 14:22:22 +01001# Copyright 2015, VIXL authors
armvixlad96eda2013-06-14 11:42:37 +01002# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are met:
6#
7# * Redistributions of source code must retain the above copyright notice,
8# this list of conditions and the following disclaimer.
9# * Redistributions in binary form must reproduce the above copyright notice,
10# this list of conditions and the following disclaimer in the documentation
11# and/or other materials provided with the distribution.
12# * Neither the name of ARM Limited nor the names of its contributors may be
13# used to endorse or promote products derived from this software without
14# specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
Pierre Langloisf737e0a2016-11-02 13:08:11 +000027from distutils.version import LooseVersion
armvixldb644342015-07-21 11:37:10 +010028import glob
Pierre Langloisf737e0a2016-11-02 13:08:11 +000029import operator
armvixl6e2c8272015-03-31 11:04:14 +010030import os
armvixlad96eda2013-06-14 11:42:37 +010031import re
armvixldb644342015-07-21 11:37:10 +010032import shlex
33import subprocess
34import sys
35
36
37def ListCCFilesWithoutExt(path):
38 return map(lambda x : os.path.splitext(os.path.basename(x))[0],
39 glob.glob(os.path.join(path, '*.cc')))
armvixlad96eda2013-06-14 11:42:37 +010040
41
42def abort(message):
43 print('ABORTING: ' + message)
44 sys.exit(1)
45
46
47# Emulate python3 subprocess.getstatusoutput.
armvixldb644342015-07-21 11:37:10 +010048def getstatusoutput(command, shell=False):
armvixlad96eda2013-06-14 11:42:37 +010049 try:
50 args = shlex.split(command)
armvixldb644342015-07-21 11:37:10 +010051 output = subprocess.check_output(args, stderr=subprocess.STDOUT, shell=shell)
armvixlad96eda2013-06-14 11:42:37 +010052 return 0, output.rstrip('\n')
53 except subprocess.CalledProcessError as e:
54 return e.returncode, e.output.rstrip('\n')
55
56
armvixl0f35e362016-05-10 13:57:58 +010057def IsCommandAvailable(command):
58 retcode, unused_output = getstatusoutput('which %s' % command)
59 return retcode == 0
60
61
armvixldb644342015-07-21 11:37:10 +010062def ensure_dir(path_name):
63 if not os.path.exists(path_name):
64 os.makedirs(path_name)
armvixl6e2c8272015-03-31 11:04:14 +010065
66
armvixldb644342015-07-21 11:37:10 +010067# Check that the specified program is available.
68def require_program(program_name):
69 rc, out = getstatusoutput('which %s' % program_name)
70 if rc != 0:
71 print('ERROR: The required program %s was not found.' % program_name)
72 sys.exit(rc)
Alexandre Rames81c76e62016-07-19 09:53:09 +010073
74def relrealpath(path, start=os.getcwd()):
75 return os.path.relpath(os.path.realpath(path), start)
Pierre Langloisa3b21462016-08-04 16:01:51 +010076
Pierre Langloisf737e0a2016-11-02 13:08:11 +000077# Query the compiler about its preprocessor directives and return all of them as
78# a dictionnary.
79def GetCompilerDirectives(cxx):
Pierre Langloisa3b21462016-08-04 16:01:51 +010080 # Instruct the compiler to dump all its preprocessor macros.
81 dump = subprocess.Popen([cxx, '-E', '-dM', '-'], stdin=subprocess.PIPE,
82 stdout=subprocess.PIPE)
83 out, _ = dump.communicate()
Pierre Langloisf737e0a2016-11-02 13:08:11 +000084 return {
85 # Extract the macro name as key and value as element.
86 match.group(1): match.group(2)
Pierre Langloisa3b21462016-08-04 16:01:51 +010087 for match in [
88 # Capture macro name.
Pierre Langloisf737e0a2016-11-02 13:08:11 +000089 re.search('^#define (\S+?) (.+)$', macro)
Pierre Langloisa3b21462016-08-04 16:01:51 +010090 for macro in out.split('\n')
91 ]
92 # Filter out non-matches.
93 if match
Pierre Langloisf737e0a2016-11-02 13:08:11 +000094 }
95
96# Query the target architecture of the compiler. The 'target' architecture of
97# the compiler used to build VIXL is considered to be the 'host' architecture of
98# VIXL itself.
99def GetHostArch(cxx):
100 directives = GetCompilerDirectives(cxx)
101 if "__x86_64__" in directives:
Pierre Langloisa3b21462016-08-04 16:01:51 +0100102 return "x86_64"
Pierre Langloisf737e0a2016-11-02 13:08:11 +0000103 elif "__arm__" in directives:
Pierre Langloisa3b21462016-08-04 16:01:51 +0100104 return "aarch32"
Pierre Langloisf737e0a2016-11-02 13:08:11 +0000105 elif "__aarch64__" in directives:
Pierre Langloisa3b21462016-08-04 16:01:51 +0100106 return "aarch64"
107 else:
108 raise Exception("Unsupported archtecture")
Pierre Langloisf737e0a2016-11-02 13:08:11 +0000109
110# Class representing the compiler toolchain and version.
111class CompilerInformation(object):
112 def __init__(self, cxx):
113 directives = GetCompilerDirectives(cxx)
114 if '__llvm__' in directives:
115 major = int(directives['__clang_major__'])
116 minor = int(directives['__clang_minor__'])
117 self.compiler = 'clang'
118 self.version = '{}.{}'.format(major, minor)
119 elif '__GNUC__' in directives:
120 major = int(directives['__GNUC__'])
121 minor = int(directives['__GNUC_MINOR__'])
122 self.compiler = 'gcc'
123 self.version = '{}.{}'.format(major, minor)
124 else:
125 # Allow other compilers to be used for building VIXL. However, one would
126 # need to teach this class how to extract version information in order to
127 # make use of it.
128 self.compiler = None
129 self.version = None
130
131 def GetDescription(self):
132 return "{}-{}".format(self.compiler, self.version)
133
134 def __str__(self):
135 return self.GetDescription()
136
137 # Compare string descriptions with our object. The semantics are:
138 #
139 # - Equality
140 #
141 # If the description does not have a version number, then we compare the
142 # compiler names. For instance, "clang-3.6" is still equal to "clang" but of
143 # course is not to "gcc".
144 #
145 # - Ordering
146 #
147 # Asking whether a compiler is lower than another depends on the version
148 # number. What we are really asking here when using these operator is
149 # "Is my compiler in the allowed range?". So with this in mind, comparing
150 # two different compilers will always return false. If the compilers are the
151 # same, then the version numbers are compared. Of course, we cannot use
152 # ordering operators if no version number is provided.
153
154 def __eq__(self, description):
155 if description == self.GetDescription():
156 return True
157 else:
158 # The user may not have provided a version, let's see if it matches the
159 # compiler.
160 return self.compiler == description
161
162 def __ne__(self, description):
163 return not self.__eq__(description)
164
165 def __lt__(self, description):
166 return self.CompareVersion(operator.lt, description)
167
168 def __le__(self, description):
169 return self.CompareVersion(operator.le, description)
170
171 def __ge__(self, description):
172 return self.CompareVersion(operator.ge, description)
173
174 def __gt__(self, description):
175 return self.CompareVersion(operator.gt, description)
176
177 # Comparing the provided `description` string, in the form of
178 # "{compiler}-{major}.{minor}". The comparison is done using the provided
179 # `operator` argument.
180 def CompareVersion(self, operator, description):
181 match = re.search('^(\S+)-(.*?)$', description)
182 if not match:
183 raise Exception("A version number is required when comparing compilers")
184 compiler, version = match.group(1), match.group(2)
185 # The result is false if the compilers are different, otherwise compare the
186 # version numbers.
187 return self.compiler == compiler and \
188 operator(LooseVersion(self.version), LooseVersion(version))