1# -*- coding: utf-8 -*- 2 3#------------------------------------------------------------------------- 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 23import os 24import re 25import sys 26import shutil 27import string 28import argparse 29import time 30 31import common 32 33def getStoreKeyPasswords (filename): 34 f = open(filename) 35 storepass = None 36 keypass = None 37 for line in f: 38 m = re.search('([a-z]+)\s*\=\s*"([^"]+)"', line) 39 if m != None: 40 if m.group(1) == "storepass": 41 storepass = m.group(2) 42 elif m.group(1) == "keypass": 43 keypass = m.group(2) 44 f.close() 45 if storepass == None or keypass == None: 46 common.die("Could not read signing key passwords") 47 return (storepass, keypass) 48 49def getNativeBuildDir (buildRoot, nativeLib, buildType): 50 buildName = "%s-%d-%s" % (buildType.lower(), nativeLib.apiVersion, nativeLib.abiVersion) 51 return os.path.normpath(os.path.join(buildRoot, "native", buildName)) 52 53def getAssetsDir (buildRoot, nativeLib, buildType): 54 return os.path.join(getNativeBuildDir(buildRoot, nativeLib, buildType), "assets") 55 56def buildNative (buildRoot, libTargetDir, nativeLib, buildType): 57 deqpDir = os.path.normpath(os.path.join(common.ANDROID_DIR, "..")) 58 buildDir = getNativeBuildDir(buildRoot, nativeLib, buildType) 59 libsDir = os.path.join(libTargetDir, nativeLib.abiVersion) 60 srcLibFile = os.path.join(buildDir, common.NATIVE_LIB_NAME) 61 dstLibFile = os.path.join(libsDir, common.NATIVE_LIB_NAME) 62 63 # Make build directory if necessary 64 if not os.path.exists(buildDir): 65 os.makedirs(buildDir) 66 toolchainFile = '%s/framework/delibs/cmake/toolchain-android-%s.cmake' % (deqpDir, common.ANDROID_NDK_TOOLCHAIN_VERSION) 67 common.execArgsInDirectory([ 68 'cmake', 69 '-G%s' % common.CMAKE_GENERATOR, 70 '-DCMAKE_TOOLCHAIN_FILE=%s' % toolchainFile, 71 '-DANDROID_NDK_HOST_OS=%s' % common.ANDROID_NDK_HOST_OS, 72 '-DANDROID_NDK_PATH=%s' % common.ANDROID_NDK_PATH, 73 '-DANDROID_ABI=%s' % nativeLib.abiVersion, 74 '-DDE_ANDROID_API=%s' % nativeLib.apiVersion, 75 '-DCMAKE_BUILD_TYPE=%s' % buildType, 76 '-DDEQP_TARGET=android', 77 deqpDir 78 ], buildDir) 79 80 common.execArgsInDirectory(['cmake', '--build', '.'] + common.EXTRA_BUILD_ARGS, buildDir) 81 82 if not os.path.exists(libsDir): 83 os.makedirs(libsDir) 84 85 shutil.copyfile(srcLibFile, dstLibFile) 86 87 # Copy gdbserver for debugging 88 if buildType.lower() == "debug": 89 srcGdbserverPath = os.path.join(common.ANDROID_NDK_PATH, 90 'prebuilt', 91 nativeLib.prebuiltDir, 92 'gdbserver', 93 'gdbserver') 94 dstGdbserverPath = os.path.join(libsDir, 'gdbserver') 95 shutil.copyfile(srcGdbserverPath, dstGdbserverPath) 96 else: 97 assert not os.path.exists(os.path.join(libsDir, "gdbserver")) 98 99def buildApp (buildRoot, androidBuildType, javaApi): 100 appDir = os.path.join(buildRoot, "package") 101 102 # Set up app 103 os.chdir(appDir) 104 105 manifestSrcPath = os.path.normpath(os.path.join(common.ANDROID_DIR, "package", "AndroidManifest.xml")) 106 manifestDstPath = os.path.normpath(os.path.join(appDir, "AndroidManifest.xml")) 107 108 # Build dir can be the Android dir, in which case the copy is not needed. 109 if manifestSrcPath != manifestDstPath: 110 shutil.copy(manifestSrcPath, manifestDstPath) 111 112 common.execArgs([ 113 common.ANDROID_BIN, 114 'update', 'project', 115 '--name', 'dEQP', 116 '--path', '.', 117 '--target', javaApi, 118 ]) 119 120 # Build 121 common.execArgs([ 122 common.ANT_BIN, 123 androidBuildType, 124 "-Dsource.dir=" + os.path.join(common.ANDROID_DIR, "package", "src"), 125 "-Dresource.absolute.dir=" + os.path.join(common.ANDROID_DIR, "package", "res") 126 ]) 127 128def signApp (keystore, keyname, storepass, keypass): 129 os.chdir(os.path.join(common.ANDROID_DIR, "package")) 130 common.execArgs([ 131 common.JARSIGNER_BIN, 132 '-keystore', keystore, 133 '-storepass', storepass, 134 '-keypass', keypass, 135 '-sigfile', 'CERT', 136 '-digestalg', 'SHA1', 137 '-sigalg', 'MD5withRSA', 138 '-signedjar', 'bin/dEQP-unaligned.apk', 139 'bin/dEQP-release-unsigned.apk', 140 keyname 141 ]) 142 common.execArgs([ 143 common.ZIPALIGN_BIN, 144 '-f', '4', 145 'bin/dEQP-unaligned.apk', 146 'bin/dEQP-release.apk' 147 ]) 148 149def build (buildRoot=common.ANDROID_DIR, androidBuildType='debug', nativeBuildType="Release", javaApi=common.ANDROID_JAVA_API, doParallelBuild=False): 150 curDir = os.getcwd() 151 152 try: 153 assetsSrcDir = getAssetsDir(buildRoot, common.NATIVE_LIBS[0], nativeBuildType) 154 assetsDstDir = os.path.join(buildRoot, "package", "assets") 155 156 # Remove assets from the first build dir where we copy assets from 157 # to avoid collecting cruft there. 158 if os.path.exists(assetsSrcDir): 159 shutil.rmtree(assetsSrcDir) 160 if os.path.exists(assetsDstDir): 161 shutil.rmtree(assetsDstDir) 162 163 # Remove old libs dir to avoid collecting out-of-date versions 164 # of libs for ABIs not built this time. 165 libTargetDir = os.path.join(buildRoot, "package", "libs") 166 if os.path.exists(libTargetDir): 167 shutil.rmtree(libTargetDir) 168 169 # Build native code 170 nativeBuildArgs = [(buildRoot, libTargetDir, nativeLib, nativeBuildType) for nativeLib in common.NATIVE_LIBS] 171 if doParallelBuild: 172 common.parallelApply(buildNative, nativeBuildArgs) 173 else: 174 common.serialApply(buildNative, nativeBuildArgs) 175 176 # Copy assets 177 if os.path.exists(assetsSrcDir): 178 shutil.copytree(assetsSrcDir, assetsDstDir) 179 180 # Build java code and .apk 181 buildApp(buildRoot, androidBuildType, javaApi) 182 183 finally: 184 # Restore working dir 185 os.chdir(curDir) 186 187def dumpConfig (): 188 print " " 189 for entry in common.CONFIG_STRINGS: 190 print "%-30s : %s" % (entry[0], entry[1]) 191 print " " 192 193# Return NDK version as [<major>,<minor>] or None if cannot be figured out. 194def getNdkVersion (path): 195 if path == None: 196 return None 197 198 propFilePath = os.path.join(path, "source.properties") 199 try: 200 with open(propFilePath) as propFile: 201 for line in propFile: 202 keyValue = map(lambda x: string.strip(x), line.split("=")) 203 if keyValue[0] == "Pkg.Revision": 204 versionParts = keyValue[1].split(".") 205 return tuple(map(int, versionParts[0:2])) 206 except: 207 print("Could not read source prop file '%s'" % propFilePath) 208 209 return None 210 211def checkConfig (): 212 HOST_OS_TO_DOWNLOAD_STRING = { 213 "linux-x86_64" : "linux-x86_64", 214 "windows" : "windows-x86", 215 "windows-x86_64" : "windows-x86_64" 216 } 217 218 version = getNdkVersion(common.ANDROID_NDK_PATH) 219 # Note: NDK currently maintains compatibility between minor 220 # versions. Error out only on major version mismatch. 221 if version == None or version[0] != common.ANDROID_NDK_VERSION[0]: 222 print("**** WARNING! Deqp requires NDK version %s" % common.ANDROID_NDK_VERSION_STRING) 223 print("**** NDK Path %s does not appear to have that version." % common.ANDROID_NDK_PATH) 224 225 # Download hint will use the version encored in common.py, not 226 # the latest minor version available 227 versionString = common.ANDROID_NDK_VERSION_STRING 228 if common.ANDROID_NDK_HOST_OS in HOST_OS_TO_DOWNLOAD_STRING: 229 osString = HOST_OS_TO_DOWNLOAD_STRING[common.ANDROID_NDK_HOST_OS] 230 print("**** Please install from https://dl.google.com/android/repository/android-ndk-%s-%s.zip" % (versionString, osString)) 231 else: 232 print("**** Please download version", versionString, "from https://developer.android.com/ndk/downloads/index.html") 233 234 return False 235 236 return True 237 238if __name__ == "__main__": 239 nativeBuildTypes = ['Release', 'Debug', 'MinSizeRel', 'RelWithAsserts', 'RelWithDebInfo'] 240 androidBuildTypes = ['debug', 'release'] 241 242 parser = argparse.ArgumentParser() 243 parser.add_argument('--android-build-type', dest='androidBuildType', choices=androidBuildTypes, default='debug', help="Build type for android project..") 244 parser.add_argument('--native-build-type', dest='nativeBuildType', default="RelWithAsserts", choices=nativeBuildTypes, help="Build type passed to cmake when building native code.") 245 parser.add_argument('--build-root', dest='buildRoot', default=common.ANDROID_DIR, help="Root directory for storing build results.") 246 parser.add_argument('--dump-config', dest='dumpConfig', action='store_true', help="Print out all configurations variables") 247 parser.add_argument('--java-api', dest='javaApi', default=common.ANDROID_JAVA_API, help="Set the API signature for the java build.") 248 parser.add_argument('-p', '--parallel-build', dest='parallelBuild', action="store_true", help="Build native libraries in parallel.") 249 parser.add_argument('--skip-config-check', dest='skipConfigCheck', action="store_true", default=False, help="Skips config check. Warranty void.") 250 251 args = parser.parse_args() 252 253 if args.dumpConfig: 254 dumpConfig() 255 256 if not args.skipConfigCheck and not checkConfig(): 257 print "Config check failed, exit" 258 exit(-1) 259 260 build(buildRoot=os.path.abspath(args.buildRoot), androidBuildType=args.androidBuildType, nativeBuildType=args.nativeBuildType, javaApi=args.javaApi, doParallelBuild=args.parallelBuild) 261