| # -*- coding: utf-8 -*- |
| |
| #------------------------------------------------------------------------- |
| # drawElements Quality Program utilities |
| # -------------------------------------- |
| # |
| # Copyright 2016 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| #------------------------------------------------------------------------- |
| |
| import os |
| import argparse |
| import tempfile |
| import sys |
| |
| from build.common import * |
| from build.build import * |
| |
| pythonExecutable = sys.executable or "python" |
| |
| class Environment: |
| def __init__ (self, srcDir, tmpDir): |
| self.srcDir = srcDir |
| self.tmpDir = tmpDir |
| |
| class BuildTestStep: |
| def getName (self): |
| return "<unknown>" |
| |
| def isAvailable (self, env): |
| return True |
| |
| def run (self, env): |
| raise Exception("Not implemented") |
| |
| class RunScript(BuildTestStep): |
| def __init__ (self, scriptPath, getExtraArgs = None): |
| self.scriptPath = scriptPath |
| self.getExtraArgs = getExtraArgs |
| |
| def getName (self): |
| return self.scriptPath |
| |
| def run (self, env): |
| args = [pythonExecutable, os.path.join(env.srcDir, self.scriptPath)] |
| |
| if self.getExtraArgs != None: |
| args += self.getExtraArgs(env) |
| |
| execute(args) |
| |
| def makeCflagsArgs (cflags): |
| cflagsStr = " ".join(cflags) |
| return ["-DCMAKE_C_FLAGS=%s" % cflagsStr, "-DCMAKE_CXX_FLAGS=%s" % cflagsStr] |
| |
| def makeBuildArgs (target, cc, cpp, cflags): |
| return ["-DDEQP_TARGET=%s" % target, "-DCMAKE_C_COMPILER=%s" % cc, "-DCMAKE_CXX_COMPILER=%s" % cpp] + makeCflagsArgs(cflags) |
| |
| class BuildConfigGen: |
| def isAvailable (self, env): |
| return True |
| |
| class UnixConfig(BuildConfigGen): |
| def __init__ (self, target, buildType, cc, cpp, cflags): |
| self.target = target |
| self.buildType = buildType |
| self.cc = cc |
| self.cpp = cpp |
| self.cflags = cflags |
| |
| def isAvailable (self, env): |
| return which(self.cc) != None and which(self.cpp) != None |
| |
| def getBuildConfig (self, env, buildDir): |
| args = makeBuildArgs(self.target, self.cc, self.cpp, self.cflags) |
| return BuildConfig(buildDir, self.buildType, args, env.srcDir) |
| |
| class VSConfig(BuildConfigGen): |
| def __init__ (self, buildType): |
| self.buildType = buildType |
| |
| def getBuildConfig (self, env, buildDir): |
| args = ["-DCMAKE_C_FLAGS=/WX -DCMAKE_CXX_FLAGS=/WX"] |
| return BuildConfig(buildDir, self.buildType, args, env.srcDir) |
| |
| class Build(BuildTestStep): |
| def __init__ (self, buildDir, configGen, generator): |
| self.buildDir = buildDir |
| self.configGen = configGen |
| self.generator = generator |
| |
| def getName (self): |
| return self.buildDir |
| |
| def isAvailable (self, env): |
| return self.configGen.isAvailable(env) and self.generator != None and self.generator.isAvailable() |
| |
| def run (self, env): |
| # specialize config for env |
| buildDir = os.path.join(env.tmpDir, self.buildDir) |
| curConfig = self.configGen.getBuildConfig(env, buildDir) |
| |
| build(curConfig, self.generator) |
| |
| class CheckSrcChanges(BuildTestStep): |
| def getName (self): |
| return "check for changes" |
| |
| def run (self, env): |
| pushWorkingDir(env.srcDir) |
| execute(["git", "diff", "--exit-code"]) |
| popWorkingDir() |
| |
| def getClangVersion (): |
| knownVersions = ["4.0", "3.9", "3.8", "3.7", "3.6", "3.5"] |
| for version in knownVersions: |
| if which("clang-" + version) != None: |
| return "-" + version |
| return "" |
| |
| def runSteps (steps): |
| for step in steps: |
| if step.isAvailable(env): |
| print("Run: %s" % step.getName()) |
| step.run(env) |
| else: |
| print("Skip: %s" % step.getName()) |
| |
| COMMON_CFLAGS = ["-Werror", "-Wno-error=unused-function"] |
| COMMON_GCC_CFLAGS = COMMON_CFLAGS + ["-Wno-error=array-bounds"] |
| COMMON_CLANG_CFLAGS = COMMON_CFLAGS + ["-Wno-error=unused-command-line-argument"] |
| GCC_32BIT_CFLAGS = COMMON_GCC_CFLAGS + ["-m32"] |
| CLANG_32BIT_CFLAGS = COMMON_CLANG_CFLAGS + ["-m32"] |
| GCC_64BIT_CFLAGS = COMMON_GCC_CFLAGS + ["-m64"] |
| CLANG_64BIT_CFLAGS = COMMON_CLANG_CFLAGS + ["-m64"] |
| CLANG_VERSION = getClangVersion() |
| |
| # Always ran before any receipe |
| PREREQUISITES = [ |
| RunScript(os.path.join("external", "fetch_sources.py"), lambda env: ["--force"]) |
| ] |
| |
| # Always ran after any receipe |
| POST_CHECKS = [ |
| CheckSrcChanges() |
| ] |
| |
| BUILD_TARGETS = [ |
| Build("clang-64-debug", |
| UnixConfig("null", |
| "Debug", |
| "clang" + CLANG_VERSION, |
| "clang++" + CLANG_VERSION, |
| CLANG_64BIT_CFLAGS), |
| ANY_UNIX_GENERATOR), |
| Build("gcc-32-debug", |
| UnixConfig("null", |
| "Debug", |
| "gcc", |
| "g++", |
| GCC_32BIT_CFLAGS), |
| ANY_UNIX_GENERATOR), |
| Build("gcc-64-release", |
| UnixConfig("null", |
| "Release", |
| "gcc", |
| "g++", |
| GCC_64BIT_CFLAGS), |
| ANY_UNIX_GENERATOR), |
| Build("vs-64-debug", |
| VSConfig("Debug"), |
| ANY_VS_X64_GENERATOR), |
| ] |
| |
| EARLY_SPECIAL_RECIPES = [ |
| ('gen-inl-files', [ |
| RunScript(os.path.join("scripts", "gen_egl.py")), |
| RunScript(os.path.join("scripts", "opengl", "gen_all.py")), |
| RunScript(os.path.join("external", "vulkancts", "scripts", "gen_framework.py")), |
| RunScript(os.path.join("external", "vulkancts", "scripts", "gen_framework_c.py")), |
| RunScript(os.path.join("external", "vulkancts", "scripts", "gen_framework.py"), lambda env: ["--api", "SC"] ), |
| RunScript(os.path.join("external", "vulkancts", "scripts", "gen_framework_c.py"), lambda env: ["--api", "SC"] ), |
| RunScript(os.path.join("scripts", "gen_android_mk.py")) |
| ]), |
| ] |
| |
| LATE_SPECIAL_RECIPES = [ |
| ('android-mustpass', [ |
| RunScript(os.path.join("scripts", "build_android_mustpass.py"), |
| lambda env: ["--build-dir", os.path.join(env.tmpDir, "android-mustpass")]), |
| ]), |
| ('vulkan-mustpass', [ |
| RunScript(os.path.join("external", "vulkancts", "scripts", "build_mustpass.py"), |
| lambda env: ["--build-dir", os.path.join(env.tmpDir, "vulkan-mustpass")]), |
| ]), |
| ('spirv-binaries', [ |
| RunScript(os.path.join("external", "vulkancts", "scripts", "build_spirv_binaries.py"), |
| lambda env: ["--build-type", "Release", |
| "--build-dir", os.path.join(env.tmpDir, "spirv-binaries"), |
| "--dst-path", os.path.join(env.tmpDir, "spirv-binaries")]), |
| ]), |
| ('amber-verify', [ |
| RunScript(os.path.join("external", "vulkancts", "scripts", "amber_verify.py"), |
| lambda env: ["--build-type", "Release", |
| "--build-dir", os.path.join(env.tmpDir, "amber-verify"), |
| "--dst-path", os.path.join(env.tmpDir, "amber-verify")]), |
| ]), |
| ('check-all', [ |
| RunScript(os.path.join("scripts", "src_util", "check_all.py")), |
| ]) |
| ] |
| |
| def getBuildRecipes (): |
| return [(b.getName(), [b]) for b in BUILD_TARGETS] |
| |
| def getAllRecipe (recipes): |
| allSteps = [] |
| for name, steps in recipes: |
| allSteps += steps |
| return ("all", allSteps) |
| |
| def getRecipes (): |
| recipes = EARLY_SPECIAL_RECIPES + getBuildRecipes() + LATE_SPECIAL_RECIPES |
| return recipes |
| |
| def getRecipe (recipes, recipeName): |
| for curName, steps in recipes: |
| if curName == recipeName: |
| return (curName, steps) |
| return None |
| |
| RECIPES = getRecipes() |
| |
| def parseArgs (): |
| parser = argparse.ArgumentParser(description = "Build and test source", |
| formatter_class=argparse.ArgumentDefaultsHelpFormatter) |
| parser.add_argument("-s", |
| "--src-dir", |
| dest="srcDir", |
| default=DEQP_DIR, |
| help="Source directory") |
| parser.add_argument("-t", |
| "--tmp-dir", |
| dest="tmpDir", |
| default=os.path.join(tempfile.gettempdir(), "deqp-build-test"), |
| help="Temporary directory") |
| parser.add_argument("-r", |
| "--recipe", |
| dest="recipe", |
| choices=[n for n, s in RECIPES] + ["all"], |
| default="all", |
| help="Build / test recipe") |
| parser.add_argument("-d", |
| "--dump-recipes", |
| dest="dumpRecipes", |
| action="store_true", |
| help="Print out recipes that have any available actions") |
| parser.add_argument("--skip-prerequisites", |
| dest="skipPrerequisites", |
| action="store_true", |
| help="Skip external dependency fetch") |
| |
| return parser.parse_args() |
| |
| if __name__ == "__main__": |
| args = parseArgs() |
| env = Environment(args.srcDir, args.tmpDir) |
| |
| if args.dumpRecipes: |
| for name, steps in RECIPES: |
| for step in steps: |
| if step.isAvailable(env): |
| print(name) |
| break |
| else: |
| name, steps = getAllRecipe(RECIPES) if args.recipe == "all" \ |
| else getRecipe(RECIPES, args.recipe) |
| |
| print("Running %s" % name) |
| |
| allSteps = (PREREQUISITES if (args.skipPrerequisites == False) else []) + steps + POST_CHECKS |
| runSteps(allSteps) |
| |
| print("All steps completed successfully") |