xref: /aosp_15_r20/external/deqp/scripts/android/build_apk.py (revision 35238bce31c2a825756842865a792f8cf7f89930)
1*35238bceSAndroid Build Coastguard Worker# -*- coding: utf-8 -*-
2*35238bceSAndroid Build Coastguard Worker
3*35238bceSAndroid Build Coastguard Worker#-------------------------------------------------------------------------
4*35238bceSAndroid Build Coastguard Worker# drawElements Quality Program utilities
5*35238bceSAndroid Build Coastguard Worker# --------------------------------------
6*35238bceSAndroid Build Coastguard Worker#
7*35238bceSAndroid Build Coastguard Worker# Copyright 2017 The Android Open Source Project
8*35238bceSAndroid Build Coastguard Worker#
9*35238bceSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
10*35238bceSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
11*35238bceSAndroid Build Coastguard Worker# You may obtain a copy of the License at
12*35238bceSAndroid Build Coastguard Worker#
13*35238bceSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
14*35238bceSAndroid Build Coastguard Worker#
15*35238bceSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
16*35238bceSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
17*35238bceSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18*35238bceSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
19*35238bceSAndroid Build Coastguard Worker# limitations under the License.
20*35238bceSAndroid Build Coastguard Worker#
21*35238bceSAndroid Build Coastguard Worker#-------------------------------------------------------------------------
22*35238bceSAndroid Build Coastguard Worker
23*35238bceSAndroid Build Coastguard Worker# \todo [2017-04-10 pyry]
24*35238bceSAndroid Build Coastguard Worker# * Use smarter asset copy in main build
25*35238bceSAndroid Build Coastguard Worker#   * cmake -E copy_directory doesn't copy timestamps which will cause
26*35238bceSAndroid Build Coastguard Worker#     assets to be always re-packaged
27*35238bceSAndroid Build Coastguard Worker# * Consider adding an option for downloading SDK & NDK
28*35238bceSAndroid Build Coastguard Worker
29*35238bceSAndroid Build Coastguard Workerimport os
30*35238bceSAndroid Build Coastguard Workerimport re
31*35238bceSAndroid Build Coastguard Workerimport sys
32*35238bceSAndroid Build Coastguard Workerimport glob
33*35238bceSAndroid Build Coastguard Workerimport string
34*35238bceSAndroid Build Coastguard Workerimport shutil
35*35238bceSAndroid Build Coastguard Workerimport argparse
36*35238bceSAndroid Build Coastguard Workerimport tempfile
37*35238bceSAndroid Build Coastguard Workerimport xml.etree.ElementTree
38*35238bceSAndroid Build Coastguard Worker
39*35238bceSAndroid Build Coastguard Worker# Import from <root>/scripts
40*35238bceSAndroid Build Coastguard Workersys.path.append(os.path.join(os.path.dirname(__file__), ".."))
41*35238bceSAndroid Build Coastguard Worker
42*35238bceSAndroid Build Coastguard Workerfrom ctsbuild.common import *
43*35238bceSAndroid Build Coastguard Workerfrom ctsbuild.config import *
44*35238bceSAndroid Build Coastguard Workerfrom ctsbuild.build import *
45*35238bceSAndroid Build Coastguard Worker
46*35238bceSAndroid Build Coastguard Workerclass SDKEnv:
47*35238bceSAndroid Build Coastguard Worker    def __init__(self, path, desired_version):
48*35238bceSAndroid Build Coastguard Worker        self.path = path
49*35238bceSAndroid Build Coastguard Worker        self.buildToolsVersion = SDKEnv.selectBuildToolsVersion(self.path, desired_version)
50*35238bceSAndroid Build Coastguard Worker
51*35238bceSAndroid Build Coastguard Worker    @staticmethod
52*35238bceSAndroid Build Coastguard Worker    def getBuildToolsVersions (path):
53*35238bceSAndroid Build Coastguard Worker        buildToolsPath = os.path.join(path, "build-tools")
54*35238bceSAndroid Build Coastguard Worker        versions = {}
55*35238bceSAndroid Build Coastguard Worker
56*35238bceSAndroid Build Coastguard Worker        if os.path.exists(buildToolsPath):
57*35238bceSAndroid Build Coastguard Worker            for item in os.listdir(buildToolsPath):
58*35238bceSAndroid Build Coastguard Worker                m = re.match(r'^([0-9]+)\.([0-9]+)\.([0-9]+)$', item)
59*35238bceSAndroid Build Coastguard Worker                if m != None:
60*35238bceSAndroid Build Coastguard Worker                    versions[int(m.group(1))] = (int(m.group(1)), int(m.group(2)), int(m.group(3)))
61*35238bceSAndroid Build Coastguard Worker
62*35238bceSAndroid Build Coastguard Worker        return versions
63*35238bceSAndroid Build Coastguard Worker
64*35238bceSAndroid Build Coastguard Worker    @staticmethod
65*35238bceSAndroid Build Coastguard Worker    def selectBuildToolsVersion (path, preferred):
66*35238bceSAndroid Build Coastguard Worker        versions = SDKEnv.getBuildToolsVersions(path)
67*35238bceSAndroid Build Coastguard Worker
68*35238bceSAndroid Build Coastguard Worker        if len(versions) == 0:
69*35238bceSAndroid Build Coastguard Worker            return (0,0,0)
70*35238bceSAndroid Build Coastguard Worker
71*35238bceSAndroid Build Coastguard Worker        if preferred == -1:
72*35238bceSAndroid Build Coastguard Worker            return max(versions.values())
73*35238bceSAndroid Build Coastguard Worker
74*35238bceSAndroid Build Coastguard Worker        if preferred in versions:
75*35238bceSAndroid Build Coastguard Worker            return versions[preferred]
76*35238bceSAndroid Build Coastguard Worker
77*35238bceSAndroid Build Coastguard Worker        # Pick newest
78*35238bceSAndroid Build Coastguard Worker        newest_version = max(versions.values())
79*35238bceSAndroid Build Coastguard Worker        print("Couldn't find Android Tool version %d, %d was selected." % (preferred, newest_version[0]))
80*35238bceSAndroid Build Coastguard Worker        return newest_version
81*35238bceSAndroid Build Coastguard Worker
82*35238bceSAndroid Build Coastguard Worker    def getPlatformLibrary (self, apiVersion):
83*35238bceSAndroid Build Coastguard Worker        return os.path.join(self.path, "platforms", "android-%d" % apiVersion, "android.jar")
84*35238bceSAndroid Build Coastguard Worker
85*35238bceSAndroid Build Coastguard Worker    def getBuildToolsPath (self):
86*35238bceSAndroid Build Coastguard Worker        return os.path.join(self.path, "build-tools", "%d.%d.%d" % self.buildToolsVersion)
87*35238bceSAndroid Build Coastguard Worker
88*35238bceSAndroid Build Coastguard Workerclass NDKEnv:
89*35238bceSAndroid Build Coastguard Worker    def __init__(self, path):
90*35238bceSAndroid Build Coastguard Worker        self.path = path
91*35238bceSAndroid Build Coastguard Worker        self.version = NDKEnv.detectVersion(self.path)
92*35238bceSAndroid Build Coastguard Worker        self.hostOsName = NDKEnv.detectHostOsName(self.path)
93*35238bceSAndroid Build Coastguard Worker
94*35238bceSAndroid Build Coastguard Worker    @staticmethod
95*35238bceSAndroid Build Coastguard Worker    def getKnownAbis ():
96*35238bceSAndroid Build Coastguard Worker        return ["armeabi-v7a", "arm64-v8a", "x86", "x86_64"]
97*35238bceSAndroid Build Coastguard Worker
98*35238bceSAndroid Build Coastguard Worker    @staticmethod
99*35238bceSAndroid Build Coastguard Worker    def getAbiPrebuiltsName (abiName):
100*35238bceSAndroid Build Coastguard Worker        prebuilts = {
101*35238bceSAndroid Build Coastguard Worker            "armeabi-v7a": 'android-arm',
102*35238bceSAndroid Build Coastguard Worker            "arm64-v8a": 'android-arm64',
103*35238bceSAndroid Build Coastguard Worker            "x86": 'android-x86',
104*35238bceSAndroid Build Coastguard Worker            "x86_64": 'android-x86_64',
105*35238bceSAndroid Build Coastguard Worker        }
106*35238bceSAndroid Build Coastguard Worker
107*35238bceSAndroid Build Coastguard Worker        if not abiName in prebuilts:
108*35238bceSAndroid Build Coastguard Worker            raise Exception("Unknown ABI: " + abiName)
109*35238bceSAndroid Build Coastguard Worker
110*35238bceSAndroid Build Coastguard Worker        return prebuilts[abiName]
111*35238bceSAndroid Build Coastguard Worker
112*35238bceSAndroid Build Coastguard Worker    @staticmethod
113*35238bceSAndroid Build Coastguard Worker    def detectVersion (path):
114*35238bceSAndroid Build Coastguard Worker        propFilePath = os.path.join(path, "source.properties")
115*35238bceSAndroid Build Coastguard Worker        try:
116*35238bceSAndroid Build Coastguard Worker            with open(propFilePath) as propFile:
117*35238bceSAndroid Build Coastguard Worker                for line in propFile:
118*35238bceSAndroid Build Coastguard Worker                    keyValue = list(map(lambda x: x.strip(), line.split("=")))
119*35238bceSAndroid Build Coastguard Worker                    if keyValue[0] == "Pkg.Revision":
120*35238bceSAndroid Build Coastguard Worker                        versionParts = keyValue[1].split(".")
121*35238bceSAndroid Build Coastguard Worker                        return tuple(map(int, versionParts[0:2]))
122*35238bceSAndroid Build Coastguard Worker        except Exception as e:
123*35238bceSAndroid Build Coastguard Worker            raise Exception("Failed to read source prop file '%s': %s" % (propFilePath, str(e)))
124*35238bceSAndroid Build Coastguard Worker        except:
125*35238bceSAndroid Build Coastguard Worker            raise Exception("Failed to read source prop file '%s': unkown error")
126*35238bceSAndroid Build Coastguard Worker
127*35238bceSAndroid Build Coastguard Worker        raise Exception("Failed to detect NDK version (does %s/source.properties have Pkg.Revision?)" % path)
128*35238bceSAndroid Build Coastguard Worker
129*35238bceSAndroid Build Coastguard Worker    @staticmethod
130*35238bceSAndroid Build Coastguard Worker    def isHostOsSupported (hostOsName):
131*35238bceSAndroid Build Coastguard Worker        os = HostInfo.getOs()
132*35238bceSAndroid Build Coastguard Worker        bits = HostInfo.getArchBits()
133*35238bceSAndroid Build Coastguard Worker        hostOsParts = hostOsName.split('-')
134*35238bceSAndroid Build Coastguard Worker
135*35238bceSAndroid Build Coastguard Worker        if len(hostOsParts) > 1:
136*35238bceSAndroid Build Coastguard Worker            assert(len(hostOsParts) == 2)
137*35238bceSAndroid Build Coastguard Worker            assert(hostOsParts[1] == "x86_64")
138*35238bceSAndroid Build Coastguard Worker
139*35238bceSAndroid Build Coastguard Worker            if bits != 64:
140*35238bceSAndroid Build Coastguard Worker                return False
141*35238bceSAndroid Build Coastguard Worker
142*35238bceSAndroid Build Coastguard Worker        if os == HostInfo.OS_WINDOWS:
143*35238bceSAndroid Build Coastguard Worker            return hostOsParts[0] == 'windows'
144*35238bceSAndroid Build Coastguard Worker        elif os == HostInfo.OS_LINUX:
145*35238bceSAndroid Build Coastguard Worker            return hostOsParts[0] == 'linux'
146*35238bceSAndroid Build Coastguard Worker        elif os == HostInfo.OS_OSX:
147*35238bceSAndroid Build Coastguard Worker            return hostOsParts[0] == 'darwin'
148*35238bceSAndroid Build Coastguard Worker        else:
149*35238bceSAndroid Build Coastguard Worker            raise Exception("Unhandled HostInfo.getOs() '%d'" % os)
150*35238bceSAndroid Build Coastguard Worker
151*35238bceSAndroid Build Coastguard Worker    @staticmethod
152*35238bceSAndroid Build Coastguard Worker    def detectHostOsName (path):
153*35238bceSAndroid Build Coastguard Worker        hostOsNames = [
154*35238bceSAndroid Build Coastguard Worker            "windows",
155*35238bceSAndroid Build Coastguard Worker            "windows-x86_64",
156*35238bceSAndroid Build Coastguard Worker            "darwin-x86",
157*35238bceSAndroid Build Coastguard Worker            "darwin-x86_64",
158*35238bceSAndroid Build Coastguard Worker            "linux-x86",
159*35238bceSAndroid Build Coastguard Worker            "linux-x86_64"
160*35238bceSAndroid Build Coastguard Worker        ]
161*35238bceSAndroid Build Coastguard Worker
162*35238bceSAndroid Build Coastguard Worker        for name in hostOsNames:
163*35238bceSAndroid Build Coastguard Worker            if os.path.exists(os.path.join(path, "prebuilt", name)):
164*35238bceSAndroid Build Coastguard Worker                return name
165*35238bceSAndroid Build Coastguard Worker
166*35238bceSAndroid Build Coastguard Worker        raise Exception("Failed to determine NDK host OS")
167*35238bceSAndroid Build Coastguard Worker
168*35238bceSAndroid Build Coastguard Workerclass Environment:
169*35238bceSAndroid Build Coastguard Worker    def __init__(self, sdk, ndk):
170*35238bceSAndroid Build Coastguard Worker        self.sdk = sdk
171*35238bceSAndroid Build Coastguard Worker        self.ndk = ndk
172*35238bceSAndroid Build Coastguard Worker
173*35238bceSAndroid Build Coastguard Workerclass Configuration:
174*35238bceSAndroid Build Coastguard Worker    def __init__(self, env, buildPath, abis, nativeApi, javaApi, minApi, nativeBuildType, gtfTarget, verbose, layers, angle):
175*35238bceSAndroid Build Coastguard Worker        self.env = env
176*35238bceSAndroid Build Coastguard Worker        self.sourcePath = DEQP_DIR
177*35238bceSAndroid Build Coastguard Worker        self.buildPath = buildPath
178*35238bceSAndroid Build Coastguard Worker        self.abis = abis
179*35238bceSAndroid Build Coastguard Worker        self.nativeApi = nativeApi
180*35238bceSAndroid Build Coastguard Worker        self.javaApi = javaApi
181*35238bceSAndroid Build Coastguard Worker        self.minApi = minApi
182*35238bceSAndroid Build Coastguard Worker        self.nativeBuildType = nativeBuildType
183*35238bceSAndroid Build Coastguard Worker        self.gtfTarget = gtfTarget
184*35238bceSAndroid Build Coastguard Worker        self.verbose = verbose
185*35238bceSAndroid Build Coastguard Worker        self.layers = layers
186*35238bceSAndroid Build Coastguard Worker        self.angle = angle
187*35238bceSAndroid Build Coastguard Worker        self.dCompilerName = "d8"
188*35238bceSAndroid Build Coastguard Worker        self.cmakeGenerator = selectFirstAvailableGenerator([NINJA_GENERATOR, MAKEFILE_GENERATOR, NMAKE_GENERATOR])
189*35238bceSAndroid Build Coastguard Worker
190*35238bceSAndroid Build Coastguard Worker    def check (self):
191*35238bceSAndroid Build Coastguard Worker        if self.cmakeGenerator == None:
192*35238bceSAndroid Build Coastguard Worker            raise Exception("Failed to find build tools for CMake")
193*35238bceSAndroid Build Coastguard Worker
194*35238bceSAndroid Build Coastguard Worker        if not os.path.exists(self.env.ndk.path):
195*35238bceSAndroid Build Coastguard Worker            raise Exception("Android NDK not found at %s" % self.env.ndk.path)
196*35238bceSAndroid Build Coastguard Worker
197*35238bceSAndroid Build Coastguard Worker        if not NDKEnv.isHostOsSupported(self.env.ndk.hostOsName):
198*35238bceSAndroid Build Coastguard Worker            raise Exception("NDK '%s' is not supported on this machine" % self.env.ndk.hostOsName)
199*35238bceSAndroid Build Coastguard Worker
200*35238bceSAndroid Build Coastguard Worker        if self.env.ndk.version[0] < 15:
201*35238bceSAndroid Build Coastguard Worker            raise Exception("Android NDK version %d is not supported; build requires NDK version >= 15" % (self.env.ndk.version[0]))
202*35238bceSAndroid Build Coastguard Worker
203*35238bceSAndroid Build Coastguard Worker        if not (self.minApi <= self.javaApi <= self.nativeApi):
204*35238bceSAndroid Build Coastguard Worker            raise Exception("Requires: min-api (%d) <= java-api (%d) <= native-api (%d)" % (self.minApi, self.javaApi, self.nativeApi))
205*35238bceSAndroid Build Coastguard Worker
206*35238bceSAndroid Build Coastguard Worker        if self.env.sdk.buildToolsVersion == (0,0,0):
207*35238bceSAndroid Build Coastguard Worker            raise Exception("No build tools directory found at %s" % os.path.join(self.env.sdk.path, "build-tools"))
208*35238bceSAndroid Build Coastguard Worker
209*35238bceSAndroid Build Coastguard Worker        if not os.path.exists(os.path.join(self.env.sdk.path, "platforms", "android-%d" % self.javaApi)):
210*35238bceSAndroid Build Coastguard Worker            raise Exception("No SDK with api version %d directory found at %s for Java Api" % (self.javaApi, os.path.join(self.env.sdk.path, "platforms")))
211*35238bceSAndroid Build Coastguard Worker
212*35238bceSAndroid Build Coastguard Worker        # Try to find first d8 since dx was deprecated
213*35238bceSAndroid Build Coastguard Worker        if which(self.dCompilerName, [self.env.sdk.getBuildToolsPath()]) == None:
214*35238bceSAndroid Build Coastguard Worker            print("Couldn't find %s, will try to find dx", self.dCompilerName)
215*35238bceSAndroid Build Coastguard Worker            self.dCompilerName = "dx"
216*35238bceSAndroid Build Coastguard Worker
217*35238bceSAndroid Build Coastguard Worker        androidBuildTools = ["aapt", "zipalign", "apksigner", self.dCompilerName]
218*35238bceSAndroid Build Coastguard Worker        for tool in androidBuildTools:
219*35238bceSAndroid Build Coastguard Worker            if which(tool, [self.env.sdk.getBuildToolsPath()]) == None:
220*35238bceSAndroid Build Coastguard Worker                raise Exception("Missing Android build tool: %s in %s" % (tool, self.env.sdk.getBuildToolsPath()))
221*35238bceSAndroid Build Coastguard Worker
222*35238bceSAndroid Build Coastguard Worker        requiredToolsInPath = ["javac", "jar", "keytool"]
223*35238bceSAndroid Build Coastguard Worker        for tool in requiredToolsInPath:
224*35238bceSAndroid Build Coastguard Worker            if which(tool) == None:
225*35238bceSAndroid Build Coastguard Worker                raise Exception("%s not in PATH" % tool)
226*35238bceSAndroid Build Coastguard Worker
227*35238bceSAndroid Build Coastguard Workerdef log (config, msg):
228*35238bceSAndroid Build Coastguard Worker    if config.verbose:
229*35238bceSAndroid Build Coastguard Worker        print(msg)
230*35238bceSAndroid Build Coastguard Worker
231*35238bceSAndroid Build Coastguard Workerdef executeAndLog (config, args):
232*35238bceSAndroid Build Coastguard Worker    if config.verbose:
233*35238bceSAndroid Build Coastguard Worker        print(" ".join(args))
234*35238bceSAndroid Build Coastguard Worker    execute(args)
235*35238bceSAndroid Build Coastguard Worker
236*35238bceSAndroid Build Coastguard Worker# Path components
237*35238bceSAndroid Build Coastguard Worker
238*35238bceSAndroid Build Coastguard Workerclass ResolvablePathComponent:
239*35238bceSAndroid Build Coastguard Worker    def __init__ (self):
240*35238bceSAndroid Build Coastguard Worker        pass
241*35238bceSAndroid Build Coastguard Worker
242*35238bceSAndroid Build Coastguard Workerclass SourceRoot (ResolvablePathComponent):
243*35238bceSAndroid Build Coastguard Worker    def resolve (self, config):
244*35238bceSAndroid Build Coastguard Worker        return config.sourcePath
245*35238bceSAndroid Build Coastguard Worker
246*35238bceSAndroid Build Coastguard Workerclass BuildRoot (ResolvablePathComponent):
247*35238bceSAndroid Build Coastguard Worker    def resolve (self, config):
248*35238bceSAndroid Build Coastguard Worker        return config.buildPath
249*35238bceSAndroid Build Coastguard Worker
250*35238bceSAndroid Build Coastguard Workerclass NativeBuildPath (ResolvablePathComponent):
251*35238bceSAndroid Build Coastguard Worker    def __init__ (self, abiName):
252*35238bceSAndroid Build Coastguard Worker        self.abiName = abiName
253*35238bceSAndroid Build Coastguard Worker
254*35238bceSAndroid Build Coastguard Worker    def resolve (self, config):
255*35238bceSAndroid Build Coastguard Worker        return getNativeBuildPath(config, self.abiName)
256*35238bceSAndroid Build Coastguard Worker
257*35238bceSAndroid Build Coastguard Workerclass GeneratedResSourcePath (ResolvablePathComponent):
258*35238bceSAndroid Build Coastguard Worker    def __init__ (self, package):
259*35238bceSAndroid Build Coastguard Worker        self.package = package
260*35238bceSAndroid Build Coastguard Worker
261*35238bceSAndroid Build Coastguard Worker    def resolve (self, config):
262*35238bceSAndroid Build Coastguard Worker        packageComps = self.package.getPackageName(config).split('.')
263*35238bceSAndroid Build Coastguard Worker        packageDir = os.path.join(*packageComps)
264*35238bceSAndroid Build Coastguard Worker
265*35238bceSAndroid Build Coastguard Worker        return os.path.join(config.buildPath, self.package.getAppDirName(), "src", packageDir, "R.java")
266*35238bceSAndroid Build Coastguard Worker
267*35238bceSAndroid Build Coastguard Workerdef resolvePath (config, path):
268*35238bceSAndroid Build Coastguard Worker    resolvedComps = []
269*35238bceSAndroid Build Coastguard Worker
270*35238bceSAndroid Build Coastguard Worker    for component in path:
271*35238bceSAndroid Build Coastguard Worker        if isinstance(component, ResolvablePathComponent):
272*35238bceSAndroid Build Coastguard Worker            resolvedComps.append(component.resolve(config))
273*35238bceSAndroid Build Coastguard Worker        else:
274*35238bceSAndroid Build Coastguard Worker            resolvedComps.append(str(component))
275*35238bceSAndroid Build Coastguard Worker
276*35238bceSAndroid Build Coastguard Worker    return os.path.join(*resolvedComps)
277*35238bceSAndroid Build Coastguard Worker
278*35238bceSAndroid Build Coastguard Workerdef resolvePaths (config, paths):
279*35238bceSAndroid Build Coastguard Worker    return list(map(lambda p: resolvePath(config, p), paths))
280*35238bceSAndroid Build Coastguard Worker
281*35238bceSAndroid Build Coastguard Workerclass BuildStep:
282*35238bceSAndroid Build Coastguard Worker    def __init__ (self):
283*35238bceSAndroid Build Coastguard Worker        pass
284*35238bceSAndroid Build Coastguard Worker
285*35238bceSAndroid Build Coastguard Worker    def getInputs (self):
286*35238bceSAndroid Build Coastguard Worker        return []
287*35238bceSAndroid Build Coastguard Worker
288*35238bceSAndroid Build Coastguard Worker    def getOutputs (self):
289*35238bceSAndroid Build Coastguard Worker        return []
290*35238bceSAndroid Build Coastguard Worker
291*35238bceSAndroid Build Coastguard Worker    @staticmethod
292*35238bceSAndroid Build Coastguard Worker    def expandPathsToFiles (paths):
293*35238bceSAndroid Build Coastguard Worker        """
294*35238bceSAndroid Build Coastguard Worker        Expand mixed list of file and directory paths into a flattened list
295*35238bceSAndroid Build Coastguard Worker        of files. Any non-existent input paths are preserved as is.
296*35238bceSAndroid Build Coastguard Worker        """
297*35238bceSAndroid Build Coastguard Worker
298*35238bceSAndroid Build Coastguard Worker        def getFiles (dirPath):
299*35238bceSAndroid Build Coastguard Worker            for root, dirs, files in os.walk(dirPath):
300*35238bceSAndroid Build Coastguard Worker                for file in files:
301*35238bceSAndroid Build Coastguard Worker                    yield os.path.join(root, file)
302*35238bceSAndroid Build Coastguard Worker
303*35238bceSAndroid Build Coastguard Worker        files = []
304*35238bceSAndroid Build Coastguard Worker        for path in paths:
305*35238bceSAndroid Build Coastguard Worker            if os.path.isdir(path):
306*35238bceSAndroid Build Coastguard Worker                files += list(getFiles(path))
307*35238bceSAndroid Build Coastguard Worker            else:
308*35238bceSAndroid Build Coastguard Worker                files.append(path)
309*35238bceSAndroid Build Coastguard Worker
310*35238bceSAndroid Build Coastguard Worker        return files
311*35238bceSAndroid Build Coastguard Worker
312*35238bceSAndroid Build Coastguard Worker    def isUpToDate (self, config):
313*35238bceSAndroid Build Coastguard Worker        inputs = resolvePaths(config, self.getInputs())
314*35238bceSAndroid Build Coastguard Worker        outputs = resolvePaths(config, self.getOutputs())
315*35238bceSAndroid Build Coastguard Worker
316*35238bceSAndroid Build Coastguard Worker        assert len(inputs) > 0 and len(outputs) > 0
317*35238bceSAndroid Build Coastguard Worker
318*35238bceSAndroid Build Coastguard Worker        expandedInputs = BuildStep.expandPathsToFiles(inputs)
319*35238bceSAndroid Build Coastguard Worker        expandedOutputs = BuildStep.expandPathsToFiles(outputs)
320*35238bceSAndroid Build Coastguard Worker
321*35238bceSAndroid Build Coastguard Worker        existingInputs = list(filter(os.path.exists, expandedInputs))
322*35238bceSAndroid Build Coastguard Worker        existingOutputs = list(filter(os.path.exists, expandedOutputs))
323*35238bceSAndroid Build Coastguard Worker
324*35238bceSAndroid Build Coastguard Worker        if len(existingInputs) != len(expandedInputs):
325*35238bceSAndroid Build Coastguard Worker            for file in expandedInputs:
326*35238bceSAndroid Build Coastguard Worker                if file not in existingInputs:
327*35238bceSAndroid Build Coastguard Worker                    print("ERROR: Missing input file: %s" % file)
328*35238bceSAndroid Build Coastguard Worker            die("Missing input files")
329*35238bceSAndroid Build Coastguard Worker
330*35238bceSAndroid Build Coastguard Worker        if len(existingOutputs) != len(expandedOutputs):
331*35238bceSAndroid Build Coastguard Worker            return False # One or more output files are missing
332*35238bceSAndroid Build Coastguard Worker
333*35238bceSAndroid Build Coastguard Worker        lastInputChange = max(map(os.path.getmtime, existingInputs))
334*35238bceSAndroid Build Coastguard Worker        firstOutputChange = min(map(os.path.getmtime, existingOutputs))
335*35238bceSAndroid Build Coastguard Worker
336*35238bceSAndroid Build Coastguard Worker        return lastInputChange <= firstOutputChange
337*35238bceSAndroid Build Coastguard Worker
338*35238bceSAndroid Build Coastguard Worker    def update (config):
339*35238bceSAndroid Build Coastguard Worker        die("BuildStep.update() not implemented")
340*35238bceSAndroid Build Coastguard Worker
341*35238bceSAndroid Build Coastguard Workerdef getNativeBuildPath (config, abiName):
342*35238bceSAndroid Build Coastguard Worker    return os.path.join(config.buildPath, "%s-%s-%d" % (abiName, config.nativeBuildType, config.nativeApi))
343*35238bceSAndroid Build Coastguard Worker
344*35238bceSAndroid Build Coastguard Workerdef clearCMakeCacheVariables(args):
345*35238bceSAndroid Build Coastguard Worker    # New value, so clear the necessary cmake variables
346*35238bceSAndroid Build Coastguard Worker    args.append('-UANGLE_LIBS')
347*35238bceSAndroid Build Coastguard Worker    args.append('-UGLES1_LIBRARY')
348*35238bceSAndroid Build Coastguard Worker    args.append('-UGLES2_LIBRARY')
349*35238bceSAndroid Build Coastguard Worker    args.append('-UEGL_LIBRARY')
350*35238bceSAndroid Build Coastguard Worker
351*35238bceSAndroid Build Coastguard Workerdef buildNativeLibrary (config, abiName):
352*35238bceSAndroid Build Coastguard Worker    def makeNDKVersionString (version):
353*35238bceSAndroid Build Coastguard Worker        minorVersionString = (chr(ord('a') + version[1]) if version[1] > 0 else "")
354*35238bceSAndroid Build Coastguard Worker        return "r%d%s" % (version[0], minorVersionString)
355*35238bceSAndroid Build Coastguard Worker
356*35238bceSAndroid Build Coastguard Worker    def getBuildArgs (config, abiName):
357*35238bceSAndroid Build Coastguard Worker        args = ['-DDEQP_TARGET=android',
358*35238bceSAndroid Build Coastguard Worker                '-DDEQP_TARGET_TOOLCHAIN=ndk-modern',
359*35238bceSAndroid Build Coastguard Worker                '-DCMAKE_C_FLAGS=-Werror',
360*35238bceSAndroid Build Coastguard Worker                '-DCMAKE_CXX_FLAGS=-Werror',
361*35238bceSAndroid Build Coastguard Worker                '-DANDROID_NDK_PATH=%s' % config.env.ndk.path,
362*35238bceSAndroid Build Coastguard Worker                '-DANDROID_ABI=%s' % abiName,
363*35238bceSAndroid Build Coastguard Worker                '-DDE_ANDROID_API=%s' % config.nativeApi,
364*35238bceSAndroid Build Coastguard Worker                '-DGLCTS_GTF_TARGET=%s' % config.gtfTarget]
365*35238bceSAndroid Build Coastguard Worker
366*35238bceSAndroid Build Coastguard Worker        if config.angle is None:
367*35238bceSAndroid Build Coastguard Worker            # Find any previous builds that may have embedded ANGLE libs and clear the CMake cache
368*35238bceSAndroid Build Coastguard Worker            for abi in NDKEnv.getKnownAbis():
369*35238bceSAndroid Build Coastguard Worker                cMakeCachePath = os.path.join(getNativeBuildPath(config, abi), "CMakeCache.txt")
370*35238bceSAndroid Build Coastguard Worker                try:
371*35238bceSAndroid Build Coastguard Worker                    if 'ANGLE_LIBS' in open(cMakeCachePath).read():
372*35238bceSAndroid Build Coastguard Worker                        clearCMakeCacheVariables(args)
373*35238bceSAndroid Build Coastguard Worker                except IOError:
374*35238bceSAndroid Build Coastguard Worker                    pass
375*35238bceSAndroid Build Coastguard Worker        else:
376*35238bceSAndroid Build Coastguard Worker            cMakeCachePath = os.path.join(getNativeBuildPath(config, abiName), "CMakeCache.txt")
377*35238bceSAndroid Build Coastguard Worker            angleLibsDir = os.path.join(config.angle, abiName)
378*35238bceSAndroid Build Coastguard Worker            # Check if the user changed where the ANGLE libs are being loaded from
379*35238bceSAndroid Build Coastguard Worker            try:
380*35238bceSAndroid Build Coastguard Worker                if angleLibsDir not in open(cMakeCachePath).read():
381*35238bceSAndroid Build Coastguard Worker                    clearCMakeCacheVariables(args)
382*35238bceSAndroid Build Coastguard Worker            except IOError:
383*35238bceSAndroid Build Coastguard Worker                pass
384*35238bceSAndroid Build Coastguard Worker            args.append('-DANGLE_LIBS=%s' % angleLibsDir)
385*35238bceSAndroid Build Coastguard Worker
386*35238bceSAndroid Build Coastguard Worker        return args
387*35238bceSAndroid Build Coastguard Worker
388*35238bceSAndroid Build Coastguard Worker    nativeBuildPath = getNativeBuildPath(config, abiName)
389*35238bceSAndroid Build Coastguard Worker    buildConfig = BuildConfig(nativeBuildPath, config.nativeBuildType, getBuildArgs(config, abiName))
390*35238bceSAndroid Build Coastguard Worker
391*35238bceSAndroid Build Coastguard Worker    build(buildConfig, config.cmakeGenerator, ["deqp"])
392*35238bceSAndroid Build Coastguard Worker
393*35238bceSAndroid Build Coastguard Workerdef executeSteps (config, steps):
394*35238bceSAndroid Build Coastguard Worker    for step in steps:
395*35238bceSAndroid Build Coastguard Worker        if not step.isUpToDate(config):
396*35238bceSAndroid Build Coastguard Worker            step.update(config)
397*35238bceSAndroid Build Coastguard Worker
398*35238bceSAndroid Build Coastguard Workerdef parsePackageName (manifestPath):
399*35238bceSAndroid Build Coastguard Worker    tree = xml.etree.ElementTree.parse(manifestPath)
400*35238bceSAndroid Build Coastguard Worker
401*35238bceSAndroid Build Coastguard Worker    if not 'package' in tree.getroot().attrib:
402*35238bceSAndroid Build Coastguard Worker        raise Exception("'package' attribute missing from root element in %s" % manifestPath)
403*35238bceSAndroid Build Coastguard Worker
404*35238bceSAndroid Build Coastguard Worker    return tree.getroot().attrib['package']
405*35238bceSAndroid Build Coastguard Worker
406*35238bceSAndroid Build Coastguard Workerclass PackageDescription:
407*35238bceSAndroid Build Coastguard Worker    def __init__ (self, appDirName, appName, hasResources = True):
408*35238bceSAndroid Build Coastguard Worker        self.appDirName = appDirName
409*35238bceSAndroid Build Coastguard Worker        self.appName = appName
410*35238bceSAndroid Build Coastguard Worker        self.hasResources = hasResources
411*35238bceSAndroid Build Coastguard Worker
412*35238bceSAndroid Build Coastguard Worker    def getAppName (self):
413*35238bceSAndroid Build Coastguard Worker        return self.appName
414*35238bceSAndroid Build Coastguard Worker
415*35238bceSAndroid Build Coastguard Worker    def getAppDirName (self):
416*35238bceSAndroid Build Coastguard Worker        return self.appDirName
417*35238bceSAndroid Build Coastguard Worker
418*35238bceSAndroid Build Coastguard Worker    def getPackageName (self, config):
419*35238bceSAndroid Build Coastguard Worker        manifestPath = resolvePath(config, self.getManifestPath())
420*35238bceSAndroid Build Coastguard Worker
421*35238bceSAndroid Build Coastguard Worker        return parsePackageName(manifestPath)
422*35238bceSAndroid Build Coastguard Worker
423*35238bceSAndroid Build Coastguard Worker    def getManifestPath (self):
424*35238bceSAndroid Build Coastguard Worker        return [SourceRoot(), "android", self.appDirName, "AndroidManifest.xml"]
425*35238bceSAndroid Build Coastguard Worker
426*35238bceSAndroid Build Coastguard Worker    def getResPath (self):
427*35238bceSAndroid Build Coastguard Worker        return [SourceRoot(), "android", self.appDirName, "res"]
428*35238bceSAndroid Build Coastguard Worker
429*35238bceSAndroid Build Coastguard Worker    def getSourcePaths (self):
430*35238bceSAndroid Build Coastguard Worker        return [
431*35238bceSAndroid Build Coastguard Worker                [SourceRoot(), "android", self.appDirName, "src"]
432*35238bceSAndroid Build Coastguard Worker            ]
433*35238bceSAndroid Build Coastguard Worker
434*35238bceSAndroid Build Coastguard Worker    def getAssetsPath (self):
435*35238bceSAndroid Build Coastguard Worker        return [BuildRoot(), self.appDirName, "assets"]
436*35238bceSAndroid Build Coastguard Worker
437*35238bceSAndroid Build Coastguard Worker    def getClassesJarPath (self):
438*35238bceSAndroid Build Coastguard Worker        return [BuildRoot(), self.appDirName, "bin", "classes.jar"]
439*35238bceSAndroid Build Coastguard Worker
440*35238bceSAndroid Build Coastguard Worker    def getClassesDexDirectory (self):
441*35238bceSAndroid Build Coastguard Worker        return [BuildRoot(), self.appDirName, "bin",]
442*35238bceSAndroid Build Coastguard Worker
443*35238bceSAndroid Build Coastguard Worker    def getClassesDexPath (self):
444*35238bceSAndroid Build Coastguard Worker        return [BuildRoot(), self.appDirName, "bin", "classes.dex"]
445*35238bceSAndroid Build Coastguard Worker
446*35238bceSAndroid Build Coastguard Worker    def getAPKPath (self):
447*35238bceSAndroid Build Coastguard Worker        return [BuildRoot(), self.appDirName, "bin", self.appName + ".apk"]
448*35238bceSAndroid Build Coastguard Worker
449*35238bceSAndroid Build Coastguard Worker# Build step implementations
450*35238bceSAndroid Build Coastguard Worker
451*35238bceSAndroid Build Coastguard Workerclass BuildNativeLibrary (BuildStep):
452*35238bceSAndroid Build Coastguard Worker    def __init__ (self, abi):
453*35238bceSAndroid Build Coastguard Worker        self.abi = abi
454*35238bceSAndroid Build Coastguard Worker
455*35238bceSAndroid Build Coastguard Worker    def isUpToDate (self, config):
456*35238bceSAndroid Build Coastguard Worker        return False
457*35238bceSAndroid Build Coastguard Worker
458*35238bceSAndroid Build Coastguard Worker    def update (self, config):
459*35238bceSAndroid Build Coastguard Worker        log(config, "BuildNativeLibrary: %s" % self.abi)
460*35238bceSAndroid Build Coastguard Worker        buildNativeLibrary(config, self.abi)
461*35238bceSAndroid Build Coastguard Worker
462*35238bceSAndroid Build Coastguard Workerclass GenResourcesSrc (BuildStep):
463*35238bceSAndroid Build Coastguard Worker    def __init__ (self, package):
464*35238bceSAndroid Build Coastguard Worker        self.package = package
465*35238bceSAndroid Build Coastguard Worker
466*35238bceSAndroid Build Coastguard Worker    def getInputs (self):
467*35238bceSAndroid Build Coastguard Worker        return [self.package.getResPath(), self.package.getManifestPath()]
468*35238bceSAndroid Build Coastguard Worker
469*35238bceSAndroid Build Coastguard Worker    def getOutputs (self):
470*35238bceSAndroid Build Coastguard Worker        return [[GeneratedResSourcePath(self.package)]]
471*35238bceSAndroid Build Coastguard Worker
472*35238bceSAndroid Build Coastguard Worker    def update (self, config):
473*35238bceSAndroid Build Coastguard Worker        aaptPath = which("aapt", [config.env.sdk.getBuildToolsPath()])
474*35238bceSAndroid Build Coastguard Worker        dstDir = os.path.dirname(resolvePath(config, [GeneratedResSourcePath(self.package)]))
475*35238bceSAndroid Build Coastguard Worker
476*35238bceSAndroid Build Coastguard Worker        if not os.path.exists(dstDir):
477*35238bceSAndroid Build Coastguard Worker            os.makedirs(dstDir)
478*35238bceSAndroid Build Coastguard Worker
479*35238bceSAndroid Build Coastguard Worker        executeAndLog(config, [
480*35238bceSAndroid Build Coastguard Worker                aaptPath,
481*35238bceSAndroid Build Coastguard Worker                "package",
482*35238bceSAndroid Build Coastguard Worker                "-f",
483*35238bceSAndroid Build Coastguard Worker                "-m",
484*35238bceSAndroid Build Coastguard Worker                "-S", resolvePath(config, self.package.getResPath()),
485*35238bceSAndroid Build Coastguard Worker                "-M", resolvePath(config, self.package.getManifestPath()),
486*35238bceSAndroid Build Coastguard Worker                "-J", resolvePath(config, [BuildRoot(), self.package.getAppDirName(), "src"]),
487*35238bceSAndroid Build Coastguard Worker                "-I", config.env.sdk.getPlatformLibrary(config.javaApi)
488*35238bceSAndroid Build Coastguard Worker            ])
489*35238bceSAndroid Build Coastguard Worker
490*35238bceSAndroid Build Coastguard Worker# Builds classes.jar from *.java files
491*35238bceSAndroid Build Coastguard Workerclass BuildJavaSource (BuildStep):
492*35238bceSAndroid Build Coastguard Worker    def __init__ (self, package, libraries = []):
493*35238bceSAndroid Build Coastguard Worker        self.package = package
494*35238bceSAndroid Build Coastguard Worker        self.libraries = libraries
495*35238bceSAndroid Build Coastguard Worker
496*35238bceSAndroid Build Coastguard Worker    def getSourcePaths (self):
497*35238bceSAndroid Build Coastguard Worker        srcPaths = self.package.getSourcePaths()
498*35238bceSAndroid Build Coastguard Worker
499*35238bceSAndroid Build Coastguard Worker        if self.package.hasResources:
500*35238bceSAndroid Build Coastguard Worker            srcPaths.append([BuildRoot(), self.package.getAppDirName(), "src"]) # Generated sources
501*35238bceSAndroid Build Coastguard Worker
502*35238bceSAndroid Build Coastguard Worker        return srcPaths
503*35238bceSAndroid Build Coastguard Worker
504*35238bceSAndroid Build Coastguard Worker    def getInputs (self):
505*35238bceSAndroid Build Coastguard Worker        inputs = self.getSourcePaths()
506*35238bceSAndroid Build Coastguard Worker
507*35238bceSAndroid Build Coastguard Worker        for lib in self.libraries:
508*35238bceSAndroid Build Coastguard Worker            inputs.append(lib.getClassesJarPath())
509*35238bceSAndroid Build Coastguard Worker
510*35238bceSAndroid Build Coastguard Worker        return inputs
511*35238bceSAndroid Build Coastguard Worker
512*35238bceSAndroid Build Coastguard Worker    def getOutputs (self):
513*35238bceSAndroid Build Coastguard Worker        return [self.package.getClassesJarPath()]
514*35238bceSAndroid Build Coastguard Worker
515*35238bceSAndroid Build Coastguard Worker    def update (self, config):
516*35238bceSAndroid Build Coastguard Worker        srcPaths = resolvePaths(config, self.getSourcePaths())
517*35238bceSAndroid Build Coastguard Worker        srcFiles = BuildStep.expandPathsToFiles(srcPaths)
518*35238bceSAndroid Build Coastguard Worker        jarPath = resolvePath(config, self.package.getClassesJarPath())
519*35238bceSAndroid Build Coastguard Worker        objPath = resolvePath(config, [BuildRoot(), self.package.getAppDirName(), "obj"])
520*35238bceSAndroid Build Coastguard Worker        classPaths = [objPath] + [resolvePath(config, lib.getClassesJarPath()) for lib in self.libraries]
521*35238bceSAndroid Build Coastguard Worker        pathSep = ";" if HostInfo.getOs() == HostInfo.OS_WINDOWS else ":"
522*35238bceSAndroid Build Coastguard Worker
523*35238bceSAndroid Build Coastguard Worker        if os.path.exists(objPath):
524*35238bceSAndroid Build Coastguard Worker            shutil.rmtree(objPath)
525*35238bceSAndroid Build Coastguard Worker
526*35238bceSAndroid Build Coastguard Worker        os.makedirs(objPath)
527*35238bceSAndroid Build Coastguard Worker
528*35238bceSAndroid Build Coastguard Worker        for srcFile in srcFiles:
529*35238bceSAndroid Build Coastguard Worker            executeAndLog(config, [
530*35238bceSAndroid Build Coastguard Worker                    "javac",
531*35238bceSAndroid Build Coastguard Worker                    "-source", "1.7",
532*35238bceSAndroid Build Coastguard Worker                    "-target", "1.7",
533*35238bceSAndroid Build Coastguard Worker                    "-d", objPath,
534*35238bceSAndroid Build Coastguard Worker                    "-bootclasspath", config.env.sdk.getPlatformLibrary(config.javaApi),
535*35238bceSAndroid Build Coastguard Worker                    "-classpath", pathSep.join(classPaths),
536*35238bceSAndroid Build Coastguard Worker                    "-sourcepath", pathSep.join(srcPaths),
537*35238bceSAndroid Build Coastguard Worker                    srcFile
538*35238bceSAndroid Build Coastguard Worker                ])
539*35238bceSAndroid Build Coastguard Worker
540*35238bceSAndroid Build Coastguard Worker        if not os.path.exists(os.path.dirname(jarPath)):
541*35238bceSAndroid Build Coastguard Worker            os.makedirs(os.path.dirname(jarPath))
542*35238bceSAndroid Build Coastguard Worker
543*35238bceSAndroid Build Coastguard Worker        try:
544*35238bceSAndroid Build Coastguard Worker            pushWorkingDir(objPath)
545*35238bceSAndroid Build Coastguard Worker            executeAndLog(config, [
546*35238bceSAndroid Build Coastguard Worker                    "jar",
547*35238bceSAndroid Build Coastguard Worker                    "cf",
548*35238bceSAndroid Build Coastguard Worker                    jarPath,
549*35238bceSAndroid Build Coastguard Worker                    "."
550*35238bceSAndroid Build Coastguard Worker                ])
551*35238bceSAndroid Build Coastguard Worker        finally:
552*35238bceSAndroid Build Coastguard Worker            popWorkingDir()
553*35238bceSAndroid Build Coastguard Worker
554*35238bceSAndroid Build Coastguard Workerclass BuildDex (BuildStep):
555*35238bceSAndroid Build Coastguard Worker    def __init__ (self, package, libraries):
556*35238bceSAndroid Build Coastguard Worker        self.package = package
557*35238bceSAndroid Build Coastguard Worker        self.libraries = libraries
558*35238bceSAndroid Build Coastguard Worker
559*35238bceSAndroid Build Coastguard Worker    def getInputs (self):
560*35238bceSAndroid Build Coastguard Worker        return [self.package.getClassesJarPath()] + [lib.getClassesJarPath() for lib in self.libraries]
561*35238bceSAndroid Build Coastguard Worker
562*35238bceSAndroid Build Coastguard Worker    def getOutputs (self):
563*35238bceSAndroid Build Coastguard Worker        return [self.package.getClassesDexPath()]
564*35238bceSAndroid Build Coastguard Worker
565*35238bceSAndroid Build Coastguard Worker    def update (self, config):
566*35238bceSAndroid Build Coastguard Worker        dxPath = which(config.dCompilerName, [config.env.sdk.getBuildToolsPath()])
567*35238bceSAndroid Build Coastguard Worker        dexPath = resolvePath(config, self.package.getClassesDexDirectory())
568*35238bceSAndroid Build Coastguard Worker        jarPaths = [resolvePath(config, self.package.getClassesJarPath())]
569*35238bceSAndroid Build Coastguard Worker
570*35238bceSAndroid Build Coastguard Worker        for lib in self.libraries:
571*35238bceSAndroid Build Coastguard Worker            jarPaths.append(resolvePath(config, lib.getClassesJarPath()))
572*35238bceSAndroid Build Coastguard Worker
573*35238bceSAndroid Build Coastguard Worker        args = [ dxPath ]
574*35238bceSAndroid Build Coastguard Worker        if config.dCompilerName == "d8":
575*35238bceSAndroid Build Coastguard Worker            args.append("--lib")
576*35238bceSAndroid Build Coastguard Worker            args.append(config.env.sdk.getPlatformLibrary(config.javaApi))
577*35238bceSAndroid Build Coastguard Worker        else:
578*35238bceSAndroid Build Coastguard Worker            args.append("--dex")
579*35238bceSAndroid Build Coastguard Worker        args.append("--output")
580*35238bceSAndroid Build Coastguard Worker        args.append(dexPath)
581*35238bceSAndroid Build Coastguard Worker
582*35238bceSAndroid Build Coastguard Worker        executeAndLog(config, args + jarPaths)
583*35238bceSAndroid Build Coastguard Worker
584*35238bceSAndroid Build Coastguard Workerclass CreateKeystore (BuildStep):
585*35238bceSAndroid Build Coastguard Worker    def __init__ (self):
586*35238bceSAndroid Build Coastguard Worker        self.keystorePath = [BuildRoot(), "debug.keystore"]
587*35238bceSAndroid Build Coastguard Worker
588*35238bceSAndroid Build Coastguard Worker    def getOutputs (self):
589*35238bceSAndroid Build Coastguard Worker        return [self.keystorePath]
590*35238bceSAndroid Build Coastguard Worker
591*35238bceSAndroid Build Coastguard Worker    def isUpToDate (self, config):
592*35238bceSAndroid Build Coastguard Worker        return os.path.exists(resolvePath(config, self.keystorePath))
593*35238bceSAndroid Build Coastguard Worker
594*35238bceSAndroid Build Coastguard Worker    def update (self, config):
595*35238bceSAndroid Build Coastguard Worker        executeAndLog(config, [
596*35238bceSAndroid Build Coastguard Worker                "keytool",
597*35238bceSAndroid Build Coastguard Worker                "-genkeypair",
598*35238bceSAndroid Build Coastguard Worker                "-keystore", resolvePath(config, self.keystorePath),
599*35238bceSAndroid Build Coastguard Worker                "-storepass", "android",
600*35238bceSAndroid Build Coastguard Worker                "-alias", "androiddebugkey",
601*35238bceSAndroid Build Coastguard Worker                "-keypass", "android",
602*35238bceSAndroid Build Coastguard Worker                "-keyalg", "RSA",
603*35238bceSAndroid Build Coastguard Worker                "-keysize", "2048",
604*35238bceSAndroid Build Coastguard Worker                "-validity", "10000",
605*35238bceSAndroid Build Coastguard Worker                "-dname", "CN=, OU=, O=, L=, S=, C=",
606*35238bceSAndroid Build Coastguard Worker            ])
607*35238bceSAndroid Build Coastguard Worker
608*35238bceSAndroid Build Coastguard Worker# Builds APK without code
609*35238bceSAndroid Build Coastguard Workerclass BuildBaseAPK (BuildStep):
610*35238bceSAndroid Build Coastguard Worker    def __init__ (self, package, libraries = []):
611*35238bceSAndroid Build Coastguard Worker        self.package = package
612*35238bceSAndroid Build Coastguard Worker        self.libraries = libraries
613*35238bceSAndroid Build Coastguard Worker        self.dstPath = [BuildRoot(), self.package.getAppDirName(), "tmp", "base.apk"]
614*35238bceSAndroid Build Coastguard Worker
615*35238bceSAndroid Build Coastguard Worker    def getResPaths (self):
616*35238bceSAndroid Build Coastguard Worker        paths = []
617*35238bceSAndroid Build Coastguard Worker        for pkg in [self.package] + self.libraries:
618*35238bceSAndroid Build Coastguard Worker            if pkg.hasResources:
619*35238bceSAndroid Build Coastguard Worker                paths.append(pkg.getResPath())
620*35238bceSAndroid Build Coastguard Worker        return paths
621*35238bceSAndroid Build Coastguard Worker
622*35238bceSAndroid Build Coastguard Worker    def getInputs (self):
623*35238bceSAndroid Build Coastguard Worker        return [self.package.getManifestPath()] + self.getResPaths()
624*35238bceSAndroid Build Coastguard Worker
625*35238bceSAndroid Build Coastguard Worker    def getOutputs (self):
626*35238bceSAndroid Build Coastguard Worker        return [self.dstPath]
627*35238bceSAndroid Build Coastguard Worker
628*35238bceSAndroid Build Coastguard Worker    def update (self, config):
629*35238bceSAndroid Build Coastguard Worker        aaptPath = which("aapt", [config.env.sdk.getBuildToolsPath()])
630*35238bceSAndroid Build Coastguard Worker        dstPath = resolvePath(config, self.dstPath)
631*35238bceSAndroid Build Coastguard Worker
632*35238bceSAndroid Build Coastguard Worker        if not os.path.exists(os.path.dirname(dstPath)):
633*35238bceSAndroid Build Coastguard Worker            os.makedirs(os.path.dirname(dstPath))
634*35238bceSAndroid Build Coastguard Worker
635*35238bceSAndroid Build Coastguard Worker        args = [
636*35238bceSAndroid Build Coastguard Worker            aaptPath,
637*35238bceSAndroid Build Coastguard Worker            "package",
638*35238bceSAndroid Build Coastguard Worker            "-f",
639*35238bceSAndroid Build Coastguard Worker            "--min-sdk-version", str(config.minApi),
640*35238bceSAndroid Build Coastguard Worker            "--target-sdk-version", str(config.javaApi),
641*35238bceSAndroid Build Coastguard Worker            "-M", resolvePath(config, self.package.getManifestPath()),
642*35238bceSAndroid Build Coastguard Worker            "-I", config.env.sdk.getPlatformLibrary(config.javaApi),
643*35238bceSAndroid Build Coastguard Worker            "-F", dstPath,
644*35238bceSAndroid Build Coastguard Worker            "-0", "arsc" # arsc files need to be uncompressed for SDK version 30 and up
645*35238bceSAndroid Build Coastguard Worker        ]
646*35238bceSAndroid Build Coastguard Worker
647*35238bceSAndroid Build Coastguard Worker        for resPath in self.getResPaths():
648*35238bceSAndroid Build Coastguard Worker            args += ["-S", resolvePath(config, resPath)]
649*35238bceSAndroid Build Coastguard Worker
650*35238bceSAndroid Build Coastguard Worker        if config.verbose:
651*35238bceSAndroid Build Coastguard Worker            args.append("-v")
652*35238bceSAndroid Build Coastguard Worker
653*35238bceSAndroid Build Coastguard Worker        executeAndLog(config, args)
654*35238bceSAndroid Build Coastguard Worker
655*35238bceSAndroid Build Coastguard Workerdef addFilesToAPK (config, apkPath, baseDir, relFilePaths):
656*35238bceSAndroid Build Coastguard Worker    aaptPath = which("aapt", [config.env.sdk.getBuildToolsPath()])
657*35238bceSAndroid Build Coastguard Worker    maxBatchSize = 25
658*35238bceSAndroid Build Coastguard Worker
659*35238bceSAndroid Build Coastguard Worker    pushWorkingDir(baseDir)
660*35238bceSAndroid Build Coastguard Worker    try:
661*35238bceSAndroid Build Coastguard Worker        workQueue = list(relFilePaths)
662*35238bceSAndroid Build Coastguard Worker        # Workaround for Windows.
663*35238bceSAndroid Build Coastguard Worker        if os.path.sep == "\\":
664*35238bceSAndroid Build Coastguard Worker            workQueue = [i.replace("\\", "/") for i in workQueue]
665*35238bceSAndroid Build Coastguard Worker
666*35238bceSAndroid Build Coastguard Worker        while len(workQueue) > 0:
667*35238bceSAndroid Build Coastguard Worker            batchSize = min(len(workQueue), maxBatchSize)
668*35238bceSAndroid Build Coastguard Worker            items = workQueue[0:batchSize]
669*35238bceSAndroid Build Coastguard Worker
670*35238bceSAndroid Build Coastguard Worker            executeAndLog(config, [
671*35238bceSAndroid Build Coastguard Worker                    aaptPath,
672*35238bceSAndroid Build Coastguard Worker                    "add",
673*35238bceSAndroid Build Coastguard Worker                    "-f", apkPath,
674*35238bceSAndroid Build Coastguard Worker                ] + items)
675*35238bceSAndroid Build Coastguard Worker
676*35238bceSAndroid Build Coastguard Worker            del workQueue[0:batchSize]
677*35238bceSAndroid Build Coastguard Worker    finally:
678*35238bceSAndroid Build Coastguard Worker        popWorkingDir()
679*35238bceSAndroid Build Coastguard Worker
680*35238bceSAndroid Build Coastguard Workerdef addFileToAPK (config, apkPath, baseDir, relFilePath):
681*35238bceSAndroid Build Coastguard Worker    addFilesToAPK(config, apkPath, baseDir, [relFilePath])
682*35238bceSAndroid Build Coastguard Worker
683*35238bceSAndroid Build Coastguard Workerclass AddJavaToAPK (BuildStep):
684*35238bceSAndroid Build Coastguard Worker    def __init__ (self, package):
685*35238bceSAndroid Build Coastguard Worker        self.package = package
686*35238bceSAndroid Build Coastguard Worker        self.srcPath = BuildBaseAPK(self.package).getOutputs()[0]
687*35238bceSAndroid Build Coastguard Worker        self.dstPath = [BuildRoot(), self.package.getAppDirName(), "tmp", "with-java.apk"]
688*35238bceSAndroid Build Coastguard Worker
689*35238bceSAndroid Build Coastguard Worker    def getInputs (self):
690*35238bceSAndroid Build Coastguard Worker        return [
691*35238bceSAndroid Build Coastguard Worker                self.srcPath,
692*35238bceSAndroid Build Coastguard Worker                self.package.getClassesDexPath(),
693*35238bceSAndroid Build Coastguard Worker            ]
694*35238bceSAndroid Build Coastguard Worker
695*35238bceSAndroid Build Coastguard Worker    def getOutputs (self):
696*35238bceSAndroid Build Coastguard Worker        return [self.dstPath]
697*35238bceSAndroid Build Coastguard Worker
698*35238bceSAndroid Build Coastguard Worker    def update (self, config):
699*35238bceSAndroid Build Coastguard Worker        srcPath = resolvePath(config, self.srcPath)
700*35238bceSAndroid Build Coastguard Worker        dstPath = resolvePath(config, self.getOutputs()[0])
701*35238bceSAndroid Build Coastguard Worker        dexPath = resolvePath(config, self.package.getClassesDexPath())
702*35238bceSAndroid Build Coastguard Worker
703*35238bceSAndroid Build Coastguard Worker        shutil.copyfile(srcPath, dstPath)
704*35238bceSAndroid Build Coastguard Worker        addFileToAPK(config, dstPath, os.path.dirname(dexPath), os.path.basename(dexPath))
705*35238bceSAndroid Build Coastguard Worker
706*35238bceSAndroid Build Coastguard Workerclass AddAssetsToAPK (BuildStep):
707*35238bceSAndroid Build Coastguard Worker    def __init__ (self, package, abi):
708*35238bceSAndroid Build Coastguard Worker        self.package = package
709*35238bceSAndroid Build Coastguard Worker        self.buildPath = [NativeBuildPath(abi)]
710*35238bceSAndroid Build Coastguard Worker        self.srcPath = AddJavaToAPK(self.package).getOutputs()[0]
711*35238bceSAndroid Build Coastguard Worker        self.dstPath = [BuildRoot(), self.package.getAppDirName(), "tmp", "with-assets.apk"]
712*35238bceSAndroid Build Coastguard Worker
713*35238bceSAndroid Build Coastguard Worker    def getInputs (self):
714*35238bceSAndroid Build Coastguard Worker        return [
715*35238bceSAndroid Build Coastguard Worker                self.srcPath,
716*35238bceSAndroid Build Coastguard Worker                self.buildPath + ["assets"]
717*35238bceSAndroid Build Coastguard Worker            ]
718*35238bceSAndroid Build Coastguard Worker
719*35238bceSAndroid Build Coastguard Worker    def getOutputs (self):
720*35238bceSAndroid Build Coastguard Worker        return [self.dstPath]
721*35238bceSAndroid Build Coastguard Worker
722*35238bceSAndroid Build Coastguard Worker    @staticmethod
723*35238bceSAndroid Build Coastguard Worker    def getAssetFiles (buildPath):
724*35238bceSAndroid Build Coastguard Worker        allFiles = BuildStep.expandPathsToFiles([os.path.join(buildPath, "assets")])
725*35238bceSAndroid Build Coastguard Worker        return [os.path.relpath(p, buildPath) for p in allFiles]
726*35238bceSAndroid Build Coastguard Worker
727*35238bceSAndroid Build Coastguard Worker    def update (self, config):
728*35238bceSAndroid Build Coastguard Worker        srcPath = resolvePath(config, self.srcPath)
729*35238bceSAndroid Build Coastguard Worker        dstPath = resolvePath(config, self.getOutputs()[0])
730*35238bceSAndroid Build Coastguard Worker        buildPath = resolvePath(config, self.buildPath)
731*35238bceSAndroid Build Coastguard Worker        assetFiles = AddAssetsToAPK.getAssetFiles(buildPath)
732*35238bceSAndroid Build Coastguard Worker
733*35238bceSAndroid Build Coastguard Worker        shutil.copyfile(srcPath, dstPath)
734*35238bceSAndroid Build Coastguard Worker
735*35238bceSAndroid Build Coastguard Worker        addFilesToAPK(config, dstPath, buildPath, assetFiles)
736*35238bceSAndroid Build Coastguard Worker
737*35238bceSAndroid Build Coastguard Workerclass AddNativeLibsToAPK (BuildStep):
738*35238bceSAndroid Build Coastguard Worker    def __init__ (self, package, abis):
739*35238bceSAndroid Build Coastguard Worker        self.package = package
740*35238bceSAndroid Build Coastguard Worker        self.abis = abis
741*35238bceSAndroid Build Coastguard Worker        self.srcPath = AddAssetsToAPK(self.package, "").getOutputs()[0]
742*35238bceSAndroid Build Coastguard Worker        self.dstPath = [BuildRoot(), self.package.getAppDirName(), "tmp", "with-native-libs.apk"]
743*35238bceSAndroid Build Coastguard Worker
744*35238bceSAndroid Build Coastguard Worker    def getInputs (self):
745*35238bceSAndroid Build Coastguard Worker        paths = [self.srcPath]
746*35238bceSAndroid Build Coastguard Worker        for abi in self.abis:
747*35238bceSAndroid Build Coastguard Worker            paths.append([NativeBuildPath(abi), "libdeqp.so"])
748*35238bceSAndroid Build Coastguard Worker        return paths
749*35238bceSAndroid Build Coastguard Worker
750*35238bceSAndroid Build Coastguard Worker    def getOutputs (self):
751*35238bceSAndroid Build Coastguard Worker        return [self.dstPath]
752*35238bceSAndroid Build Coastguard Worker
753*35238bceSAndroid Build Coastguard Worker    def update (self, config):
754*35238bceSAndroid Build Coastguard Worker        srcPath = resolvePath(config, self.srcPath)
755*35238bceSAndroid Build Coastguard Worker        dstPath = resolvePath(config, self.getOutputs()[0])
756*35238bceSAndroid Build Coastguard Worker        pkgPath = resolvePath(config, [BuildRoot(), self.package.getAppDirName()])
757*35238bceSAndroid Build Coastguard Worker        libFiles = []
758*35238bceSAndroid Build Coastguard Worker
759*35238bceSAndroid Build Coastguard Worker        # Create right directory structure first
760*35238bceSAndroid Build Coastguard Worker        for abi in self.abis:
761*35238bceSAndroid Build Coastguard Worker            libSrcPath = resolvePath(config, [NativeBuildPath(abi), "libdeqp.so"])
762*35238bceSAndroid Build Coastguard Worker            libRelPath = os.path.join("lib", abi, "libdeqp.so")
763*35238bceSAndroid Build Coastguard Worker            libAbsPath = os.path.join(pkgPath, libRelPath)
764*35238bceSAndroid Build Coastguard Worker
765*35238bceSAndroid Build Coastguard Worker            if not os.path.exists(os.path.dirname(libAbsPath)):
766*35238bceSAndroid Build Coastguard Worker                os.makedirs(os.path.dirname(libAbsPath))
767*35238bceSAndroid Build Coastguard Worker
768*35238bceSAndroid Build Coastguard Worker            shutil.copyfile(libSrcPath, libAbsPath)
769*35238bceSAndroid Build Coastguard Worker            libFiles.append(libRelPath)
770*35238bceSAndroid Build Coastguard Worker
771*35238bceSAndroid Build Coastguard Worker            if config.layers:
772*35238bceSAndroid Build Coastguard Worker                # Need to copy everything in the layer folder
773*35238bceSAndroid Build Coastguard Worker                layersGlob = os.path.join(config.layers, abi, "*")
774*35238bceSAndroid Build Coastguard Worker                libVkLayers = glob.glob(layersGlob)
775*35238bceSAndroid Build Coastguard Worker                for layer in libVkLayers:
776*35238bceSAndroid Build Coastguard Worker                    layerFilename = os.path.basename(layer)
777*35238bceSAndroid Build Coastguard Worker                    layerRelPath = os.path.join("lib", abi, layerFilename)
778*35238bceSAndroid Build Coastguard Worker                    layerAbsPath = os.path.join(pkgPath, layerRelPath)
779*35238bceSAndroid Build Coastguard Worker                    shutil.copyfile(layer, layerAbsPath)
780*35238bceSAndroid Build Coastguard Worker                    libFiles.append(layerRelPath)
781*35238bceSAndroid Build Coastguard Worker                    print("Adding layer binary: %s" % (layer,))
782*35238bceSAndroid Build Coastguard Worker
783*35238bceSAndroid Build Coastguard Worker            if config.angle:
784*35238bceSAndroid Build Coastguard Worker                angleGlob = os.path.join(config.angle, abi, "lib*_angle.so")
785*35238bceSAndroid Build Coastguard Worker                libAngle = glob.glob(angleGlob)
786*35238bceSAndroid Build Coastguard Worker                for lib in libAngle:
787*35238bceSAndroid Build Coastguard Worker                    libFilename = os.path.basename(lib)
788*35238bceSAndroid Build Coastguard Worker                    libRelPath = os.path.join("lib", abi, libFilename)
789*35238bceSAndroid Build Coastguard Worker                    libAbsPath = os.path.join(pkgPath, libRelPath)
790*35238bceSAndroid Build Coastguard Worker                    shutil.copyfile(lib, libAbsPath)
791*35238bceSAndroid Build Coastguard Worker                    libFiles.append(libRelPath)
792*35238bceSAndroid Build Coastguard Worker                    print("Adding ANGLE binary: %s" % (lib,))
793*35238bceSAndroid Build Coastguard Worker
794*35238bceSAndroid Build Coastguard Worker        shutil.copyfile(srcPath, dstPath)
795*35238bceSAndroid Build Coastguard Worker        addFilesToAPK(config, dstPath, pkgPath, libFiles)
796*35238bceSAndroid Build Coastguard Worker
797*35238bceSAndroid Build Coastguard Workerclass SignAPK (BuildStep):
798*35238bceSAndroid Build Coastguard Worker    def __init__ (self, package):
799*35238bceSAndroid Build Coastguard Worker        self.package = package
800*35238bceSAndroid Build Coastguard Worker        self.srcPath = AlignAPK(self.package).getOutputs()[0]
801*35238bceSAndroid Build Coastguard Worker        self.dstPath = [BuildRoot(), getBuildRootRelativeAPKPath(self.package)]
802*35238bceSAndroid Build Coastguard Worker        self.keystorePath = CreateKeystore().getOutputs()[0]
803*35238bceSAndroid Build Coastguard Worker
804*35238bceSAndroid Build Coastguard Worker    def getInputs (self):
805*35238bceSAndroid Build Coastguard Worker        return [self.srcPath, self.keystorePath]
806*35238bceSAndroid Build Coastguard Worker
807*35238bceSAndroid Build Coastguard Worker    def getOutputs (self):
808*35238bceSAndroid Build Coastguard Worker        return [self.dstPath]
809*35238bceSAndroid Build Coastguard Worker
810*35238bceSAndroid Build Coastguard Worker    def update (self, config):
811*35238bceSAndroid Build Coastguard Worker        apksigner = which("apksigner", [config.env.sdk.getBuildToolsPath()])
812*35238bceSAndroid Build Coastguard Worker        srcPath = resolvePath(config, self.srcPath)
813*35238bceSAndroid Build Coastguard Worker        dstPath = resolvePath(config, self.dstPath)
814*35238bceSAndroid Build Coastguard Worker
815*35238bceSAndroid Build Coastguard Worker        executeAndLog(config, [
816*35238bceSAndroid Build Coastguard Worker                apksigner,
817*35238bceSAndroid Build Coastguard Worker                "sign",
818*35238bceSAndroid Build Coastguard Worker                "--ks", resolvePath(config, self.keystorePath),
819*35238bceSAndroid Build Coastguard Worker                "--ks-key-alias", "androiddebugkey",
820*35238bceSAndroid Build Coastguard Worker                "--ks-pass", "pass:android",
821*35238bceSAndroid Build Coastguard Worker                "--key-pass", "pass:android",
822*35238bceSAndroid Build Coastguard Worker                "--min-sdk-version", str(config.minApi),
823*35238bceSAndroid Build Coastguard Worker                "--max-sdk-version", str(config.javaApi),
824*35238bceSAndroid Build Coastguard Worker                "--out", dstPath,
825*35238bceSAndroid Build Coastguard Worker                srcPath
826*35238bceSAndroid Build Coastguard Worker            ])
827*35238bceSAndroid Build Coastguard Worker
828*35238bceSAndroid Build Coastguard Workerdef getBuildRootRelativeAPKPath (package):
829*35238bceSAndroid Build Coastguard Worker    return os.path.join(package.getAppDirName(), package.getAppName() + ".apk")
830*35238bceSAndroid Build Coastguard Worker
831*35238bceSAndroid Build Coastguard Workerclass AlignAPK (BuildStep):
832*35238bceSAndroid Build Coastguard Worker    def __init__ (self, package):
833*35238bceSAndroid Build Coastguard Worker        self.package = package
834*35238bceSAndroid Build Coastguard Worker        self.srcPath = AddNativeLibsToAPK(self.package, []).getOutputs()[0]
835*35238bceSAndroid Build Coastguard Worker        self.dstPath = [BuildRoot(), self.package.getAppDirName(), "tmp", "aligned.apk"]
836*35238bceSAndroid Build Coastguard Worker        self.keystorePath = CreateKeystore().getOutputs()[0]
837*35238bceSAndroid Build Coastguard Worker
838*35238bceSAndroid Build Coastguard Worker    def getInputs (self):
839*35238bceSAndroid Build Coastguard Worker        return [self.srcPath]
840*35238bceSAndroid Build Coastguard Worker
841*35238bceSAndroid Build Coastguard Worker    def getOutputs (self):
842*35238bceSAndroid Build Coastguard Worker        return [self.dstPath]
843*35238bceSAndroid Build Coastguard Worker
844*35238bceSAndroid Build Coastguard Worker    def update (self, config):
845*35238bceSAndroid Build Coastguard Worker        srcPath = resolvePath(config, self.srcPath)
846*35238bceSAndroid Build Coastguard Worker        dstPath = resolvePath(config, self.dstPath)
847*35238bceSAndroid Build Coastguard Worker        zipalignPath = os.path.join(config.env.sdk.getBuildToolsPath(), "zipalign")
848*35238bceSAndroid Build Coastguard Worker
849*35238bceSAndroid Build Coastguard Worker        executeAndLog(config, [
850*35238bceSAndroid Build Coastguard Worker                zipalignPath,
851*35238bceSAndroid Build Coastguard Worker                "-f", "4",
852*35238bceSAndroid Build Coastguard Worker                srcPath,
853*35238bceSAndroid Build Coastguard Worker                dstPath
854*35238bceSAndroid Build Coastguard Worker            ])
855*35238bceSAndroid Build Coastguard Worker
856*35238bceSAndroid Build Coastguard Workerdef getBuildStepsForPackage (abis, package, libraries = []):
857*35238bceSAndroid Build Coastguard Worker    steps = []
858*35238bceSAndroid Build Coastguard Worker
859*35238bceSAndroid Build Coastguard Worker    assert len(abis) > 0
860*35238bceSAndroid Build Coastguard Worker
861*35238bceSAndroid Build Coastguard Worker    # Build native code first
862*35238bceSAndroid Build Coastguard Worker    for abi in abis:
863*35238bceSAndroid Build Coastguard Worker        steps += [BuildNativeLibrary(abi)]
864*35238bceSAndroid Build Coastguard Worker
865*35238bceSAndroid Build Coastguard Worker    # Build library packages
866*35238bceSAndroid Build Coastguard Worker    for library in libraries:
867*35238bceSAndroid Build Coastguard Worker        if library.hasResources:
868*35238bceSAndroid Build Coastguard Worker            steps.append(GenResourcesSrc(library))
869*35238bceSAndroid Build Coastguard Worker        steps.append(BuildJavaSource(library))
870*35238bceSAndroid Build Coastguard Worker
871*35238bceSAndroid Build Coastguard Worker    # Build main package .java sources
872*35238bceSAndroid Build Coastguard Worker    if package.hasResources:
873*35238bceSAndroid Build Coastguard Worker        steps.append(GenResourcesSrc(package))
874*35238bceSAndroid Build Coastguard Worker    steps.append(BuildJavaSource(package, libraries))
875*35238bceSAndroid Build Coastguard Worker    steps.append(BuildDex(package, libraries))
876*35238bceSAndroid Build Coastguard Worker
877*35238bceSAndroid Build Coastguard Worker    # Build base APK
878*35238bceSAndroid Build Coastguard Worker    steps.append(BuildBaseAPK(package, libraries))
879*35238bceSAndroid Build Coastguard Worker    steps.append(AddJavaToAPK(package))
880*35238bceSAndroid Build Coastguard Worker
881*35238bceSAndroid Build Coastguard Worker    # Add assets from first ABI
882*35238bceSAndroid Build Coastguard Worker    steps.append(AddAssetsToAPK(package, abis[0]))
883*35238bceSAndroid Build Coastguard Worker
884*35238bceSAndroid Build Coastguard Worker    # Add native libs to APK
885*35238bceSAndroid Build Coastguard Worker    steps.append(AddNativeLibsToAPK(package, abis))
886*35238bceSAndroid Build Coastguard Worker
887*35238bceSAndroid Build Coastguard Worker    # Finalize APK
888*35238bceSAndroid Build Coastguard Worker    steps.append(CreateKeystore())
889*35238bceSAndroid Build Coastguard Worker    steps.append(AlignAPK(package))
890*35238bceSAndroid Build Coastguard Worker    steps.append(SignAPK(package))
891*35238bceSAndroid Build Coastguard Worker
892*35238bceSAndroid Build Coastguard Worker    return steps
893*35238bceSAndroid Build Coastguard Worker
894*35238bceSAndroid Build Coastguard Workerdef getPackageAndLibrariesForTarget (target):
895*35238bceSAndroid Build Coastguard Worker    deqpPackage = PackageDescription("package", "dEQP")
896*35238bceSAndroid Build Coastguard Worker    ctsPackage = PackageDescription("openglcts", "Khronos-CTS", hasResources = False)
897*35238bceSAndroid Build Coastguard Worker
898*35238bceSAndroid Build Coastguard Worker    if target == 'deqp':
899*35238bceSAndroid Build Coastguard Worker        return (deqpPackage, [])
900*35238bceSAndroid Build Coastguard Worker    elif target == 'openglcts':
901*35238bceSAndroid Build Coastguard Worker        return (ctsPackage, [deqpPackage])
902*35238bceSAndroid Build Coastguard Worker    else:
903*35238bceSAndroid Build Coastguard Worker        raise Exception("Uknown target '%s'" % target)
904*35238bceSAndroid Build Coastguard Worker
905*35238bceSAndroid Build Coastguard Workerdef findNDK ():
906*35238bceSAndroid Build Coastguard Worker    ndkBuildPath = which('ndk-build')
907*35238bceSAndroid Build Coastguard Worker    if ndkBuildPath != None:
908*35238bceSAndroid Build Coastguard Worker        return os.path.dirname(ndkBuildPath)
909*35238bceSAndroid Build Coastguard Worker    else:
910*35238bceSAndroid Build Coastguard Worker        return None
911*35238bceSAndroid Build Coastguard Worker
912*35238bceSAndroid Build Coastguard Workerdef findSDK ():
913*35238bceSAndroid Build Coastguard Worker    sdkBuildPath = which('android')
914*35238bceSAndroid Build Coastguard Worker    if sdkBuildPath != None:
915*35238bceSAndroid Build Coastguard Worker        return os.path.dirname(os.path.dirname(sdkBuildPath))
916*35238bceSAndroid Build Coastguard Worker    else:
917*35238bceSAndroid Build Coastguard Worker        return None
918*35238bceSAndroid Build Coastguard Worker
919*35238bceSAndroid Build Coastguard Workerdef getDefaultBuildRoot ():
920*35238bceSAndroid Build Coastguard Worker    return os.path.join(tempfile.gettempdir(), "deqp-android-build")
921*35238bceSAndroid Build Coastguard Worker
922*35238bceSAndroid Build Coastguard Workerdef parseArgs ():
923*35238bceSAndroid Build Coastguard Worker    nativeBuildTypes = ['Release', 'Debug', 'MinSizeRel', 'RelWithAsserts', 'RelWithDebInfo']
924*35238bceSAndroid Build Coastguard Worker    defaultNDKPath = findNDK()
925*35238bceSAndroid Build Coastguard Worker    defaultSDKPath = findSDK()
926*35238bceSAndroid Build Coastguard Worker    defaultBuildRoot = getDefaultBuildRoot()
927*35238bceSAndroid Build Coastguard Worker
928*35238bceSAndroid Build Coastguard Worker    parser = argparse.ArgumentParser(os.path.basename(__file__),
929*35238bceSAndroid Build Coastguard Worker        formatter_class=argparse.ArgumentDefaultsHelpFormatter)
930*35238bceSAndroid Build Coastguard Worker    parser.add_argument('--native-build-type',
931*35238bceSAndroid Build Coastguard Worker        dest='nativeBuildType',
932*35238bceSAndroid Build Coastguard Worker        default="RelWithAsserts",
933*35238bceSAndroid Build Coastguard Worker        choices=nativeBuildTypes,
934*35238bceSAndroid Build Coastguard Worker        help="Native code build type")
935*35238bceSAndroid Build Coastguard Worker    parser.add_argument('--build-root',
936*35238bceSAndroid Build Coastguard Worker        dest='buildRoot',
937*35238bceSAndroid Build Coastguard Worker        default=defaultBuildRoot,
938*35238bceSAndroid Build Coastguard Worker        help="Root build directory")
939*35238bceSAndroid Build Coastguard Worker    parser.add_argument('--abis',
940*35238bceSAndroid Build Coastguard Worker        dest='abis',
941*35238bceSAndroid Build Coastguard Worker        default=",".join(NDKEnv.getKnownAbis()),
942*35238bceSAndroid Build Coastguard Worker        help="ABIs to build")
943*35238bceSAndroid Build Coastguard Worker    parser.add_argument('--native-api',
944*35238bceSAndroid Build Coastguard Worker        type=int,
945*35238bceSAndroid Build Coastguard Worker        dest='nativeApi',
946*35238bceSAndroid Build Coastguard Worker        default=28,
947*35238bceSAndroid Build Coastguard Worker        help="Android API level to target in native code")
948*35238bceSAndroid Build Coastguard Worker    parser.add_argument('--java-api',
949*35238bceSAndroid Build Coastguard Worker        type=int,
950*35238bceSAndroid Build Coastguard Worker        dest='javaApi',
951*35238bceSAndroid Build Coastguard Worker        default=28,
952*35238bceSAndroid Build Coastguard Worker        help="Android API level to target in Java code")
953*35238bceSAndroid Build Coastguard Worker    parser.add_argument('--tool-api',
954*35238bceSAndroid Build Coastguard Worker        type=int,
955*35238bceSAndroid Build Coastguard Worker        dest='toolApi',
956*35238bceSAndroid Build Coastguard Worker        default=-1,
957*35238bceSAndroid Build Coastguard Worker        help="Android Tools level to target (-1 being maximum present)")
958*35238bceSAndroid Build Coastguard Worker    parser.add_argument('--min-api',
959*35238bceSAndroid Build Coastguard Worker        type=int,
960*35238bceSAndroid Build Coastguard Worker        dest='minApi',
961*35238bceSAndroid Build Coastguard Worker        default=22,
962*35238bceSAndroid Build Coastguard Worker        help="Minimum Android API level for which the APK can be installed")
963*35238bceSAndroid Build Coastguard Worker    parser.add_argument('--sdk',
964*35238bceSAndroid Build Coastguard Worker        dest='sdkPath',
965*35238bceSAndroid Build Coastguard Worker        default=defaultSDKPath,
966*35238bceSAndroid Build Coastguard Worker        help="Android SDK path",
967*35238bceSAndroid Build Coastguard Worker        required=(True if defaultSDKPath == None else False))
968*35238bceSAndroid Build Coastguard Worker    parser.add_argument('--ndk',
969*35238bceSAndroid Build Coastguard Worker        dest='ndkPath',
970*35238bceSAndroid Build Coastguard Worker        default=defaultNDKPath,
971*35238bceSAndroid Build Coastguard Worker        help="Android NDK path",
972*35238bceSAndroid Build Coastguard Worker        required=(True if defaultNDKPath == None else False))
973*35238bceSAndroid Build Coastguard Worker    parser.add_argument('-v', '--verbose',
974*35238bceSAndroid Build Coastguard Worker        dest='verbose',
975*35238bceSAndroid Build Coastguard Worker        help="Verbose output",
976*35238bceSAndroid Build Coastguard Worker        default=False,
977*35238bceSAndroid Build Coastguard Worker        action='store_true')
978*35238bceSAndroid Build Coastguard Worker    parser.add_argument('--target',
979*35238bceSAndroid Build Coastguard Worker        dest='target',
980*35238bceSAndroid Build Coastguard Worker        help='Build target',
981*35238bceSAndroid Build Coastguard Worker        choices=['deqp', 'openglcts'],
982*35238bceSAndroid Build Coastguard Worker        default='deqp')
983*35238bceSAndroid Build Coastguard Worker    parser.add_argument('--kc-cts-target',
984*35238bceSAndroid Build Coastguard Worker        dest='gtfTarget',
985*35238bceSAndroid Build Coastguard Worker        default='gles32',
986*35238bceSAndroid Build Coastguard Worker        choices=['gles32', 'gles31', 'gles3', 'gles2', 'gl'],
987*35238bceSAndroid Build Coastguard Worker        help="KC-CTS (GTF) target API (only used in openglcts target)")
988*35238bceSAndroid Build Coastguard Worker    parser.add_argument('--layers-path',
989*35238bceSAndroid Build Coastguard Worker        dest='layers',
990*35238bceSAndroid Build Coastguard Worker        default=None,
991*35238bceSAndroid Build Coastguard Worker        required=False)
992*35238bceSAndroid Build Coastguard Worker    parser.add_argument('--angle-path',
993*35238bceSAndroid Build Coastguard Worker        dest='angle',
994*35238bceSAndroid Build Coastguard Worker        default=None,
995*35238bceSAndroid Build Coastguard Worker        required=False)
996*35238bceSAndroid Build Coastguard Worker
997*35238bceSAndroid Build Coastguard Worker    args = parser.parse_args()
998*35238bceSAndroid Build Coastguard Worker
999*35238bceSAndroid Build Coastguard Worker    def parseAbis (abisStr):
1000*35238bceSAndroid Build Coastguard Worker        knownAbis = set(NDKEnv.getKnownAbis())
1001*35238bceSAndroid Build Coastguard Worker        abis = []
1002*35238bceSAndroid Build Coastguard Worker
1003*35238bceSAndroid Build Coastguard Worker        for abi in abisStr.split(','):
1004*35238bceSAndroid Build Coastguard Worker            abi = abi.strip()
1005*35238bceSAndroid Build Coastguard Worker            if not abi in knownAbis:
1006*35238bceSAndroid Build Coastguard Worker                raise Exception("Unknown ABI: %s" % abi)
1007*35238bceSAndroid Build Coastguard Worker            abis.append(abi)
1008*35238bceSAndroid Build Coastguard Worker
1009*35238bceSAndroid Build Coastguard Worker        return abis
1010*35238bceSAndroid Build Coastguard Worker
1011*35238bceSAndroid Build Coastguard Worker    # Custom parsing & checks
1012*35238bceSAndroid Build Coastguard Worker    try:
1013*35238bceSAndroid Build Coastguard Worker        args.abis = parseAbis(args.abis)
1014*35238bceSAndroid Build Coastguard Worker        if len(args.abis) == 0:
1015*35238bceSAndroid Build Coastguard Worker            raise Exception("--abis can't be empty")
1016*35238bceSAndroid Build Coastguard Worker    except Exception as e:
1017*35238bceSAndroid Build Coastguard Worker        print("ERROR: %s" % str(e))
1018*35238bceSAndroid Build Coastguard Worker        parser.print_help()
1019*35238bceSAndroid Build Coastguard Worker        sys.exit(-1)
1020*35238bceSAndroid Build Coastguard Worker
1021*35238bceSAndroid Build Coastguard Worker    return args
1022*35238bceSAndroid Build Coastguard Worker
1023*35238bceSAndroid Build Coastguard Workerif __name__ == "__main__":
1024*35238bceSAndroid Build Coastguard Worker    args = parseArgs()
1025*35238bceSAndroid Build Coastguard Worker
1026*35238bceSAndroid Build Coastguard Worker    ndk = NDKEnv(os.path.realpath(args.ndkPath))
1027*35238bceSAndroid Build Coastguard Worker    sdk = SDKEnv(os.path.realpath(args.sdkPath), args.toolApi)
1028*35238bceSAndroid Build Coastguard Worker    buildPath = os.path.realpath(args.buildRoot)
1029*35238bceSAndroid Build Coastguard Worker    env = Environment(sdk, ndk)
1030*35238bceSAndroid Build Coastguard Worker    config = Configuration(env, buildPath, abis=args.abis, nativeApi=args.nativeApi, javaApi=args.javaApi, minApi=args.minApi, nativeBuildType=args.nativeBuildType, gtfTarget=args.gtfTarget,
1031*35238bceSAndroid Build Coastguard Worker                         verbose=args.verbose, layers=args.layers, angle=args.angle)
1032*35238bceSAndroid Build Coastguard Worker
1033*35238bceSAndroid Build Coastguard Worker    try:
1034*35238bceSAndroid Build Coastguard Worker        config.check()
1035*35238bceSAndroid Build Coastguard Worker    except Exception as e:
1036*35238bceSAndroid Build Coastguard Worker        print("ERROR: %s" % str(e))
1037*35238bceSAndroid Build Coastguard Worker        print("")
1038*35238bceSAndroid Build Coastguard Worker        print("Please check your configuration:")
1039*35238bceSAndroid Build Coastguard Worker        print("  --sdk=%s" % args.sdkPath)
1040*35238bceSAndroid Build Coastguard Worker        print("  --ndk=%s" % args.ndkPath)
1041*35238bceSAndroid Build Coastguard Worker        sys.exit(-1)
1042*35238bceSAndroid Build Coastguard Worker
1043*35238bceSAndroid Build Coastguard Worker    pkg, libs = getPackageAndLibrariesForTarget(args.target)
1044*35238bceSAndroid Build Coastguard Worker    steps = getBuildStepsForPackage(config.abis, pkg, libs)
1045*35238bceSAndroid Build Coastguard Worker
1046*35238bceSAndroid Build Coastguard Worker    executeSteps(config, steps)
1047*35238bceSAndroid Build Coastguard Worker
1048*35238bceSAndroid Build Coastguard Worker    print("")
1049*35238bceSAndroid Build Coastguard Worker    print("Built %s" % os.path.join(buildPath, getBuildRootRelativeAPKPath(pkg)))
1050