blob: a8189194f0870716356eb0fe4ae695ba1cb1e372 [file] [log] [blame]
# -*- 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_ext_deps.py")),
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")]),
]),
('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")