add component metadata tag to CTS DEQP module
[platform/upstream/VK-GL-CTS.git] / android / scripts / build.py
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
23 import os
24 import re
25 import sys
26 import shutil
27 import string
28 import argparse
29 import time
30
31 import common
32
33 def 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
49 def 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
53 def getAssetsDir (buildRoot, nativeLib, buildType):
54         return os.path.join(getNativeBuildDir(buildRoot, nativeLib, buildType), "assets")
55
56 def 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
99 def 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
128 def 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
149 def 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
187 def 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.
194 def 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
211 def 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
238 if __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)