• 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
23import os
24import argparse
25import tempfile
26import sys
27
28from ctsbuild.common import *
29from ctsbuild.build import *
30
31pythonExecutable = sys.executable or "python"
32
33class Environment:
34	def __init__ (self, srcDir, tmpDir):
35		self.srcDir	= srcDir
36		self.tmpDir	= tmpDir
37
38class 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
48class 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
64def makeCflagsArgs (cflags):
65	cflagsStr = " ".join(cflags)
66	return ["-DCMAKE_C_FLAGS=%s" % cflagsStr, "-DCMAKE_CXX_FLAGS=%s" % cflagsStr]
67
68def makeBuildArgs (target, cc, cpp, cflags):
69	return ["-DDEQP_TARGET=%s" % target, "-DCMAKE_C_COMPILER=%s" % cc, "-DCMAKE_CXX_COMPILER=%s" % cpp] + makeCflagsArgs(cflags)
70
71class BuildConfigGen:
72	def isAvailable (self, env):
73		return True
74
75class 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
90class 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
98class 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
117class 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
126def 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
133def 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
141COMMON_CFLAGS		= ["-Werror", "-Wno-error=unused-function"]
142COMMON_GCC_CFLAGS	= COMMON_CFLAGS + ["-Wno-error=array-bounds", "-Wno-error=address", "-Wno-error=nonnull"]
143COMMON_CLANG_CFLAGS	= COMMON_CFLAGS + ["-Wno-error=unused-command-line-argument"]
144GCC_32BIT_CFLAGS	= COMMON_GCC_CFLAGS + ["-m32"]
145CLANG_32BIT_CFLAGS	= COMMON_CLANG_CFLAGS + ["-m32"]
146GCC_64BIT_CFLAGS	= COMMON_GCC_CFLAGS + ["-m64"]
147CLANG_64BIT_CFLAGS	= COMMON_CLANG_CFLAGS + ["-m64"]
148CLANG_VERSION		= getClangVersion()
149
150# Always ran before any receipe
151PREREQUISITES		= [
152	RunScript(os.path.join("external", "fetch_sources.py"), lambda env: ["--force"])
153]
154
155# Always ran after any receipe
156POST_CHECKS			= [
157	CheckSrcChanges()
158]
159
160BUILD_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
187EARLY_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("external", "vulkancts", "scripts", "gen_framework.py"), lambda env: ["--api", "SC"] ),
194			RunScript(os.path.join("external", "vulkancts", "scripts", "gen_framework_c.py"), lambda env: ["--api", "SC"] ),
195			RunScript(os.path.join("scripts", "gen_android_bp.py"))
196		]),
197]
198
199LATE_SPECIAL_RECIPES	= [
200	('android-mustpass', [
201			RunScript(os.path.join("scripts", "build_android_mustpass.py"),
202					  lambda env: ["--build-dir", os.path.join(env.tmpDir, "android-mustpass")]),
203		]),
204	('vulkan-mustpass', [
205			RunScript(os.path.join("external", "vulkancts", "scripts", "build_mustpass.py"),
206					  lambda env: ["--build-dir", os.path.join(env.tmpDir, "vulkan-mustpass")]),
207		]),
208	('spirv-binaries', [
209			RunScript(os.path.join("external", "vulkancts", "scripts", "build_spirv_binaries.py"),
210					  lambda env: ["--build-type", "Release",
211									"--build-dir", os.path.join(env.tmpDir, "spirv-binaries"),
212									"--dst-path", os.path.join(env.tmpDir, "spirv-binaries")]),
213		]),
214	('amber-verify', [
215			RunScript(os.path.join("external", "vulkancts", "scripts", "amber_verify.py"),
216					  lambda env: ["--build-type", "Release",
217									"--build-dir", os.path.join(env.tmpDir, "amber-verify"),
218									"--dst-path", os.path.join(env.tmpDir, "amber-verify")]),
219		]),
220	('check-all', [
221			RunScript(os.path.join("scripts", "src_util", "check_all.py")),
222		])
223]
224
225def getBuildRecipes ():
226	return [(b.getName(), [b]) for b in BUILD_TARGETS]
227
228def getAllRecipe (recipes):
229	allSteps = []
230	for name, steps in recipes:
231		allSteps += steps
232	return ("all", allSteps)
233
234def getRecipes ():
235	recipes = EARLY_SPECIAL_RECIPES + getBuildRecipes() + LATE_SPECIAL_RECIPES
236	return recipes
237
238def getRecipe (recipes, recipeName):
239	for curName, steps in recipes:
240		if curName == recipeName:
241			return (curName, steps)
242	return None
243
244RECIPES			= getRecipes()
245
246def parseArgs ():
247	parser = argparse.ArgumentParser(description = "Build and test source",
248									 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
249	parser.add_argument("-s",
250						"--src-dir",
251						dest="srcDir",
252						default=DEQP_DIR,
253						help="Source directory")
254	parser.add_argument("-t",
255						"--tmp-dir",
256						dest="tmpDir",
257						default=os.path.join(tempfile.gettempdir(), "deqp-build-test"),
258						help="Temporary directory")
259	parser.add_argument("-r",
260						"--recipe",
261						dest="recipe",
262						choices=[n for n, s in RECIPES] + ["all"],
263						default="all",
264						help="Build / test recipe")
265	parser.add_argument("-d",
266						"--dump-recipes",
267						dest="dumpRecipes",
268						action="store_true",
269						help="Print out recipes that have any available actions")
270	parser.add_argument("--skip-prerequisites",
271						dest="skipPrerequisites",
272						action="store_true",
273						help="Skip external dependency fetch")
274
275	return parser.parse_args()
276
277if __name__ == "__main__":
278	args	= parseArgs()
279	env		= Environment(args.srcDir, args.tmpDir)
280
281	if args.dumpRecipes:
282		for name, steps in RECIPES:
283			for step in steps:
284				if step.isAvailable(env):
285					print(name)
286					break
287	else:
288		name, steps	= getAllRecipe(RECIPES) if args.recipe == "all" \
289					  else getRecipe(RECIPES, args.recipe)
290
291		print("Running %s" % name)
292
293		allSteps = (PREREQUISITES if (args.skipPrerequisites == False) else []) + steps + POST_CHECKS
294		runSteps(allSteps)
295
296		print("All steps completed successfully")
297