blob: 13fb1fd39d4933f827acde2e454efa9defed96cf [file] [log] [blame]
Jarkko Poyry3c827362014-09-02 11:48:52 +03001# -*- coding: utf-8 -*-
2
Jarkko Pöyry3c77ed42015-01-06 12:54:34 -08003#-------------------------------------------------------------------------
4# drawElements Quality Program utilities
5# --------------------------------------
6#
7# Copyright 2015 The Android Open Source Project
8#
9# Licensed under the Apache License, Version 2.0 (the "License");
10# you may not use this file except in compliance with the License.
11# You may obtain a copy of the License at
12#
13# http://www.apache.org/licenses/LICENSE-2.0
14#
15# Unless required by applicable law or agreed to in writing, software
16# distributed under the License is distributed on an "AS IS" BASIS,
17# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18# See the License for the specific language governing permissions and
19# limitations under the License.
20#
21#-------------------------------------------------------------------------
22
Jarkko Poyry3c827362014-09-02 11:48:52 +030023import os
Pyry Haulos89e04052014-10-20 11:09:56 -070024import re
Jarkko Poyry3c827362014-09-02 11:48:52 +030025import sys
26import shlex
27import subprocess
Pyry Haulos89e04052014-10-20 11:09:56 -070028import multiprocessing
Kalle Raitac9f76742014-11-13 13:00:08 -080029import string
Jarkko Poyry3c827362014-09-02 11:48:52 +030030
Jarkko Pöyry842a87c2014-12-11 18:22:05 -080031try:
32 import threading
33except ImportError:
34 import dummy_threading as threading
35
Jarkko Poyry3c827362014-09-02 11:48:52 +030036class NativeLib:
Jarkko Pöyryb6d32332015-03-09 16:38:57 -070037 def __init__ (self, apiVersion, abiVersion, prebuiltDir):
38 self.apiVersion = apiVersion
39 self.abiVersion = abiVersion
40 self.prebuiltDir = prebuiltDir
Jarkko Poyry3c827362014-09-02 11:48:52 +030041
Kalle Raitac9f76742014-11-13 13:00:08 -080042 def __str__ (self):
43 return "(API: %s, ABI: %s)" % (self.apiVersion, self.abiVersion)
44
45 def __repr__ (self):
46 return "(API: %s, ABI: %s)" % (self.apiVersion, self.abiVersion)
47
48
Jarkko Poyry3c827362014-09-02 11:48:52 +030049def getPlatform ():
50 if sys.platform.startswith('linux'):
51 return 'linux'
52 else:
53 return sys.platform
54
Pyry Haulos89e04052014-10-20 11:09:56 -070055def selectByOS (variants):
Jarkko Poyry3c827362014-09-02 11:48:52 +030056 platform = getPlatform()
57 if platform in variants:
58 return variants[platform]
59 elif 'other' in variants:
60 return variants['other']
61 else:
62 raise Exception("No configuration for '%s'" % platform)
63
64def isExecutable (path):
65 return os.path.isfile(path) and os.access(path, os.X_OK)
66
67def which (binName):
68 for path in os.environ['PATH'].split(os.pathsep):
69 path = path.strip('"')
70 fullPath = os.path.join(path, binName)
71 if isExecutable(fullPath):
72 return fullPath
73
74 return None
75
76def isBinaryInPath (binName):
77 return which(binName) != None
78
Pyry Haulos89e04052014-10-20 11:09:56 -070079def selectFirstExistingBinary (filenames):
80 for filename in filenames:
81 if filename != None and isExecutable(filename):
82 return filename
83
84 return None
85
86def selectFirstExistingDir (paths):
87 for path in paths:
88 if path != None and os.path.isdir(path):
89 return path
90
91 return None
Jarkko Poyry3c827362014-09-02 11:48:52 +030092
93def die (msg):
94 print msg
95 exit(-1)
96
97def shellquote(s):
98 return '"%s"' % s.replace('\\', '\\\\').replace('"', '\"').replace('$', '\$').replace('`', '\`')
99
100def execute (commandLine):
101 args = shlex.split(commandLine)
102 retcode = subprocess.call(args)
103 if retcode != 0:
104 raise Exception("Failed to execute '%s', got %d" % (commandLine, retcode))
105
106def execArgs (args):
Kalle Raitac9f76742014-11-13 13:00:08 -0800107 # Make sure previous stdout prints have been written out.
108 sys.stdout.flush()
Jarkko Poyry3c827362014-09-02 11:48:52 +0300109 retcode = subprocess.call(args)
110 if retcode != 0:
Jarkko Pöyry842a87c2014-12-11 18:22:05 -0800111 raise Exception("Failed to execute '%s', got %d" % (str(args), retcode))
112
Jarkko Pöyryd1ae94f2015-03-12 15:20:47 -0700113def execArgsInDirectory (args, cwd, linePrefix=""):
114
115 def readApplyPrefixAndPrint (source, prefix, sink):
116 while True:
117 line = source.readline()
118 if len(line) == 0: # EOF
119 break;
120 sink.write(prefix + line)
121
122 process = subprocess.Popen(args, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
123 stdoutJob = threading.Thread(target=readApplyPrefixAndPrint, args=(process.stdout, linePrefix, sys.stdout))
Jarkko Pöyrya31fb7a2015-05-19 11:12:01 -0700124 stderrJob = threading.Thread(target=readApplyPrefixAndPrint, args=(process.stderr, linePrefix, sys.stderr))
Jarkko Pöyryd1ae94f2015-03-12 15:20:47 -0700125 stdoutJob.start()
126 stderrJob.start()
Jarkko Pöyry842a87c2014-12-11 18:22:05 -0800127 retcode = process.wait()
128 if retcode != 0:
129 raise Exception("Failed to execute '%s', got %d" % (str(args), retcode))
130
131def serialApply(f, argsList):
132 for args in argsList:
133 f(*args)
134
135def parallelApply(f, argsList):
136 class ErrorCode:
137 def __init__ (self):
138 self.error = None;
139
140 def applyAndCaptureError (func, args, errorCode):
141 try:
142 func(*args)
143 except:
144 errorCode.error = sys.exc_info()
145
146 errorCode = ErrorCode()
147 jobs = []
148 for args in argsList:
149 job = threading.Thread(target=applyAndCaptureError, args=(f, args, errorCode))
150 job.start()
151 jobs.append(job)
152
153 for job in jobs:
154 job.join()
155
156 if errorCode.error:
157 raise errorCode.error[0], errorCode.error[1], errorCode.error[2]
Jarkko Poyry3c827362014-09-02 11:48:52 +0300158
Pyry Haulos89e04052014-10-20 11:09:56 -0700159class Device:
160 def __init__(self, serial, product, model, device):
161 self.serial = serial
162 self.product = product
163 self.model = model
164 self.device = device
Jarkko Poyry3c827362014-09-02 11:48:52 +0300165
Pyry Haulos89e04052014-10-20 11:09:56 -0700166 def __str__ (self):
167 return "%s: {product: %s, model: %s, device: %s}" % (self.serial, self.product, self.model, self.device)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300168
Pyry Haulos89e04052014-10-20 11:09:56 -0700169def getDevices (adb):
170 proc = subprocess.Popen([adb, 'devices', '-l'], stdout=subprocess.PIPE)
171 (stdout, stderr) = proc.communicate()
172
173 if proc.returncode != 0:
Jarkko Pöyry842a87c2014-12-11 18:22:05 -0800174 raise Exception("adb devices -l failed, got %d" % proc.returncode)
Pyry Haulos89e04052014-10-20 11:09:56 -0700175
Nicolas Boichatdbf97152016-11-30 12:14:52 +0800176 ptrn = re.compile(r'^([a-zA-Z0-9\.:]+)\s+.*product:([^\s]+)\s+model:([^\s]+)\s+device:([^\s]+)')
Pyry Haulos89e04052014-10-20 11:09:56 -0700177 devices = []
178 for line in stdout.splitlines()[1:]:
179 if len(line.strip()) == 0:
180 continue
181
182 m = ptrn.match(line)
183 if m == None:
Pyry Haulosa78b6612014-11-10 10:17:16 -0800184 print "WARNING: Failed to parse device info '%s'" % line
185 continue
Pyry Haulos89e04052014-10-20 11:09:56 -0700186
187 devices.append(Device(m.group(1), m.group(2), m.group(3), m.group(4)))
188
189 return devices
Jarkko Poyry3c827362014-09-02 11:48:52 +0300190
191def getWin32Generator ():
192 if which("jom.exe") != None:
193 return "NMake Makefiles JOM"
194 else:
195 return "NMake Makefiles"
196
Pyry Haulos89e04052014-10-20 11:09:56 -0700197def isNinjaSupported ():
198 return which("ninja") != None
199
200def getUnixGenerator ():
201 if isNinjaSupported():
202 return "Ninja"
203 else:
204 return "Unix Makefiles"
205
206def getExtraBuildArgs (generator):
207 if generator == "Unix Makefiles":
208 return ["--", "-j%d" % multiprocessing.cpu_count()]
209 else:
210 return []
211
212NDK_HOST_OS_NAMES = [
213 "windows",
Maciej Jesionowski993a2802016-01-04 10:45:10 +0100214 "windows-x86_64",
Pyry Haulos89e04052014-10-20 11:09:56 -0700215 "darwin-x86",
Jesse Hallc198d022015-10-15 19:44:21 -0700216 "darwin-x86_64",
Pyry Haulos89e04052014-10-20 11:09:56 -0700217 "linux-x86",
218 "linux-x86_64"
219]
220
221def getNDKHostOsName (ndkPath):
222 for name in NDK_HOST_OS_NAMES:
223 if os.path.exists(os.path.join(ndkPath, "prebuilt", name)):
224 return name
225
226 raise Exception("Couldn't determine NDK host OS")
227
228# deqp/android path
229ANDROID_DIR = os.path.realpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
230
231# Build configuration
232NATIVE_LIBS = [
Jarkko Pöyryb6d32332015-03-09 16:38:57 -0700233 # API ABI prebuiltsDir
234 NativeLib(13, "armeabi-v7a", 'android-arm'), # ARM v7a ABI
235 NativeLib(13, "x86", 'android-x86'), # x86
236 NativeLib(21, "arm64-v8a", 'android-arm64'), # ARM64 v8a ABI
Pyry Haulos89e04052014-10-20 11:09:56 -0700237 ]
Jarkko Pöyryb6d32332015-03-09 16:38:57 -0700238
Daniel Kochd290dcd2015-09-24 23:20:40 -0400239ANDROID_JAVA_API = "android-22"
Pyry Haulos03700a82014-10-20 13:01:20 -0700240NATIVE_LIB_NAME = "libdeqp.so"
Pyry Haulos89e04052014-10-20 11:09:56 -0700241
Kalle Raitac9f76742014-11-13 13:00:08 -0800242def selectNDKPath ():
243 candidates = [
Pyry Haulosde7fb142016-03-15 13:47:53 -0700244 os.path.expanduser("~/android-ndk-r11"),
245 "C:/android/android-ndk-r11",
Kalle Raitafee3a5f2014-11-17 10:40:26 -0800246 os.environ.get("ANDROID_NDK_PATH", None), # If not defined, return None
Kalle Raitac9f76742014-11-13 13:00:08 -0800247 ]
248
249 ndkPath = selectFirstExistingDir(candidates)
250
251 if ndkPath == None:
252 raise Exception("None of NDK directory candidates exist: %s. Check ANDROID_NDK_PATH in common.py" % candidates)
253
254 return ndkPath
255
Kalle Raitafee3a5f2014-11-17 10:40:26 -0800256def noneSafePathJoin (*components):
257 if None in components:
258 return None
259 return os.path.join(*components)
260
261
Kalle Raitac9f76742014-11-13 13:00:08 -0800262# NDK paths
263ANDROID_NDK_PATH = selectNDKPath()
Pyry Haulos89e04052014-10-20 11:09:56 -0700264ANDROID_NDK_HOST_OS = getNDKHostOsName(ANDROID_NDK_PATH)
Pyry Haulosde7fb142016-03-15 13:47:53 -0700265ANDROID_NDK_TOOLCHAIN_VERSION = "r11" # Toolchain file is selected based on this
Pyry Haulos89e04052014-10-20 11:09:56 -0700266
Jarkko Poyry3c827362014-09-02 11:48:52 +0300267# Native code build settings
Pyry Haulos89e04052014-10-20 11:09:56 -0700268CMAKE_GENERATOR = selectByOS({
Jarkko Poyry3c827362014-09-02 11:48:52 +0300269 'win32': getWin32Generator(),
Pyry Haulos89e04052014-10-20 11:09:56 -0700270 'other': getUnixGenerator()
Jarkko Poyry3c827362014-09-02 11:48:52 +0300271 })
Pyry Haulos89e04052014-10-20 11:09:56 -0700272EXTRA_BUILD_ARGS = getExtraBuildArgs(CMAKE_GENERATOR)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300273
274# SDK paths
Pyry Haulos89e04052014-10-20 11:09:56 -0700275ANDROID_SDK_PATH = selectFirstExistingDir([
Jesse Hallc198d022015-10-15 19:44:21 -0700276 os.environ.get("ANDROID_SDK_PATH", None),
Pyry Haulos89e04052014-10-20 11:09:56 -0700277 os.path.expanduser("~/android-sdk-linux"),
278 os.path.expanduser("~/android-sdk-mac_x86"),
279 "C:/android/android-sdk-windows",
280 ])
281ANDROID_BIN = selectFirstExistingBinary([
Kalle Raitafee3a5f2014-11-17 10:40:26 -0800282 noneSafePathJoin(ANDROID_SDK_PATH, "tools", "android"),
283 noneSafePathJoin(ANDROID_SDK_PATH, "tools", "android.bat"),
Pyry Haulos89e04052014-10-20 11:09:56 -0700284 which('android'),
285 ])
286ADB_BIN = selectFirstExistingBinary([
287 which('adb'), # \note Prefer adb in path to avoid version issues on dev machines
Kalle Raitafee3a5f2014-11-17 10:40:26 -0800288 noneSafePathJoin(ANDROID_SDK_PATH, "platform-tools", "adb"),
289 noneSafePathJoin(ANDROID_SDK_PATH, "platform-tools", "adb.exe"),
Pyry Haulos89e04052014-10-20 11:09:56 -0700290 ])
291ZIPALIGN_BIN = selectFirstExistingBinary([
Kalle Raitafee3a5f2014-11-17 10:40:26 -0800292 noneSafePathJoin(ANDROID_SDK_PATH, "tools", "zipalign"),
293 noneSafePathJoin(ANDROID_SDK_PATH, "tools", "zipalign.exe"),
Pyry Haulos89e04052014-10-20 11:09:56 -0700294 which('zipalign'),
295 ])
296JARSIGNER_BIN = which('jarsigner')
Jarkko Poyry3c827362014-09-02 11:48:52 +0300297
298# Apache ant
Pyry Haulos89e04052014-10-20 11:09:56 -0700299ANT_BIN = selectFirstExistingBinary([
300 which('ant'),
301 "C:/android/apache-ant-1.8.4/bin/ant.bat",
302 "C:/android/apache-ant-1.9.2/bin/ant.bat",
303 "C:/android/apache-ant-1.9.3/bin/ant.bat",
304 "C:/android/apache-ant-1.9.4/bin/ant.bat",
305 ])
Kalle Raitac9f76742014-11-13 13:00:08 -0800306
307def makeNameValueTuple (name):
308 return (name, str(eval(name)))
309
Pyry Haulos6b1f7dc2014-11-17 09:37:44 -0800310CONFIG_VAR_NAMES = [
311 "ANDROID_DIR",
312 "NATIVE_LIBS",
313 "ANDROID_JAVA_API",
314 "NATIVE_LIB_NAME",
315 "ANDROID_NDK_PATH",
316 "ANDROID_NDK_HOST_OS",
317 "ANDROID_NDK_TOOLCHAIN_VERSION",
318 "CMAKE_GENERATOR",
319 "EXTRA_BUILD_ARGS",
320 "ANDROID_SDK_PATH",
321 "ANDROID_BIN",
322 "ADB_BIN",
323 "ZIPALIGN_BIN",
324 "JARSIGNER_BIN",
325 "ANT_BIN",
Kalle Raitac9f76742014-11-13 13:00:08 -0800326 ]
Pyry Haulos6b1f7dc2014-11-17 09:37:44 -0800327CONFIG_STRINGS = [makeNameValueTuple(x) for x in CONFIG_VAR_NAMES]