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