• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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", "-Wno-error=array-bounds"]
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_bp.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")
291