1#!/usr/bin/env python 2 3import os 4import sys 5 6from waflib import Build, Logs, Options, TaskGen 7from waflib.extras import autowaf 8 9# Library and package version (UNIX style major, minor, micro) 10# major increment <=> incompatible changes 11# minor increment <=> compatible changes (additions) 12# micro increment <=> no interface changes 13PUGL_VERSION = '0.2.0' 14PUGL_MAJOR_VERSION = '0' 15 16# Mandatory waf variables 17APPNAME = 'pugl' # Package name for waf dist 18VERSION = PUGL_VERSION # Package version for waf dist 19top = '.' # Source directory 20out = 'build' # Build directory 21 22 23def options(ctx): 24 ctx.load('compiler_c') 25 ctx.load('compiler_cxx') 26 27 opts = ctx.configuration_options() 28 opts.add_option('--target', default=None, dest='target', 29 help='target platform (e.g. "win32" or "darwin")') 30 31 ctx.add_flags( 32 opts, 33 {'all-headers': 'install complete header implementation', 34 'no-vulkan': 'do not build Vulkan support', 35 'no-gl': 'do not build OpenGL support', 36 'no-cxx': 'do not build C++ examples', 37 'no-cairo': 'do not build Cairo support', 38 'no-static': 'do not build static library', 39 'no-shared': 'do not build shared library'}) 40 41 ctx.get_option_group('Test options').add_option( 42 '--gui-tests', action='store_true', help='Run GUI tests') 43 44 45def configure(conf): 46 conf.load('compiler_c', cache=True) 47 if not Options.options.no_cxx: 48 try: 49 conf.load('compiler_cxx', cache=True) 50 except Exception: 51 pass 52 53 conf.load('autowaf', cache=True) 54 autowaf.set_c_lang(conf, 'c99') 55 if 'COMPILER_CXX' in conf.env: 56 autowaf.set_cxx_lang(conf, 'c++11') 57 58 conf.env.TARGET_PLATFORM = Options.options.target or sys.platform 59 platform = conf.env.TARGET_PLATFORM 60 61 data_dir = '%s/%s' % (conf.env.DATADIR, 'pugl-%s' % PUGL_MAJOR_VERSION) 62 63 if Options.options.strict: 64 # Check for programs used by lint target 65 conf.find_program("flake8", var="FLAKE8", mandatory=False) 66 conf.find_program("clang-tidy", var="CLANG_TIDY", mandatory=False) 67 conf.find_program("iwyu_tool", var="IWYU_TOOL", mandatory=False) 68 69 if Options.options.ultra_strict: 70 # All warnings enabled by autowaf, disable some we trigger 71 72 autowaf.add_compiler_flags(conf.env, '*', { 73 'clang': [ 74 '-Wno-padded', 75 '-Wno-reserved-id-macro', 76 '-Wno-switch-enum', 77 ], 78 'gcc': [ 79 '-Wno-inline', 80 '-Wno-padded', 81 '-Wno-suggest-attribute=const', 82 '-Wno-suggest-attribute=malloc', 83 '-Wno-suggest-attribute=pure', 84 '-Wno-switch-enum', 85 ], 86 'msvc': [ 87 '/wd4061', # enumerator in switch is not explicitly handled 88 '/wd4514', # unreferenced inline function has been removed 89 '/wd4710', # function not inlined 90 '/wd4711', # function selected for automatic inline expansion 91 '/wd4820', # padding added after construct 92 '/wd4996', # POSIX name for this item is deprecated 93 '/wd5045', # will insert Spectre mitigation for memory load 94 ], 95 }) 96 97 autowaf.add_compiler_flags(conf.env, 'c', { 98 'clang': [ 99 '-Wno-bad-function-cast', 100 '-Wno-float-equal', 101 '-Wno-implicit-fallthrough', 102 ], 103 'gcc': [ 104 '-Wno-bad-function-cast', 105 '-Wno-float-equal', 106 '-Wno-pedantic', 107 ], 108 'msvc': [ 109 '/wd4191', # unsafe conversion from type to type 110 '/wd4706', # assignment within conditional expression 111 '/wd4710', # function not inlined 112 '/wd5045', # will insert Spectre mitigation for memory load 113 ], 114 }) 115 116 autowaf.add_compiler_flags(conf.env, 'cxx', { 117 'clang': [ 118 '-Wno-cast-align', # pugl_vulkan_cxx_demo 119 '-Wno-documentation-unknown-command', 120 '-Wno-old-style-cast', 121 ], 122 'gcc': [ 123 '-Wno-cast-align', # pugl_vulkan_cxx_demo 124 '-Wno-effc++', 125 '-Wno-old-style-cast', 126 '-Wno-suggest-final-methods', 127 '-Wno-useless-cast', 128 ], 129 'msvc': [ 130 '/wd4191', # unsafe conversion between function pointers 131 '/wd4355', # 'this' used in base member initializer list 132 '/wd4571', # structured exceptions (SEH) are no longer caught 133 '/wd4623', # default constructor implicitly deleted 134 '/wd4625', # copy constructor implicitly deleted 135 '/wd4626', # assignment operator implicitly deleted 136 '/wd4706', # assignment within conditional expression 137 '/wd4868', # may not enforce left-to-right evaluation order 138 '/wd5026', # move constructor implicitly deleted 139 '/wd5027', # move assignment operator implicitly deleted 140 '/wd5039', # pointer to throwing function passed to C function 141 ], 142 }) 143 144 # Add some platform-specific warning suppressions 145 if conf.env.TARGET_PLATFORM == "win32": 146 autowaf.add_compiler_flags(conf.env, '*', { 147 'gcc': ['-Wno-cast-function-type', 148 '-Wno-conversion', 149 '-Wno-format', 150 '-Wno-suggest-attribute=format'], 151 'clang': ['-D_CRT_SECURE_NO_WARNINGS', 152 '-Wno-format-nonliteral', 153 '-Wno-nonportable-system-include-path'], 154 }) 155 elif conf.env.TARGET_PLATFORM == 'darwin': 156 autowaf.add_compiler_flags(conf.env, '*', { 157 'clang': ['-DGL_SILENCE_DEPRECATION', 158 '-Wno-deprecated-declarations', 159 '-Wno-direct-ivar-access'], 160 'gcc': ['-DGL_SILENCE_DEPRECATION', 161 '-Wno-deprecated-declarations', 162 '-Wno-direct-ivar-access'], 163 }) 164 165 if Options.options.debug and not Options.options.no_coverage: 166 conf.env.append_unique('CFLAGS', ['--coverage']) 167 conf.env.append_unique('CXXFLAGS', ['--coverage']) 168 conf.env.append_unique('LINKFLAGS', ['--coverage']) 169 170 if conf.env.DOCS: 171 conf.load('python') 172 conf.load('sphinx') 173 conf.find_program('doxygen', var='DOXYGEN') 174 175 if not (conf.env.DOXYGEN and conf.env.SPHINX_BUILD): 176 conf.env.DOCS = False 177 178 sys_header = 'windows.h' if platform == 'win32' else '' 179 180 if not Options.options.no_vulkan: 181 vulkan_sdk = os.environ.get('VULKAN_SDK', None) 182 vulkan_cflags = '' 183 if vulkan_sdk: 184 vk_include_path = os.path.join(vulkan_sdk, 'Include') 185 vulkan_cflags = conf.env.CPPPATH_ST % vk_include_path 186 187 # Check for Vulkan header (needed for backends) 188 conf.check(features='c cxx', 189 cflags=vulkan_cflags, 190 cxxflags=vulkan_cflags, 191 header_name=sys_header + ' vulkan/vulkan.h', 192 uselib_store='VULKAN', 193 mandatory=False) 194 195 if conf.env.BUILD_TESTS and conf.env.HAVE_VULKAN: 196 # Check for Vulkan library and shader compiler 197 # The library is needed by pugl_vulkan_demo.c which has no loader 198 vulkan_linkflags = '' 199 if vulkan_sdk: 200 vk_lib_path = os.path.join(vulkan_sdk, 'Lib') 201 vulkan_linkflags = conf.env.LIBPATH_ST % vk_lib_path 202 203 # The Vulkan library has a different name on Windows 204 for l in ['vulkan', 'vulkan-1']: 205 if conf.check(lib=l, 206 uselib_store='VULKAN_LIB', 207 cflags=vulkan_cflags, 208 linkflags=vulkan_linkflags, 209 mandatory=False): 210 break 211 212 validator_name = 'glslangValidator' 213 if vulkan_sdk: 214 vk_bin_path = os.path.join(vulkan_sdk, 'bin') 215 validator_name = os.path.join(vk_bin_path, 'glslangValidator') 216 217 conf.find_program(validator_name, var='GLSLANGVALIDATOR') 218 219 # Check for base system libraries needed on some systems 220 conf.check_cc(lib='pthread', uselib_store='PTHREAD', mandatory=False) 221 conf.check_cc(lib='m', uselib_store='M', mandatory=False) 222 conf.check_cc(lib='dl', uselib_store='DL', mandatory=False) 223 224 # Check for "native" platform dependencies 225 conf.env.HAVE_GL = False 226 if platform == 'darwin': 227 conf.check_cc(framework_name='Cocoa', framework='Cocoa', 228 uselib_store='COCOA') 229 conf.check_cc(framework_name='Corevideo', framework='Corevideo', 230 uselib_store='COREVIDEO') 231 if not Options.options.no_gl: 232 conf.check_cc(framework_name='OpenGL', uselib_store='GL', 233 mandatory=False) 234 conf.env.HAVE_GL = conf.env.FRAMEWORK_GL 235 236 elif platform == 'win32': 237 conf.check_cc(lib='gdi32', uselib_store='GDI32') 238 conf.check_cc(lib='user32', uselib_store='USER32') 239 if not Options.options.no_gl: 240 conf.check_cc(lib='opengl32', uselib_store='GL', mandatory=False) 241 conf.env.HAVE_GL = conf.env.LIB_GL 242 243 else: 244 conf.check_cc(lib='X11', uselib_store='X11') 245 246 xsync_fragment = """#include <X11/Xlib.h> 247 #include <X11/extensions/sync.h> 248 int main(void) { XSyncQueryExtension(0, 0, 0); return 0; }""" 249 if conf.check_cc(fragment=xsync_fragment, 250 uselib_store='XSYNC', 251 lib='Xext', 252 mandatory=False, 253 msg='Checking for function XSyncQueryExtension'): 254 conf.define('HAVE_XSYNC', 1) 255 256 if conf.check_cc(lib='Xcursor', 257 uselib_store='XCURSOR', 258 mandatory=False): 259 conf.define('HAVE_XCURSOR', 1) 260 261 if conf.check_cc(lib='Xrandr', 262 uselib_store='XRANDR', 263 mandatory=False): 264 conf.define('HAVE_XRANDR', 1) 265 266 if not Options.options.no_gl: 267 glx_fragment = """#include <GL/glx.h> 268 int main(void) { glXSwapBuffers(0, 0); return 0; }""" 269 270 conf.check_cc(lib='GLX', uselib_store='GLX', mandatory=False) 271 conf.check_cc(lib='GL', uselib_store='GL', mandatory=False) 272 conf.check_cc(fragment=glx_fragment, 273 lib='GLX' if conf.env.LIB_GLX else 'GL', 274 mandatory=False, 275 msg='Checking for GLX') 276 conf.env.HAVE_GL = conf.env.LIB_GL or conf.env.LIB_GLX 277 278 # Check for Cairo via pkg-config 279 if not Options.options.no_cairo: 280 autowaf.check_pkg(conf, 'cairo', 281 uselib_store = 'CAIRO', 282 atleast_version = '1.0.0', 283 system = True, 284 mandatory = False) 285 286 conf.env.update({ 287 'BUILD_SHARED': not Options.options.no_shared, 288 'BUILD_STATIC': conf.env.BUILD_TESTS or not Options.options.no_static, 289 'BUILD_STRICT_HEADER_TEST': Options.options.strict, 290 'PUGL_MAJOR_VERSION': PUGL_MAJOR_VERSION, 291 }) 292 293 if conf.env.TARGET_PLATFORM == 'win32': 294 conf.env.PUGL_PLATFORM = 'win' 295 elif conf.env.TARGET_PLATFORM == 'darwin': 296 conf.env.PUGL_PLATFORM = 'mac' 297 else: 298 conf.env.PUGL_PLATFORM = 'x11' 299 300 conf.define('PUGL_DATA_DIR', data_dir) 301 302 autowaf.set_lib_env(conf, 'pugl', PUGL_VERSION, 303 lib='pugl_' + conf.env.PUGL_PLATFORM) 304 305 autowaf.set_lib_env(conf, 'pugl_gl', PUGL_VERSION, 306 lib='pugl_%s_gl' % conf.env.PUGL_PLATFORM) 307 308 autowaf.display_summary( 309 conf, 310 {"Build static library": bool(conf.env.BUILD_STATIC), 311 "Build shared library": bool(conf.env.BUILD_SHARED), 312 "Cairo support": bool(conf.env.HAVE_CAIRO), 313 "OpenGL support": bool(conf.env.HAVE_GL), 314 "Vulkan support": bool(conf.env.HAVE_VULKAN)}) 315 316 317def _build_pc_file(bld, 318 name, 319 desc, 320 target, 321 libname, 322 deps={}, 323 requires=[], 324 cflags=[]): 325 "Builds a pkg-config file for a library" 326 env = bld.env 327 prefix = env.PREFIX 328 xprefix = os.path.dirname(env.LIBDIR) 329 if libname is not None: 330 libname += '-%s' % PUGL_MAJOR_VERSION 331 332 uselib = deps.get('uselib', []) 333 pkg_deps = [l for l in uselib if 'PKG_' + l.lower() in env] 334 lib_deps = [l for l in uselib if 'PKG_' + l.lower() not in env] 335 lib = deps.get('lib', []) + [libname] if libname is not None else [] 336 337 link_flags = [env.LIB_ST % l for l in lib] 338 for l in lib_deps: 339 link_flags += [env.LIB_ST % l for l in env['LIB_' + l]] 340 for f in deps.get('framework', []): 341 link_flags += ['-framework', f] 342 343 bld(features='subst', 344 source='pugl.pc.in', 345 target='%s-%s.pc' % (target, PUGL_MAJOR_VERSION), 346 install_path=os.path.join(env.LIBDIR, 'pkgconfig'), 347 348 PREFIX=prefix, 349 EXEC_PREFIX='${prefix}' if xprefix == prefix else xprefix, 350 LIBDIR='${exec_prefix}/' + os.path.basename(env.LIBDIR), 351 INCLUDEDIR=env.INCLUDEDIR.replace(prefix, '${prefix}', 1), 352 353 NAME=name, 354 DESCRIPTION=desc, 355 PUGL_MAJOR_VERSION=PUGL_MAJOR_VERSION, 356 REQUIRES=' '.join(requires + [p.lower() for p in pkg_deps]), 357 LIBS=' '.join(link_flags), 358 CFLAGS=' '.join(cflags)) 359 360 361gl_tests = ['gl_hints'] 362 363basic_tests = [ 364 'clipboard', 365 'realize', 366 'redisplay', 367 'show_hide', 368 'stub_hints', 369 'timer', 370 'update', 371] 372 373tests = gl_tests + basic_tests 374 375 376def concatenate(task): 377 """Task to concatenate all input files into the output file""" 378 with open(task.outputs[0].abspath(), 'w') as out: 379 for filename in task.inputs: 380 with open(filename.abspath(), 'r') as source: 381 for line in source: 382 out.write(line) 383 384 385def build(bld): 386 # C Headers 387 includedir = '${INCLUDEDIR}/pugl-%s/pugl' % PUGL_MAJOR_VERSION 388 bld.install_files(includedir, bld.path.ant_glob('include/pugl/*.h')) 389 390 if 'COMPILER_CXX' in bld.env: 391 # C++ Headers 392 includedirxx = '${INCLUDEDIR}/puglxx-%s/pugl' % PUGL_MAJOR_VERSION 393 bld.install_files(includedirxx, 394 bld.path.ant_glob('bindings/cxx/include/pugl/*.hpp')) 395 bld.install_files(includedirxx, 396 bld.path.ant_glob('bindings/cxx/include/pugl/*.ipp')) 397 398 # Library dependencies of pugl libraries (for building examples) 399 deps = {} 400 401 data_dir = os.path.join(bld.env.DATADIR, 'pugl-%s' % PUGL_MAJOR_VERSION) 402 403 def build_pugl_lib(name, **kwargs): 404 deps[name] = {} 405 for k in ('lib', 'framework', 'uselib'): 406 deps[name][k] = kwargs.get(k, []) 407 408 args = kwargs.copy() 409 args.update({'includes': ['include'], 410 'export_includes': ['include'], 411 'install_path': '${LIBDIR}', 412 'vnum': PUGL_VERSION}) 413 414 flags = [] 415 if not bld.env.MSVC_COMPILER: 416 flags = ['-fvisibility=hidden'] 417 if bld.env.TARGET_PLATFORM != 'win32': 418 flags = ['-fPIC'] 419 420 if bld.env.BUILD_SHARED: 421 bld(features = 'c cshlib', 422 name = name, 423 target = 'pugl_%s-%s' % (name, PUGL_MAJOR_VERSION), 424 defines = ['PUGL_INTERNAL'], 425 cflags = flags, 426 linkflags = flags, 427 **args) 428 429 if bld.env.BUILD_STATIC: 430 bld(features = 'c cstlib', 431 name = 'pugl_%s_static' % name, 432 target = 'pugl_%s-%s' % (name, PUGL_MAJOR_VERSION), 433 defines = ['PUGL_STATIC', 'PUGL_INTERNAL', 'PUGL_DISABLE_DEPRECATED'], 434 cflags = flags, 435 linkflags = flags, 436 **args) 437 438 def build_platform(platform, **kwargs): 439 build_pugl_lib(platform, **kwargs) 440 _build_pc_file(bld, 'Pugl', 'Pugl GUI library core', 441 'pugl', 'pugl_%s' % platform, 442 deps=kwargs, 443 cflags=['-I${includedir}/pugl-%s' % PUGL_MAJOR_VERSION]) 444 445 def build_backend(platform, backend, **kwargs): 446 name = '%s_%s' % (platform, backend) 447 label = 'OpenGL' if backend == 'gl' else backend.title() 448 build_pugl_lib(name, **kwargs) 449 _build_pc_file(bld, 'Pugl %s' % label, 450 'Pugl GUI library with %s backend' % label, 451 'pugl-%s' % backend, 'pugl_' + name, 452 deps=kwargs, 453 requires=['pugl-%s' % PUGL_MAJOR_VERSION], 454 cflags=['-I${includedir}/pugl-%s' % PUGL_MAJOR_VERSION]) 455 456 lib_source = ['src/implementation.c'] 457 if bld.env.TARGET_PLATFORM == 'win32': 458 platform = 'win' 459 build_platform('win', 460 uselib=['GDI32', 'USER32'], 461 source=lib_source + ['src/win.c']) 462 463 build_backend('win', 'stub', 464 uselib=['GDI32', 'USER32'], 465 source=['src/win_stub.c']) 466 467 if bld.env.HAVE_GL: 468 build_backend('win', 'gl', 469 uselib=['GDI32', 'USER32', 'GL'], 470 source=['src/win_gl.c']) 471 472 if bld.env.HAVE_VULKAN: 473 build_backend('win', 'vulkan', 474 uselib=['GDI32', 'USER32', 'VULKAN'], 475 source=['src/win_vulkan.c', 'src/win_stub.c']) 476 477 if bld.env.HAVE_CAIRO: 478 build_backend('win', 'cairo', 479 uselib=['CAIRO', 'GDI32', 'USER32'], 480 source=['src/win_cairo.c', 'src/win_stub.c']) 481 482 elif bld.env.TARGET_PLATFORM == 'darwin': 483 platform = 'mac' 484 build_platform('mac', 485 framework=['Cocoa', 'Corevideo'], 486 source=lib_source + ['src/mac.m']) 487 488 build_backend('mac', 'stub', 489 framework=['Cocoa', 'Corevideo'], 490 source=['src/mac_stub.m']) 491 492 if bld.env.HAVE_GL: 493 build_backend('mac', 'gl', 494 framework=['Cocoa', 'Corevideo', 'OpenGL'], 495 source=['src/mac_gl.m']) 496 497 if bld.env.HAVE_VULKAN: 498 build_backend('mac', 'vulkan', 499 framework=['Cocoa', 'QuartzCore'], 500 source=['src/mac_vulkan.m']) 501 502 if bld.env.HAVE_CAIRO: 503 build_backend('mac', 'cairo', 504 framework=['Cocoa', 'Corevideo'], 505 uselib=['CAIRO'], 506 source=['src/mac_cairo.m']) 507 else: 508 platform = 'x11' 509 build_platform('x11', 510 uselib=['M', 'X11', 'XSYNC', 'XCURSOR', 'XRANDR'], 511 source=lib_source + ['src/x11.c']) 512 513 build_backend('x11', 'stub', 514 uselib=['X11'], 515 source=['src/x11_stub.c']) 516 517 if bld.env.HAVE_GL: 518 glx_lib = 'GLX' if bld.env.LIB_GLX else 'GL' 519 build_backend('x11', 'gl', 520 uselib=[glx_lib, 'X11'], 521 source=['src/x11_gl.c']) 522 523 if bld.env.HAVE_VULKAN: 524 build_backend('x11', 'vulkan', 525 uselib=['DL', 'X11'], 526 source=['src/x11_vulkan.c', 'src/x11_stub.c']) 527 528 if bld.env.HAVE_CAIRO: 529 build_backend('x11', 'cairo', 530 uselib=['CAIRO', 'X11'], 531 source=['src/x11_cairo.c', 'src/x11_stub.c']) 532 533 if 'COMPILER_CXX' in bld.env: 534 _build_pc_file( 535 bld, 'Pugl C++', 536 'C++ bindings for the Pugl GUI library', 537 'puglxx', 538 None, 539 requires=['pugl-%s' % PUGL_MAJOR_VERSION], 540 cflags=['-I${includedir}/puglxx-%s' % PUGL_MAJOR_VERSION]) 541 542 bld.add_group() 543 544 def build_example(prog, source, platform, backend, **kwargs): 545 lang = 'cxx' if source[0].endswith('.cpp') else 'c' 546 547 includes = ['.'] + (['bindings/cxx/include'] if lang == 'cxx' else []) 548 549 use = ['pugl_%s_static' % platform, 550 'pugl_%s_%s_static' % (platform, backend)] 551 552 target = 'examples/' + prog 553 if bld.env.TARGET_PLATFORM == 'darwin': 554 target = '{0}.app/Contents/MacOS/{0}'.format(prog) 555 556 bld(features = 'subst', 557 source = 'resources/Info.plist.in', 558 target = '{}.app/Contents/Info.plist'.format(prog), 559 includes = includes, 560 install_path = '', 561 NAME = prog) 562 563 backend_lib = platform + '_' + backend 564 for k in ('lib', 'framework', 'uselib'): 565 kwargs.update({k: (kwargs.get(k, []) + 566 deps.get(platform, {}).get(k, []) + 567 deps.get(backend_lib, {}).get(k, []))}) 568 569 kwargs['defines'] = kwargs.get('defines', []) + ['PUGL_STATIC'] 570 571 bld(features = '%s %sprogram' % (lang, lang), 572 source = source, 573 target = target, 574 includes = includes, 575 use = use, 576 install_path = bld.env.BINDIR, 577 **kwargs) 578 579 if bld.env.BUILD_TESTS: 580 for s in [ 581 'header_330.glsl', 582 'header_420.glsl', 583 'rect.frag', 584 'rect.vert', 585 ]: 586 # Copy shaders to build directory for example programs 587 bld(features = 'subst', 588 is_copy = True, 589 source = 'examples/shaders/%s' % s, 590 target = 'examples/shaders/%s' % s, 591 install_path = os.path.join(data_dir, 'shaders')) 592 593 if bld.env.HAVE_GL: 594 glad_cflags = [] if bld.env.MSVC_COMPILER else ['-Wno-pedantic'] 595 build_example('pugl_embed_demo', ['examples/pugl_embed_demo.c'], 596 platform, 'gl', uselib=['GL', 'M']) 597 build_example('pugl_window_demo', ['examples/pugl_window_demo.c'], 598 platform, 'gl', uselib=['GL', 'M']) 599 build_example('pugl_cursor_demo', ['examples/pugl_cursor_demo.c'], 600 platform, 'gl', uselib=['GL', 'M']) 601 build_example('pugl_print_events', 602 ['examples/pugl_print_events.c'], 603 platform, 'stub') 604 build_example('pugl_shader_demo', 605 ['examples/pugl_shader_demo.c', 606 'examples/file_utils.c', 607 'examples/glad/glad.c'], 608 platform, 'gl', 609 cflags=glad_cflags, 610 uselib=['DL', 'GL', 'M']) 611 612 for test in gl_tests: 613 bld(features = 'c cprogram', 614 source = 'test/test_%s.c' % test, 615 target = 'test/test_%s' % test, 616 install_path = '', 617 defines = ['PUGL_STATIC'], 618 use = ['pugl_%s_static' % platform, 619 'pugl_%s_gl_static' % platform], 620 uselib = deps[platform]['uselib'] + ['GL']) 621 622 if bld.env.HAVE_VULKAN and 'GLSLANGVALIDATOR' in bld.env: 623 for s in ['rect.vert', 'rect.frag']: 624 complete = bld.path.get_bld().make_node( 625 'shaders/%s' % s.replace('.', '.vulkan.')) 626 bld(rule = concatenate, 627 source = ['examples/shaders/header_420.glsl', 628 'examples/shaders/%s' % s], 629 target = complete) 630 631 cmd = bld.env.GLSLANGVALIDATOR[0] + " -V -o ${TGT} ${SRC}" 632 bld(rule = cmd, 633 source = complete, 634 target = 'examples/shaders/%s.spv' % s, 635 install_path = os.path.join(data_dir, 'shaders')) 636 637 build_example('pugl_vulkan_demo', 638 ['examples/pugl_vulkan_demo.c'], 639 platform, 640 'vulkan', uselib=['M', 'VULKAN', 'VULKAN_LIB']) 641 642 if bld.env.CXX: 643 build_example('pugl_vulkan_cxx_demo', 644 ['examples/pugl_vulkan_cxx_demo.cpp', 645 'examples/file_utils.c'], 646 platform, 'vulkan', 647 defines=['PUGL_STATIC', 'PUGL_DISABLE_DEPRECATED'], 648 uselib=['DL', 'M', 'PTHREAD', 'VULKAN']) 649 650 if bld.env.HAVE_CAIRO: 651 build_example('pugl_cairo_demo', ['examples/pugl_cairo_demo.c'], 652 platform, 'cairo', 653 uselib=['M', 'CAIRO']) 654 655 for test in basic_tests: 656 bld(features = 'c cprogram', 657 source = 'test/test_%s.c' % test, 658 target = 'test/test_%s' % test, 659 install_path = '', 660 defines = ['PUGL_STATIC'], 661 use = ['pugl_%s_static' % platform, 662 'pugl_%s_stub_static' % platform, 663 'pugl_%s_gl_static' % platform], 664 uselib = deps[platform]['uselib'] + ['CAIRO']) 665 666 if bld.env.BUILD_STRICT_HEADER_TEST: 667 # Make a hyper strict warning environment for checking API headers 668 strict_env = bld.env.derive() 669 autowaf.remove_all_warning_flags(strict_env) 670 autowaf.enable_all_warnings(strict_env) 671 autowaf.set_warnings_as_errors(strict_env) 672 autowaf.add_compiler_flags(strict_env, '*', { 673 'clang': ['-Wno-padded'], 674 'gcc': ['-Wno-padded', '-Wno-suggest-attribute=const'], 675 'msvc': [ 676 '/wd4514', # unreferenced inline function has been removed 677 '/wd4820', # padding added after construct 678 ], 679 }) 680 autowaf.add_compiler_flags(strict_env, 'cxx', { 681 'clang': ['-Wno-documentation-unknown-command'], 682 'msvc': [ 683 '/wd4355', # 'this' used in base member initializer list 684 '/wd4571', # structured exceptions are no longer caught 685 ], 686 }) 687 688 # Check that C headers build with (almost) no warnings 689 bld(features = 'c cprogram', 690 source = 'test/test_build.c', 691 target = 'test/test_build_c', 692 install_path = '', 693 env = strict_env, 694 use = ['pugl_%s_static' % platform], 695 uselib = deps[platform]['uselib'] + ['CAIRO']) 696 697 # Check that C++ headers build with (almost) no warnings 698 bld(features = 'cxx cxxprogram', 699 source = 'test/test_build.cpp', 700 target = 'test/test_build_cpp', 701 install_path = '', 702 env = strict_env, 703 includes = ['bindings/cxx/include'], 704 use = ['pugl_%s_static' % platform], 705 uselib = deps[platform]['uselib'] + ['CAIRO']) 706 707 if bld.env.CXX and bld.env.HAVE_GL: 708 build_example('pugl_cxx_demo', ['examples/pugl_cxx_demo.cpp'], 709 platform, 'gl', 710 defines=['PUGL_DISABLE_DEPRECATED'], 711 uselib=['GL', 'M']) 712 713 if bld.env.DOCS: 714 bld.recurse('doc/c') 715 bld.recurse('doc/cpp') 716 717 718def test(tst): 719 if tst.options.gui_tests: 720 with tst.group('gui') as check: 721 for test in basic_tests: 722 check(['test/test_%s' % test]) 723 724 if tst.env.HAVE_GL: 725 for test in gl_tests: 726 check(['test/test_%s' % test]) 727 728 729class LintContext(Build.BuildContext): 730 fun = cmd = 'lint' 731 732 733def lint(ctx): 734 "checks code for style issues" 735 import glob 736 import json 737 import subprocess 738 739 st = 0 740 741 if "FLAKE8" in ctx.env: 742 Logs.info("Running flake8") 743 st = subprocess.call([ctx.env.FLAKE8[0], 744 "wscript", 745 "--ignore", 746 "E221,W504,E251,E241,E741"]) 747 else: 748 Logs.warn("Not running flake8") 749 750 if "IWYU_TOOL" in ctx.env: 751 Logs.info("Running include-what-you-use") 752 cmd = [ctx.env.IWYU_TOOL[0], "-o", "clang", "-p", "build", "--", 753 "-Xiwyu", "--check_also=*.hpp", 754 "-Xiwyu", "--check_also=examples/*.hpp", 755 "-Xiwyu", "--check_also=examples/*", 756 "-Xiwyu", "--check_also=pugl/*.h", 757 "-Xiwyu", "--check_also=bindings/cxx/include/pugl/*.*", 758 "-Xiwyu", "--check_also=src/*.c", 759 "-Xiwyu", "--check_also=src/*.h", 760 "-Xiwyu", "--check_also=src/*.m"] 761 output = subprocess.check_output(cmd).decode('utf-8') 762 if 'error: ' in output: 763 sys.stdout.write(output) 764 st += 1 765 else: 766 Logs.warn("Not running include-what-you-use") 767 768 if "CLANG_TIDY" in ctx.env and "clang" in ctx.env.CC[0]: 769 Logs.info("Running clang-tidy") 770 with open('build/compile_commands.json', 'r') as db: 771 commands = json.load(db) 772 files = [c['file'] for c in commands 773 if os.path.basename(c['file']) != 'glad.c'] 774 775 c_files = [os.path.join('build', f) 776 for f in files if f.endswith('.c')] 777 778 c_files += glob.glob('include/pugl/*.h') 779 c_files += glob.glob('src/implementation.h') 780 781 cpp_files = [os.path.join('build', f) 782 for f in files if f.endswith('.cpp')] 783 784 cpp_files += glob.glob('bindings/cxx/include/pugl/*') 785 786 c_files = list(map(os.path.abspath, c_files)) 787 cpp_files = list(map(os.path.abspath, cpp_files)) 788 789 procs = [] 790 for c_file in c_files: 791 cmd = [ctx.env.CLANG_TIDY[0], "--quiet", "-p=.", c_file] 792 procs += [subprocess.Popen(cmd, cwd="build")] 793 794 for cpp_file in cpp_files: 795 cmd = [ctx.env.CLANG_TIDY[0], 796 '--header-filter=".*"', 797 "--quiet", 798 "-p=.", cpp_file] 799 procs += [subprocess.Popen(cmd, cwd="build")] 800 801 for proc in procs: 802 stdout, stderr = proc.communicate() 803 st += proc.returncode 804 else: 805 Logs.warn("Not running clang-tidy") 806 807 if st != 0: 808 sys.exit(st) 809 810 811# Alias .m files to be compiled like .c files, gcc will do the right thing. 812@TaskGen.extension('.m') 813def m_hook(self, node): 814 return self.create_compiled_task('c', node) 815