glmark2代码分析
glmark2是一个GPU测试bench,来自glcompbench,早前的版本glmark1是用makefile构建的。
构建方式
glmark2的构建使用的是waf
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方法中一些参数配置的方法
glmark2 waf
编译方法:
$ ./waf configure --with-flavors=<drm-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文件
编译文件为顶层wscript文件,流程如下:
- def options(opt):
- 配置编译器:
opt.load('gnu_dirs') 使用标准的gnu库路径
opt.load('compiler_c')
opt.load('compiler_cxx')
- add_option添加编译配置参数,包括:
–with-flavors:配置编译的操作系统平台 + api版本gl/es2 + 窗口系统drm/wayland/dispmanx/mir
–version-suffix:添加版本后缀
–no-debug:disable compiler debug information’
–no-opt:disable compiler optimizations
–data-path:path to main data (also see --data(root)dir)
–extras-path:path to additional data (models, shaders, textures)
- def configure(ctx):
- 解析flavors参数,区分linux和win,两者只能一个不同能同时存在。
flavors用键值对保存,
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)
- load前面的配置:
ctx.load('gnu_dirs')
ctx.load('compiler_c')
ctx.load('compiler_cxx')
根据是win还是linux进行配置
if is_win:
configure_win32(ctx)
else:
configure_linux(ctx)
- 添加定义versionsuffix和信息打印,这些打印在运行 waf configure 时打印出来。
-
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')
- class Glmark2Dist(Context.Context):
定义 waf dist 命令,将根目录下的源文件和资源文件打包成一个压缩包,名为glmark2-2020.04.tar.gz。不包含的文件:
excludes = [’.bzr’, '.git’, ‘~’, ‘./.waf’, './build’, ‘.swp’, '.pyc’, ‘glmark2-.tar.gz’]
压缩方法,使用python tarfile
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
src下wscript_build的流程如下:
- 获取所有源文件all_sources,对源文件进行分类:
common_sources:非平台相关的代码,src目录下的cpp,scene-ideas下的cc文件 和 scene-terrain下的cc文件。不包含以下前缀的文件:canvas-、android、native-state-、gl-state-、main.cpp。
libmatrix_sources:libmatrix/*.cc不含test目录下文件
common_flavor_sources:‘main.cpp’, ‘canvas-generic.cpp’
libpng_local_sources:libpng目录下的c文件
zlib_local_sources = zlib目录下的c文件
libjpeg_turbo_local_sources:libjpeg-turbo目录下的c文件 - 判断是不是win32和msvc环境,win32使用的platform_uselibs和platform_libs为local的,主要是png、jpeg和z库。
- 如果是WAYLAND_SCANNER_wayland_scanner,要在系统指定pkg目录下扫描生成xdg-shell-client-protocol.h和xdg-shell-protocol.c文件
- 按照flavor参数设置flavor_sources、flavor_uselibs、flavor_defines、flavor_libs、flavor_depends_on、flavor_sources_gen、egl_platform_defines,都是定义成list组
- 根据flavor名称,创建bld,生成target
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]
)
- 后面判断all_uselibs里如果包含下面的库,创建相关的依赖库的生成命令bld:
glad-glx/gl/wgl/glesv2
matrix-gl/glesv2
libpng-local
zlib-local
libjpeg-turbo-local
common-gl
common-glesv2