Postpone .amber file parsing
[platform/upstream/VK-GL-CTS.git] / scripts / check_build_sanity.py
1 # -*- coding: utf-8 -*-
2
3 #-------------------------------------------------------------------------
4 # drawElements Quality Program utilities
5 # --------------------------------------
6 #
7 # Copyright 2016 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 argparse
25 import tempfile
26 import sys
27
28 from build.common import *
29 from build.build import *
30
31 pythonExecutable = sys.executable or "python"
32
33 class Environment:
34         def __init__ (self, srcDir, tmpDir):
35                 self.srcDir     = srcDir
36                 self.tmpDir     = tmpDir
37
38 class BuildTestStep:
39         def getName (self):
40                 return "<unknown>"
41
42         def isAvailable (self, env):
43                 return True
44
45         def run (self, env):
46                 raise Exception("Not implemented")
47
48 class RunScript(BuildTestStep):
49         def __init__ (self, scriptPath, getExtraArgs = None):
50                 self.scriptPath         = scriptPath
51                 self.getExtraArgs       = getExtraArgs
52
53         def getName (self):
54                 return self.scriptPath
55
56         def run (self, env):
57                 args = [pythonExecutable, os.path.join(env.srcDir, self.scriptPath)]
58
59                 if self.getExtraArgs != None:
60                         args += self.getExtraArgs(env)
61
62                 execute(args)
63
64 def makeCflagsArgs (cflags):
65         cflagsStr = " ".join(cflags)
66         return ["-DCMAKE_C_FLAGS=%s" % cflagsStr, "-DCMAKE_CXX_FLAGS=%s" % cflagsStr]
67
68 def makeBuildArgs (target, cc, cpp, cflags):
69         return ["-DDEQP_TARGET=%s" % target, "-DCMAKE_C_COMPILER=%s" % cc, "-DCMAKE_CXX_COMPILER=%s" % cpp] + makeCflagsArgs(cflags)
70
71 class BuildConfigGen:
72         def isAvailable (self, env):
73                 return True
74
75 class UnixConfig(BuildConfigGen):
76         def __init__ (self, target, buildType, cc, cpp, cflags):
77                 self.target             = target
78                 self.buildType  = buildType
79                 self.cc                 = cc
80                 self.cpp                = cpp
81                 self.cflags             = cflags
82
83         def isAvailable (self, env):
84                 return which(self.cc) != None and which(self.cpp) != None
85
86         def getBuildConfig (self, env, buildDir):
87                 args = makeBuildArgs(self.target, self.cc, self.cpp, self.cflags)
88                 return BuildConfig(buildDir, self.buildType, args, env.srcDir)
89
90 class VSConfig(BuildConfigGen):
91         def __init__ (self, buildType):
92                 self.buildType = buildType
93
94         def getBuildConfig (self, env, buildDir):
95                 args = ["-DCMAKE_C_FLAGS=/WX -DCMAKE_CXX_FLAGS=/WX"]
96                 return BuildConfig(buildDir, self.buildType, args, env.srcDir)
97
98 class Build(BuildTestStep):
99         def __init__ (self, buildDir, configGen, generator):
100                 self.buildDir   = buildDir
101                 self.configGen  = configGen
102                 self.generator  = generator
103
104         def getName (self):
105                 return self.buildDir
106
107         def isAvailable (self, env):
108                 return self.configGen.isAvailable(env) and self.generator != None and self.generator.isAvailable()
109
110         def run (self, env):
111                 # specialize config for env
112                 buildDir        = os.path.join(env.tmpDir, self.buildDir)
113                 curConfig       = self.configGen.getBuildConfig(env, buildDir)
114
115                 build(curConfig, self.generator)
116
117 class CheckSrcChanges(BuildTestStep):
118         def getName (self):
119                 return "check for changes"
120
121         def run (self, env):
122                 pushWorkingDir(env.srcDir)
123                 execute(["git", "diff", "--exit-code"])
124                 popWorkingDir()
125
126 def getClangVersion ():
127         knownVersions = ["4.0", "3.9", "3.8", "3.7", "3.6", "3.5"]
128         for version in knownVersions:
129                 if which("clang-" + version) != None:
130                         return "-" + version
131         return ""
132
133 def runSteps (steps):
134         for step in steps:
135                 if step.isAvailable(env):
136                         print("Run: %s" % step.getName())
137                         step.run(env)
138                 else:
139                         print("Skip: %s" % step.getName())
140
141 COMMON_CFLAGS           = ["-Werror", "-Wno-error=unused-function"]
142 COMMON_GCC_CFLAGS       = COMMON_CFLAGS + ["-Wno-implicit-fallthrough"]
143 COMMON_CLANG_CFLAGS     = COMMON_CFLAGS + ["-Wno-error=unused-command-line-argument"]
144 GCC_32BIT_CFLAGS        = COMMON_GCC_CFLAGS + ["-m32"]
145 CLANG_32BIT_CFLAGS      = COMMON_CLANG_CFLAGS + ["-m32"]
146 GCC_64BIT_CFLAGS        = COMMON_GCC_CFLAGS + ["-m64"]
147 CLANG_64BIT_CFLAGS      = COMMON_CLANG_CFLAGS + ["-m64"]
148 CLANG_VERSION           = getClangVersion()
149
150 # Always ran before any receipe
151 PREREQUISITES           = [
152         RunScript(os.path.join("external", "fetch_sources.py"))
153 ]
154
155 # Always ran after any receipe
156 POST_CHECKS                     = [
157         CheckSrcChanges()
158 ]
159
160 BUILD_TARGETS           = [
161         Build("clang-64-debug",
162                   UnixConfig("null",
163                                          "Debug",
164                                          "clang" + CLANG_VERSION,
165                                          "clang++" + CLANG_VERSION,
166                                          CLANG_64BIT_CFLAGS),
167                   ANY_UNIX_GENERATOR),
168         Build("gcc-32-debug",
169                   UnixConfig("null",
170                                          "Debug",
171                                          "gcc",
172                                          "g++",
173                                          GCC_32BIT_CFLAGS),
174                   ANY_UNIX_GENERATOR),
175         Build("gcc-64-release",
176                   UnixConfig("null",
177                                          "Release",
178                                          "gcc",
179                                          "g++",
180                                          GCC_64BIT_CFLAGS),
181                   ANY_UNIX_GENERATOR),
182         Build("vs-64-debug",
183                   VSConfig("Debug"),
184                   ANY_VS_X64_GENERATOR),
185 ]
186
187 EARLY_SPECIAL_RECIPES   = [
188         ('gen-inl-files', [
189                         RunScript(os.path.join("scripts", "gen_egl.py")),
190                         RunScript(os.path.join("scripts", "opengl", "gen_all.py")),
191                         RunScript(os.path.join("external", "vulkancts", "scripts", "gen_framework.py")),
192                         RunScript(os.path.join("external", "vulkancts", "scripts", "gen_framework_c.py")),
193                         RunScript(os.path.join("scripts", "gen_android_mk.py")),
194                 ]),
195         ('gen-ext-deps', [
196                         RunScript(os.path.join("external", "vulkancts", "scripts", "gen_ext_deps.py"))
197                 ]),
198 ]
199
200 LATE_SPECIAL_RECIPES    = [
201         ('android-mustpass', [
202                         RunScript(os.path.join("scripts", "build_android_mustpass.py"),
203                                           lambda env: ["--build-dir", os.path.join(env.tmpDir, "android-mustpass")]),
204                 ]),
205         ('vulkan-mustpass', [
206                         RunScript(os.path.join("external", "vulkancts", "scripts", "build_mustpass.py"),
207                                           lambda env: ["--build-dir", os.path.join(env.tmpDir, "vulkan-mustpass")]),
208                 ]),
209         ('spirv-binaries', [
210                         RunScript(os.path.join("external", "vulkancts", "scripts", "build_spirv_binaries.py"),
211                                           lambda env: ["--build-dir", os.path.join(env.tmpDir, "spirv-binaries"),
212                                                                         "--dst-path", os.path.join(env.tmpDir, "spirv-binaries")]),
213                 ]),
214         ('check-all', [
215                         RunScript(os.path.join("scripts", "src_util", "check_all.py")),
216                 ])
217 ]
218
219 def getBuildRecipes ():
220         return [(b.getName(), [b]) for b in BUILD_TARGETS]
221
222 def getAllRecipe (recipes):
223         allSteps = []
224         for name, steps in recipes:
225                 allSteps += steps
226         return ("all", allSteps)
227
228 def getRecipes ():
229         recipes = EARLY_SPECIAL_RECIPES + getBuildRecipes() + LATE_SPECIAL_RECIPES
230         return recipes
231
232 def getRecipe (recipes, recipeName):
233         for curName, steps in recipes:
234                 if curName == recipeName:
235                         return (curName, steps)
236         return None
237
238 RECIPES                 = getRecipes()
239
240 def parseArgs ():
241         parser = argparse.ArgumentParser(description = "Build and test source",
242                                                                          formatter_class=argparse.ArgumentDefaultsHelpFormatter)
243         parser.add_argument("-s",
244                                                 "--src-dir",
245                                                 dest="srcDir",
246                                                 default=DEQP_DIR,
247                                                 help="Source directory")
248         parser.add_argument("-t",
249                                                 "--tmp-dir",
250                                                 dest="tmpDir",
251                                                 default=os.path.join(tempfile.gettempdir(), "deqp-build-test"),
252                                                 help="Temporary directory")
253         parser.add_argument("-r",
254                                                 "--recipe",
255                                                 dest="recipe",
256                                                 choices=[n for n, s in RECIPES] + ["all"],
257                                                 default="all",
258                                                 help="Build / test recipe")
259         parser.add_argument("-d",
260                                                 "--dump-recipes",
261                                                 dest="dumpRecipes",
262                                                 action="store_true",
263                                                 help="Print out recipes that have any available actions")
264         parser.add_argument("--skip-prerequisites",
265                                                 dest="skipPrerequisites",
266                                                 action="store_true",
267                                                 help="Skip external dependency fetch")
268
269         return parser.parse_args()
270
271 if __name__ == "__main__":
272         args    = parseArgs()
273         env             = Environment(args.srcDir, args.tmpDir)
274
275         if args.dumpRecipes:
276                 for name, steps in RECIPES:
277                         for step in steps:
278                                 if step.isAvailable(env):
279                                         print(name)
280                                         break
281         else:
282                 name, steps     = getAllRecipe(RECIPES) if args.recipe == "all" \
283                                           else getRecipe(RECIPES, args.recipe)
284
285                 print("Running %s" % name)
286
287                 allSteps = (PREREQUISITES if (args.skipPrerequisites == False) else []) + steps + POST_CHECKS
288                 runSteps(allSteps)
289
290                 print("All steps completed successfully")