glmark2是一个GPU测试bench,来自glcompbench,早前的版本glmark1是用makefile构建的。
glmark2的构建使用的是waf
Waf的构建文件是wscript。wscript中一个project一般包含6个步骤构成:
configure:
build: transform the source files into build files
install
uninstall
dist: 源文件打包
clean: remove the build files
每一个步骤在wscript文件中定义成一个python函数,后台会把这几个函数作为参数实例化一个 waflib.Context.Context。每个步骤的定义模板如下:
def configure(conf):
print("configure!")
def build(bld):
print("build!")
使用的时候要下载waf,放到根目录下,按照过程执行:
$ cd /tmp/myproject
$ wget https://waf.io/waf-2.0.0
$ python ./waf-2.0.0 configure build
configure!
build!
waf编译中主要是def build(bld),调用bld函数创建一个task generator对象,创建tasks。waf先读取所有的bld,判断文件和target的依赖顺序,然后再按照bld的顺序执行其中的rule。rule是生成target时需要执行的命令。
def build(bld):
tg = bld(rule='cp ${SRC} ${TGT}', source='wscript', target='foo.txt')
bld(rule='cp ${SRC} ${TGT}', source='foo.txt', target='bar.txt')
默认的一些语言不用指定rule,指定编译器,waf tool会调用对应的方法,同时可以为指定相关的编译参数。
def options(opt):
opt.load('compiler_c compiler_cxx')
def configure(cnf):
cnf.load('compiler_c compiler_cxx')
cnf.check(features='cxx cxxprogram', lib=['m'], cflags=['-Wall'], defines=['var=foo'], uselib_store='M')
def build(bld):
bld(features='c cshlib', source='b.c', target='mylib')
bld(features='c cxx cxxprogram', source='a.c main.cpp', target='app', use=['M','mylib'], lib=['dl'])
相当于定义了下面的三个变量:
conf.env.LIB_M = ['m']
conf.env.CFLAGS_M = ['-Wall']
conf.env.DEFINES_M = ['var=foo']
内置变量的引用用“${}”
def build(bld):
bld.env.MESSAGE = 'Hello, world!'
bld(rule='echo ${MESSAGE}', always=True)
调用子目录的waf脚本:
def build(bld):
bld.recurse('src')
Waf的核心是13个module构成,其流程图如下:
使用waf的主要函数和特性有:
feature: 指定编译器
configure:包含一些method设置功用参数和配置的方法
build:bld方法中一些参数配置的方法
$ ./waf configure --with-flavors=-gl,drm-glesv2,mir-gl,mir-glesv2,wayland-gl,wayland-glesv2,x11-gl,x11-glesv2> [--data-path=DATA_PATH --prefix=PREFIX]
$ ./waf
$ ./waf install --destdir=DESTDIR
编译文件为顶层wscript文件,流程如下:
opt.load('gnu_dirs') 使用标准的gnu库路径
opt.load('compiler_c')
opt.load('compiler_cxx')
FLAVORS = {
'dispmanx-glesv2' : 'glmark2-es2-dispmanx',
'drm-gl' : 'glmark2-drm',
'drm-glesv2' : 'glmark2-es2-drm',
'mir-gl' : 'glmark2-mir',
'mir-glesv2' : 'glmark2-es2-mir',
'wayland-gl' : 'glmark2-wayland',
'wayland-glesv2' : 'glmark2-es2-wayland',
'win32-gl': 'glmark2-win32',
'win32-glesv2': 'glmark2-es2',
'x11-gl' : 'glmark2',
'x11-glesv2' : 'glmark2-es2',
}
生成FLAVOR_%s的环境变量参数,后面的build中根据这个flavor取对应的库、源文件、头文件、defines、依赖等配置。这些配置也是用键值对定义好数组。
ctx.env["FLAVOR_%s" % flavor.upper().replace('-','_')] = FLAVORS[flavor]
for name in bld.env.keys():
if name.startswith('FLAVOR_') and bld.env[name]:
flavor = name.replace('FLAVOR_', '').lower().replace('_', '-')
egl_platform = flavor.split('-')[0]
target = bld.env[name]
node = bld(
features = ['cxx', 'cprogram'],
source = flavor_sources[flavor],
target = target,
use = platform_uselibs + flavor_uselibs[flavor],
lib = platform_libs + flavor_libs[flavor],
includes = ['.'] + platform_includes,
defines = common_defines + flavor_defines[flavor] +
egl_platform_defines[egl_platform],
depends_on = flavor_depends_on[flavor]
)
if flavor_sources_gen[flavor]:
node.source.extend(flavor_sources_gen[flavor])
all_uselibs |= set(flavor_uselibs[flavor] + platform_uselibs)
ctx.load('gnu_dirs')
ctx.load('compiler_c')
ctx.load('compiler_cxx')
根据是win还是linux进行配置
if is_win:
configure_win32(ctx)
else:
configure_linux(ctx)
def configure_linux(ctx):
用 check_cc 和 check_cfg 查找依赖库和头文件和编译参数CXXFLAGS和资源路径宏,包含标准头文件和库、gl相关库、flovar中指定的驱动库、libjpeg和libpng。
def build(ctx):
调用子目录的wscript_build
ctx.recurse('src')
ctx.recurse('data')
ctx.recurse('doc')
def archive(self):
import tarfile
tar = tarfile.open(APPNAME + '-' + VERSION + '.tar.gz', 'w:gz')
for f in self.get_files():
tar.add(f, arcname = APPNAME + '-' + VERSION + '/' + f, recursive = False)
tar.close()
src下wscript_build的流程如下:
for name in bld.env.keys():
if name.startswith('FLAVOR_') and bld.env[name]:
flavor = name.replace('FLAVOR_', '').lower().replace('_', '-')
egl_platform = flavor.split('-')[0]
target = bld.env[name]
node = bld(
features = ['cxx', 'cprogram'],
source = flavor_sources[flavor],
target = target,
use = platform_uselibs + flavor_uselibs[flavor],
lib = platform_libs + flavor_libs[flavor],
includes = ['.'] + platform_includes,
defines = common_defines + flavor_defines[flavor] +
egl_platform_defines[egl_platform],
depends_on = flavor_depends_on[flavor]
)
if flavor_sources_gen[flavor]:
node.source.extend(flavor_sources_gen[flavor])
all_uselibs |= set(flavor_uselibs[flavor] + platform_uselibs)
for egl_target in (v for v in all_uselibs if v.startswith('glad-egl')):
egl_platform = egl_target.split('-')[2]
bld(
features = ['c'],
source = ['glad/src/egl.c'],
target = egl_target,
includes = ['glad/include'],
export_includes = 'glad/include',
defines = egl_platform_defines[egl_platform]
)