1 # -*- coding: utf-8 -*-
3 #-------------------------------------------------------------------------
4 # drawElements Quality Program utilities
5 # --------------------------------------
7 # Copyright 2015 The Android Open Source Project
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
13 # http://www.apache.org/licenses/LICENSE-2.0
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.
21 #-------------------------------------------------------------------------
28 import multiprocessing
34 import dummy_threading as threading
37 def __init__ (self, apiVersion, abiVersion, prebuiltDir):
38 self.apiVersion = apiVersion
39 self.abiVersion = abiVersion
40 self.prebuiltDir = prebuiltDir
43 return "(API: %s, ABI: %s)" % (self.apiVersion, self.abiVersion)
46 return "(API: %s, ABI: %s)" % (self.apiVersion, self.abiVersion)
50 if sys.platform.startswith('linux'):
55 def selectByOS (variants):
56 platform = getPlatform()
57 if platform in variants:
58 return variants[platform]
59 elif 'other' in variants:
60 return variants['other']
62 raise Exception("No configuration for '%s'" % platform)
64 def isExecutable (path):
65 return os.path.isfile(path) and os.access(path, os.X_OK)
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):
76 def isBinaryInPath (binName):
77 return which(binName) != None
79 def selectFirstExistingBinary (filenames):
80 for filename in filenames:
81 if filename != None and isExecutable(filename):
86 def selectFirstExistingDir (paths):
88 if path != None and os.path.isdir(path):
98 return '"%s"' % s.replace('\\', '\\\\').replace('"', '\"').replace('$', '\$').replace('`', '\`')
100 def execute (commandLine):
101 args = shlex.split(commandLine)
102 retcode = subprocess.call(args)
104 raise Exception("Failed to execute '%s', got %d" % (commandLine, retcode))
107 # Make sure previous stdout prints have been written out.
109 retcode = subprocess.call(args)
111 raise Exception("Failed to execute '%s', got %d" % (str(args), retcode))
113 def execArgsInDirectory (args, cwd, linePrefix=""):
115 def readApplyPrefixAndPrint (source, prefix, sink):
117 line = source.readline()
118 if len(line) == 0: # EOF
120 sink.write(prefix + line)
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))
124 stderrJob = threading.Thread(target=readApplyPrefixAndPrint, args=(process.stderr, linePrefix, sys.stderr))
127 retcode = process.wait()
129 raise Exception("Failed to execute '%s', got %d" % (str(args), retcode))
131 def serialApply(f, argsList):
132 for args in argsList:
135 def parallelApply(f, argsList):
140 def applyAndCaptureError (func, args, errorCode):
144 errorCode.error = sys.exc_info()
146 errorCode = ErrorCode()
148 for args in argsList:
149 job = threading.Thread(target=applyAndCaptureError, args=(f, args, errorCode))
157 raise errorCode.error[0], errorCode.error[1], errorCode.error[2]
160 def __init__(self, serial, product, model, device):
162 self.product = product
167 return "%s: {product: %s, model: %s, device: %s}" % (self.serial, self.product, self.model, self.device)
169 def getDevices (adb):
170 proc = subprocess.Popen([adb, 'devices', '-l'], stdout=subprocess.PIPE)
171 (stdout, stderr) = proc.communicate()
173 if proc.returncode != 0:
174 raise Exception("adb devices -l failed, got %d" % proc.returncode)
176 ptrn = re.compile(r'^([a-zA-Z0-9]+)\s+.*product:([^\s]+)\s+model:([^\s]+)\s+device:([^\s]+)')
178 for line in stdout.splitlines()[1:]:
179 if len(line.strip()) == 0:
184 print "WARNING: Failed to parse device info '%s'" % line
187 devices.append(Device(m.group(1), m.group(2), m.group(3), m.group(4)))
191 def getWin32Generator ():
192 if which("jom.exe") != None:
193 return "NMake Makefiles JOM"
195 return "NMake Makefiles"
197 def isNinjaSupported ():
198 return which("ninja") != None
200 def getUnixGenerator ():
201 if isNinjaSupported():
204 return "Unix Makefiles"
206 def getExtraBuildArgs (generator):
207 if generator == "Unix Makefiles":
208 return ["--", "-j%d" % multiprocessing.cpu_count()]
212 NDK_HOST_OS_NAMES = [
221 def getNDKHostOsName (ndkPath):
222 for name in NDK_HOST_OS_NAMES:
223 if os.path.exists(os.path.join(ndkPath, "prebuilt", name)):
226 raise Exception("Couldn't determine NDK host OS")
229 ANDROID_DIR = os.path.realpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), ".."))
231 # Build configuration
233 # 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
239 ANDROID_JAVA_API = "android-22"
240 NATIVE_LIB_NAME = "libdeqp.so"
242 def selectNDKPath ():
244 os.path.expanduser("~/android-ndk-r11"),
245 "C:/android/android-ndk-r11",
246 os.environ.get("ANDROID_NDK_PATH", None), # If not defined, return None
249 ndkPath = selectFirstExistingDir(candidates)
252 raise Exception("None of NDK directory candidates exist: %s. Check ANDROID_NDK_PATH in common.py" % candidates)
256 def noneSafePathJoin (*components):
257 if None in components:
259 return os.path.join(*components)
263 ANDROID_NDK_PATH = selectNDKPath()
264 ANDROID_NDK_HOST_OS = getNDKHostOsName(ANDROID_NDK_PATH)
265 ANDROID_NDK_TOOLCHAIN_VERSION = "r11" # Toolchain file is selected based on this
267 # Native code build settings
268 CMAKE_GENERATOR = selectByOS({
269 'win32': getWin32Generator(),
270 'other': getUnixGenerator()
272 EXTRA_BUILD_ARGS = getExtraBuildArgs(CMAKE_GENERATOR)
275 ANDROID_SDK_PATH = selectFirstExistingDir([
276 os.environ.get("ANDROID_SDK_PATH", None),
277 os.path.expanduser("~/android-sdk-linux"),
278 os.path.expanduser("~/android-sdk-mac_x86"),
279 "C:/android/android-sdk-windows",
281 ANDROID_BIN = selectFirstExistingBinary([
282 noneSafePathJoin(ANDROID_SDK_PATH, "tools", "android"),
283 noneSafePathJoin(ANDROID_SDK_PATH, "tools", "android.bat"),
286 ADB_BIN = selectFirstExistingBinary([
287 which('adb'), # \note Prefer adb in path to avoid version issues on dev machines
288 noneSafePathJoin(ANDROID_SDK_PATH, "platform-tools", "adb"),
289 noneSafePathJoin(ANDROID_SDK_PATH, "platform-tools", "adb.exe"),
291 ZIPALIGN_BIN = selectFirstExistingBinary([
292 noneSafePathJoin(ANDROID_SDK_PATH, "tools", "zipalign"),
293 noneSafePathJoin(ANDROID_SDK_PATH, "tools", "zipalign.exe"),
296 JARSIGNER_BIN = which('jarsigner')
299 ANT_BIN = selectFirstExistingBinary([
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",
307 def makeNameValueTuple (name):
308 return (name, str(eval(name)))
316 "ANDROID_NDK_HOST_OS",
317 "ANDROID_NDK_TOOLCHAIN_VERSION",
327 CONFIG_STRINGS = [makeNameValueTuple(x) for x in CONFIG_VAR_NAMES]