1#!/usr/bin/env python 2 3import glob 4import os 5import sys 6 7from waflib import Logs, Options 8from waflib.extras import autowaf 9 10# Library and package version (UNIX style major, minor, micro) 11# major increment <=> incompatible changes 12# minor increment <=> compatible changes (additions) 13# micro increment <=> no interface changes 14SORD_VERSION = '0.16.8' 15SORD_MAJOR_VERSION = '0' 16 17# Mandatory waf variables 18APPNAME = 'sord' # Package name for waf dist 19VERSION = SORD_VERSION # Package version for waf dist 20top = '.' # Source directory 21out = 'build' # Build directory 22 23# Release variables 24uri = 'http://drobilla.net/sw/sord' 25dist_pattern = 'http://download.drobilla.net/sord-%d.%d.%d.tar.bz2' 26post_tags = ['Hacking', 'RDF', 'Sord'] 27 28def options(ctx): 29 ctx.load('compiler_c') 30 ctx.load('compiler_cxx') 31 opt = ctx.configuration_options() 32 33 ctx.add_flags( 34 opt, 35 {'no-utils': 'do not build command line utilities', 36 'static': 'build static library', 37 'no-shared': 'do not build shared library', 38 'static-progs': 'build programs as static binaries'}) 39 40 opt.add_option('--dump', type='string', default='', dest='dump', 41 help='dump debugging output (iter, search, write, all)') 42 43def configure(conf): 44 conf.load('compiler_c', cache=True) 45 if Options.options.build_tests: 46 try: 47 conf.load('compiler_cxx', cache=True) 48 except: 49 Logs.warn("No C++ compiler, sordmm.hpp compile test skipped") 50 pass 51 52 conf.load('autowaf', cache=True) 53 autowaf.set_c_lang(conf, 'c99') 54 autowaf.set_cxx_lang(conf, 'c++11') 55 56 conf.env.BUILD_UTILS = not Options.options.no_utils 57 conf.env.BUILD_SHARED = not Options.options.no_shared 58 conf.env.STATIC_PROGS = Options.options.static_progs 59 conf.env.BUILD_STATIC = (Options.options.static or 60 Options.options.static_progs) 61 62 if Options.options.ultra_strict: 63 autowaf.add_compiler_flags(conf.env, '*', { 64 'gcc': [ 65 '-Wno-cast-align', 66 '-Wno-cast-qual', 67 '-Wno-conversion', 68 '-Wno-inline', 69 '-Wno-padded', 70 '-Wno-sign-conversion', 71 '-Wno-stack-protector', 72 '-Wno-suggest-attribute=const', 73 '-Wno-suggest-attribute=pure', 74 '-Wno-switch-enum', 75 '-Wno-unused-macros', 76 '-Wno-unused-parameter', 77 '-Wno-vla', 78 ], 79 'clang': [ 80 '-Wno-cast-align', 81 '-Wno-cast-qual', 82 '-Wno-format-nonliteral', 83 '-Wno-nullability-extension', 84 '-Wno-padded', 85 '-Wno-reserved-id-macro', 86 '-Wno-shorten-64-to-32', 87 '-Wno-sign-conversion', 88 '-Wno-switch-enum', 89 '-Wno-unused-macros', 90 '-Wno-unused-parameter', 91 '-Wno-vla', 92 ], 93 'msvc': [ 94 '/wd4061', # enumerator in switch is not explicitly handled 95 '/wd4100', # unreferenced formal parameter 96 '/wd4200', # zero-sized array in struct/union 97 '/wd4244', # conversion with possible loss of data 98 '/wd4267', # conversion from size_t to a smaller type 99 '/wd4365', # signed/unsigned mismatch 100 '/wd4389', # '==': signed/unsigned mismatch 101 '/wd4514', # unreferenced inline function has been removed 102 '/wd4702', # unreachable code 103 '/wd4706', # assignment within conditional expression 104 '/wd4820', # padding added after construct 105 '/wd5045', # will insert Spectre mitigation for memory load 106 ], 107 }) 108 109 autowaf.add_compiler_flags(conf.env, 'cxx', { 110 'gcc': [ 111 '-Wno-effc++', 112 '-Wno-multiple-inheritance', 113 ], 114 'clang': [ 115 '-Wno-implicit-float-conversion', 116 ], 117 'msvc': [ 118 '/wd4571', # catch semantics changed 119 '/wd4625', # copy constructor implicitly deleted 120 '/wd4626', # assignment opreator implicitly deleted 121 ], 122 }) 123 124 conf.check_pkg('serd-0 >= 0.30.0', uselib_store='SERD') 125 conf.check_pkg('libpcre', uselib_store='PCRE', mandatory=False) 126 127 if conf.env.HAVE_PCRE: 128 if conf.check(cflags=['-pthread'], mandatory=False): 129 conf.env.PTHREAD_CFLAGS = ['-pthread'] 130 if conf.env.CC_NAME != 'clang': 131 conf.env.PTHREAD_LINKFLAGS = ['-pthread'] 132 elif conf.check(linkflags=['-lpthread'], mandatory=False): 133 conf.env.PTHREAD_CFLAGS = [] 134 conf.env.PTHREAD_LINKFLAGS = ['-lpthread'] 135 else: 136 conf.env.PTHREAD_CFLAGS = [] 137 conf.env.PTHREAD_LINKFLAGS = [] 138 139 # Parse dump options and define things accordingly 140 dump = Options.options.dump.split(',') 141 all = 'all' in dump 142 if all or 'iter' in dump: 143 conf.define('SORD_DEBUG_ITER', 1) 144 if all or 'search' in dump: 145 conf.define('SORD_DEBUG_SEARCH', 1) 146 if all or 'write' in dump: 147 conf.define('SORD_DEBUG_WRITE', 1) 148 149 # Set up environment for building/using as a subproject 150 autowaf.set_lib_env(conf, 'sord', SORD_VERSION, 151 include_path=str(conf.path.find_node('include'))) 152 153 if conf.env.BUILD_UTILS and conf.env.HAVE_PCRE: 154 sord_validate_node = conf.path.get_bld().make_node('sord_validate') 155 conf.env.SORD_VALIDATE = [sord_validate_node.abspath()] 156 157 conf.define('SORD_NO_DEFAULT_CONFIG', 1) 158 159 autowaf.display_summary( 160 conf, 161 {'Static library': bool(conf.env.BUILD_STATIC), 162 'Shared library': bool(conf.env.BUILD_SHARED), 163 'Utilities': bool(conf.env.BUILD_UTILS), 164 'Unit tests': bool(conf.env.BUILD_TESTS), 165 'Debug dumping': dump}) 166 167def build(bld): 168 # C/C++ Headers 169 includedir = '${INCLUDEDIR}/sord-%s/sord' % SORD_MAJOR_VERSION 170 bld.install_files(includedir, bld.path.ant_glob('include/sord/*.h')) 171 bld.install_files(includedir, bld.path.ant_glob('include/sord/*.hpp')) 172 173 # Pkgconfig file 174 autowaf.build_pc(bld, 'SORD', SORD_VERSION, SORD_MAJOR_VERSION, [], 175 {'SORD_MAJOR_VERSION' : SORD_MAJOR_VERSION, 176 'SORD_PKG_DEPS' : 'serd-0'}) 177 178 source = 'src/sord.c src/syntax.c' 179 180 libflags = ['-fvisibility=hidden'] 181 libs = ['m'] 182 defines = [] 183 if bld.env.MSVC_COMPILER: 184 libflags = [] 185 libs = [] 186 defines = [] 187 188 # Shared Library 189 if bld.env.BUILD_SHARED: 190 obj = bld(features = 'c cshlib', 191 source = source, 192 includes = ['.', 'include', './src'], 193 export_includes = ['.', 'include'], 194 name = 'libsord', 195 target = 'sord-%s' % SORD_MAJOR_VERSION, 196 vnum = SORD_VERSION, 197 install_path = '${LIBDIR}', 198 libs = libs, 199 uselib = 'SERD', 200 defines = defines + ['SORD_INTERNAL'], 201 cflags = libflags) 202 203 # Static Library 204 if bld.env.BUILD_STATIC: 205 obj = bld(features = 'c cstlib', 206 source = source, 207 includes = ['.', 'include', './src'], 208 export_includes = ['.', 'include'], 209 name = 'libsord_static', 210 target = 'sord-%s' % SORD_MAJOR_VERSION, 211 vnum = SORD_VERSION, 212 install_path = '${LIBDIR}', 213 libs = libs, 214 uselib = 'SERD', 215 defines = ['SORD_STATIC', 'SORD_INTERNAL']) 216 217 if bld.env.BUILD_TESTS: 218 test_libs = libs 219 test_cflags = [''] 220 test_linkflags = [''] 221 if not bld.env.NO_COVERAGE: 222 test_cflags += ['--coverage'] 223 test_linkflags += ['--coverage'] 224 225 # Profiled static library for test coverage 226 obj = bld(features = 'c cstlib', 227 source = source, 228 includes = ['.', 'include', './src'], 229 name = 'libsord_profiled', 230 target = 'sord_profiled', 231 install_path = '', 232 defines = defines + ['SORD_STATIC', 'SORD_INTERNAL'], 233 cflags = test_cflags, 234 linkflags = test_linkflags, 235 lib = test_libs, 236 uselib = 'SERD') 237 238 # Unit test program 239 obj = bld(features = 'c cprogram', 240 source = 'src/sord_test.c', 241 includes = ['.', 'include', './src'], 242 use = 'libsord_profiled', 243 lib = test_libs, 244 target = 'sord_test', 245 install_path = '', 246 defines = defines + ['SORD_STATIC'], 247 cflags = test_cflags, 248 linkflags = test_linkflags, 249 uselib = 'SERD') 250 251 # Static profiled sordi for tests 252 obj = bld(features = 'c cprogram', 253 source = 'src/sordi.c', 254 includes = ['.', 'include', './src'], 255 use = 'libsord_profiled', 256 lib = test_libs, 257 target = 'sordi_static', 258 install_path = '', 259 defines = defines + ['SORD_STATIC'], 260 cflags = test_cflags, 261 linkflags = test_linkflags, 262 uselib = 'SERD') 263 264 # C++ build test 265 if bld.env.COMPILER_CXX: 266 obj = bld(features = 'cxx cxxprogram', 267 source = 'src/sordmm_test.cpp', 268 includes = ['.', 'include', './src'], 269 use = 'libsord_profiled', 270 lib = test_libs, 271 target = 'sordmm_test', 272 install_path = '', 273 defines = defines + ['SORD_STATIC'], 274 cxxflags = test_cflags, 275 linkflags = test_linkflags, 276 uselib = 'SERD') 277 278 # Utilities 279 if bld.env.BUILD_UTILS: 280 utils = ['sordi'] 281 if bld.env.HAVE_PCRE: 282 utils += ['sord_validate'] 283 for i in utils: 284 obj = bld(features = 'c cprogram', 285 source = 'src/%s.c' % i, 286 includes = ['.', 'include', './src'], 287 use = 'libsord', 288 lib = libs, 289 uselib = 'SERD', 290 target = i, 291 install_path = '${BINDIR}', 292 defines = defines) 293 if not bld.env.BUILD_SHARED or bld.env.STATIC_PROGS: 294 obj.use = 'libsord_static' 295 if bld.env.STATIC_PROGS: 296 obj.env.SHLIB_MARKER = obj.env.STLIB_MARKER 297 obj.linkflags = ['-static', '-Wl,--start-group'] 298 if i == 'sord_validate': 299 obj.uselib += ' PCRE' 300 obj.cflags = bld.env.PTHREAD_CFLAGS 301 obj.linkflags = bld.env.PTHREAD_LINKFLAGS 302 303 # Documentation 304 autowaf.build_dox(bld, 'SORD', SORD_VERSION, top, out) 305 306 # Man pages 307 bld.install_files('${MANDIR}/man1', bld.path.ant_glob('doc/*.1')) 308 309 bld.add_post_fun(autowaf.run_ldconfig) 310 311def lint(ctx): 312 "checks code for style issues" 313 import subprocess 314 cmd = ("clang-tidy -p=. -header-filter=.* -checks=\"*," + 315 "-cert-dcl03-c," + 316 "-clang-analyzer-alpha.*," + 317 "-google-readability-todo," + 318 "-llvm-header-guard," + 319 "-llvm-include-order," + 320 "-misc-static-assert," + 321 "-misc-unused-parameters," + 322 "-readability-else-after-return\" " + 323 "../src/*.c") 324 subprocess.call(cmd, cwd='build', shell=True) 325 326def upload_docs(ctx): 327 os.system('rsync -ravz --delete -e ssh build/doc/html/ drobilla@drobilla.net:~/drobilla.net/docs/sord/') 328 for page in glob.glob('doc/*.[1-8]'): 329 os.system('soelim %s | pre-grohtml troff -man -wall -Thtml | post-grohtml > build/%s.html' % (page, page)) 330 os.system('rsync -avz --delete -e ssh build/%s.html drobilla@drobilla.net:~/drobilla.net/man/' % page) 331 332def test(tst): 333 import tempfile 334 try: 335 test_dir = os.path.join 336 os.mkdir('tests') 337 for i in glob.glob('tests/*.*'): 338 os.remove(i) 339 except: 340 pass 341 342 srcdir = tst.path.abspath() 343 sordi = './sordi_static' 344 base = 'http://example.org/' 345 snippet = '<{0}s> <{0}p> <{0}o> .\n'.format(base) 346 manifest = 'file://%s/tests/manifest.ttl' % srcdir.replace('\\', '/') 347 348 with tst.group('Unit') as check: 349 check(['./sord_test']) 350 351 with tst.group('GoodCommands') as check: 352 check([sordi, manifest]) 353 check([sordi, '%s/tests/UTF-8.ttl' % srcdir]) 354 check([sordi, '-v']) 355 check([sordi, '-h']) 356 check([sordi, '-s', '<foo> a <#Thingie> .', 'file:///test']) 357 check([sordi, os.devnull], stdout=os.devnull) 358 with tempfile.TemporaryFile(mode='r+') as stdin: 359 stdin.write(snippet + '\n') 360 check([sordi, '-', 'http://example.org/'], stdin=stdin) 361 check([sordi, '-o', 'turtle', '-', 'http://example.org/'], stdin=stdin) 362 363 with tst.group('BadCommands', expected=1) as check: 364 check([sordi]) 365 check([sordi, 'ftp://example.org/unsupported.ttl']) 366 check([sordi, '-i']) 367 check([sordi, '-o']) 368 check([sordi, '-z']) 369 check([sordi, '-p']) 370 check([sordi, '-c']) 371 check([sordi, '-i illegal']) 372 check([sordi, '-o illegal']) 373 check([sordi, '-i turtle']) 374 check([sordi, '-i ntriples']) 375 check([sordi, '/no/such/file']) 376 377 with tst.group('IoErrors', expected=1) as check: 378 check([sordi, 'file://%s/' % srcdir], name='Read directory') 379 if os.path.exists('/dev/full'): 380 check([sordi, manifest], stdout='/dev/full', name='Write error') 381 382 with tst.group('good', verbosity=0) as check: 383 suite_base = 'http://www.w3.org/2001/sw/DataAccess/df1/' 384 good_tests = glob.glob(os.path.join(srcdir, 'tests', 'test-*.ttl')) 385 for test in good_tests: 386 path = os.path.relpath(test, srcdir) 387 base_uri = suite_base + path.replace('\\', '/') 388 389 out_path = path + '.out' 390 check([sordi, test, base_uri], stdout=out_path) 391 392 check_path = test.replace('.ttl', '.out') 393 out_lines = sorted(open(out_path).readlines()) 394 cmp_lines = sorted(open(check_path).readlines()) 395 check(lambda: out_lines == cmp_lines, 396 name='%s check' % path) 397 398def posts(ctx): 399 path = str(ctx.path.abspath()) 400 autowaf.news_to_posts( 401 os.path.join(path, 'NEWS'), 402 {'title' : 'Sord', 403 'description' : autowaf.get_blurb(os.path.join(path, 'README')), 404 'dist_pattern' : 'http://download.drobilla.net/sord-%s.tar.bz2'}, 405 { 'Author' : 'drobilla', 406 'Tags' : 'Hacking, RDF, Sord' }, 407 os.path.join(out, 'posts')) 408