# -*- coding: utf-8 -*- #------------------------------------------------------------------------- # drawElements Quality Program utilities # -------------------------------------- # # Copyright 2015 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #------------------------------------------------------------------------- import os import re import sys import shutil import string import argparse import time import common def getStoreKeyPasswords (filename): f = open(filename) storepass = None keypass = None for line in f: m = re.search('([a-z]+)\s*\=\s*"([^"]+)"', line) if m != None: if m.group(1) == "storepass": storepass = m.group(2) elif m.group(1) == "keypass": keypass = m.group(2) f.close() if storepass == None or keypass == None: common.die("Could not read signing key passwords") return (storepass, keypass) def getNativeBuildDir (buildRoot, nativeLib, buildType): buildName = "%s-%d-%s" % (buildType.lower(), nativeLib.apiVersion, nativeLib.abiVersion) return os.path.normpath(os.path.join(buildRoot, "native", buildName)) def getAssetsDir (buildRoot, nativeLib, buildType): return os.path.join(getNativeBuildDir(buildRoot, nativeLib, buildType), "assets") def buildNative (buildRoot, libTargetDir, nativeLib, buildType): deqpDir = os.path.normpath(os.path.join(common.ANDROID_DIR, "..")) buildDir = getNativeBuildDir(buildRoot, nativeLib, buildType) libsDir = os.path.join(libTargetDir, nativeLib.abiVersion) srcLibFile = os.path.join(buildDir, common.NATIVE_LIB_NAME) dstLibFile = os.path.join(libsDir, common.NATIVE_LIB_NAME) # Make build directory if necessary if not os.path.exists(buildDir): os.makedirs(buildDir) toolchainFile = '%s/framework/delibs/cmake/toolchain-android-%s.cmake' % (deqpDir, common.ANDROID_NDK_TOOLCHAIN_VERSION) common.execArgsInDirectory([ 'cmake', '-G%s' % common.CMAKE_GENERATOR, '-DCMAKE_TOOLCHAIN_FILE=%s' % toolchainFile, '-DANDROID_NDK_HOST_OS=%s' % common.ANDROID_NDK_HOST_OS, '-DANDROID_NDK_PATH=%s' % common.ANDROID_NDK_PATH, '-DANDROID_ABI=%s' % nativeLib.abiVersion, '-DDE_ANDROID_API=%s' % nativeLib.apiVersion, '-DCMAKE_BUILD_TYPE=%s' % buildType, '-DDEQP_TARGET=android', deqpDir ], buildDir) common.execArgsInDirectory(['cmake', '--build', '.'] + common.EXTRA_BUILD_ARGS, buildDir) if not os.path.exists(libsDir): os.makedirs(libsDir) shutil.copyfile(srcLibFile, dstLibFile) # Copy gdbserver for debugging if buildType.lower() == "debug": srcGdbserverPath = os.path.join(common.ANDROID_NDK_PATH, 'prebuilt', nativeLib.prebuiltDir, 'gdbserver', 'gdbserver') dstGdbserverPath = os.path.join(libsDir, 'gdbserver') shutil.copyfile(srcGdbserverPath, dstGdbserverPath) else: assert not os.path.exists(os.path.join(libsDir, "gdbserver")) def buildApp (buildRoot, androidBuildType, javaApi): appDir = os.path.join(buildRoot, "package") # Set up app os.chdir(appDir) manifestSrcPath = os.path.normpath(os.path.join(common.ANDROID_DIR, "package", "AndroidManifest.xml")) manifestDstPath = os.path.normpath(os.path.join(appDir, "AndroidManifest.xml")) # Build dir can be the Android dir, in which case the copy is not needed. if manifestSrcPath != manifestDstPath: shutil.copy(manifestSrcPath, manifestDstPath) common.execArgs([ common.ANDROID_BIN, 'update', 'project', '--name', 'dEQP', '--path', '.', '--target', javaApi, ]) # Build common.execArgs([ common.ANT_BIN, androidBuildType, "-Dsource.dir=" + os.path.join(common.ANDROID_DIR, "package", "src"), "-Dresource.absolute.dir=" + os.path.join(common.ANDROID_DIR, "package", "res") ]) def signApp (keystore, keyname, storepass, keypass): os.chdir(os.path.join(common.ANDROID_DIR, "package")) common.execArgs([ common.JARSIGNER_BIN, '-keystore', keystore, '-storepass', storepass, '-keypass', keypass, '-sigfile', 'CERT', '-digestalg', 'SHA1', '-sigalg', 'MD5withRSA', '-signedjar', 'bin/dEQP-unaligned.apk', 'bin/dEQP-release-unsigned.apk', keyname ]) common.execArgs([ common.ZIPALIGN_BIN, '-f', '4', 'bin/dEQP-unaligned.apk', 'bin/dEQP-release.apk' ]) def build (buildRoot=common.ANDROID_DIR, androidBuildType='debug', nativeBuildType="Release", javaApi=common.ANDROID_JAVA_API, doParallelBuild=False): curDir = os.getcwd() try: assetsSrcDir = getAssetsDir(buildRoot, common.NATIVE_LIBS[0], nativeBuildType) assetsDstDir = os.path.join(buildRoot, "package", "assets") # Remove assets from the first build dir where we copy assets from # to avoid collecting cruft there. if os.path.exists(assetsSrcDir): shutil.rmtree(assetsSrcDir) if os.path.exists(assetsDstDir): shutil.rmtree(assetsDstDir) # Remove old libs dir to avoid collecting out-of-date versions # of libs for ABIs not built this time. libTargetDir = os.path.join(buildRoot, "package", "libs") if os.path.exists(libTargetDir): shutil.rmtree(libTargetDir) # Build native code nativeBuildArgs = [(buildRoot, libTargetDir, nativeLib, nativeBuildType) for nativeLib in common.NATIVE_LIBS] if doParallelBuild: common.parallelApply(buildNative, nativeBuildArgs) else: common.serialApply(buildNative, nativeBuildArgs) # Copy assets if os.path.exists(assetsSrcDir): shutil.copytree(assetsSrcDir, assetsDstDir) # Build java code and .apk buildApp(buildRoot, androidBuildType, javaApi) finally: # Restore working dir os.chdir(curDir) def dumpConfig (): print " " for entry in common.CONFIG_STRINGS: print "%-30s : %s" % (entry[0], entry[1]) print " " # Return NDK version as [,] or None if cannot be figured out. def getNdkVersion (path): if path == None: return None propFilePath = os.path.join(path, "source.properties") try: with open(propFilePath) as propFile: for line in propFile: keyValue = map(lambda x: string.strip(x), line.split("=")) if keyValue[0] == "Pkg.Revision": versionParts = keyValue[1].split(".") return tuple(map(int, versionParts[0:2])) except: print("Could not read source prop file '%s'" % propFilePath) return None def checkConfig (): HOST_OS_TO_DOWNLOAD_STRING = { "linux-x86_64" : "linux-x86_64", "windows" : "windows-x86", "windows-x86_64" : "windows-x86_64" } version = getNdkVersion(common.ANDROID_NDK_PATH) # Note: NDK currently maintains compatibility between minor # versions. Error out only on major version mismatch. if version == None or version[0] != common.ANDROID_NDK_VERSION[0]: print("**** WARNING! Deqp requires NDK version %s" % common.ANDROID_NDK_VERSION_STRING) print("**** NDK Path %s does not appear to have that version." % common.ANDROID_NDK_PATH) # Download hint will use the version encored in common.py, not # the latest minor version available versionString = common.ANDROID_NDK_VERSION_STRING if common.ANDROID_NDK_HOST_OS in HOST_OS_TO_DOWNLOAD_STRING: osString = HOST_OS_TO_DOWNLOAD_STRING[common.ANDROID_NDK_HOST_OS] print("**** Please install from https://dl.google.com/android/repository/android-ndk-%s-%s.zip" % (versionString, osString)) else: print("**** Please download version", versionString, "from https://developer.android.com/ndk/downloads/index.html") return False return True if __name__ == "__main__": nativeBuildTypes = ['Release', 'Debug', 'MinSizeRel', 'RelWithAsserts', 'RelWithDebInfo'] androidBuildTypes = ['debug', 'release'] parser = argparse.ArgumentParser() parser.add_argument('--android-build-type', dest='androidBuildType', choices=androidBuildTypes, default='debug', help="Build type for android project..") parser.add_argument('--native-build-type', dest='nativeBuildType', default="RelWithAsserts", choices=nativeBuildTypes, help="Build type passed to cmake when building native code.") parser.add_argument('--build-root', dest='buildRoot', default=common.ANDROID_DIR, help="Root directory for storing build results.") parser.add_argument('--dump-config', dest='dumpConfig', action='store_true', help="Print out all configurations variables") parser.add_argument('--java-api', dest='javaApi', default=common.ANDROID_JAVA_API, help="Set the API signature for the java build.") parser.add_argument('-p', '--parallel-build', dest='parallelBuild', action="store_true", help="Build native libraries in parallel.") parser.add_argument('--skip-config-check', dest='skipConfigCheck', action="store_true", default=False, help="Skips config check. Warranty void.") args = parser.parse_args() if args.dumpConfig: dumpConfig() if not args.skipConfigCheck and not checkConfig(): print "Config check failed, exit" exit(-1) build(buildRoot=os.path.abspath(args.buildRoot), androidBuildType=args.androidBuildType, nativeBuildType=args.nativeBuildType, javaApi=args.javaApi, doParallelBuild=args.parallelBuild)