build: add waf-tool to simplify building with AddressSanitizer & friends
Change-Id: I368fe5bbbe3a92a7e82c22f56f6784761d94118d
Refs: #2589
diff --git a/.waf-tools/default-compiler-flags.py b/.waf-tools/default-compiler-flags.py
index abe0a25..fd15dbb 100644
--- a/.waf-tools/default-compiler-flags.py
+++ b/.waf-tools/default-compiler-flags.py
@@ -60,7 +60,7 @@
supportedFlags += [flag]
self.end_msg(' '.join(supportedFlags))
- self.env.CXXFLAGS = supportedFlags + self.env.CXXFLAGS
+ self.env.prepend_value('CXXFLAGS', supportedFlags)
@Configure.conf
def add_supported_linkflags(self, linkflags):
@@ -78,7 +78,7 @@
supportedFlags += [flag]
self.end_msg(' '.join(supportedFlags))
- self.env.LINKFLAGS = supportedFlags + self.env.LINKFLAGS
+ self.env.prepend_value('LINKFLAGS', supportedFlags)
class CompilerFlags(object):
diff --git a/.waf-tools/sanitizers.py b/.waf-tools/sanitizers.py
new file mode 100644
index 0000000..a8fe55d
--- /dev/null
+++ b/.waf-tools/sanitizers.py
@@ -0,0 +1,22 @@
+# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+def options(opt):
+ opt.add_option('--with-sanitizer', action='store', default='', dest='sanitizers',
+ help='Comma-separated list of compiler sanitizers to enable [default=none]')
+
+def configure(conf):
+ for san in conf.options.sanitizers.split(','):
+ if not san:
+ continue
+
+ sanflag = '-fsanitize=%s' % san
+ conf.start_msg('Checking if compiler supports %s' % sanflag)
+
+ if conf.check_cxx(cxxflags=['-Werror', sanflag, '-fno-omit-frame-pointer'],
+ linkflags=[sanflag], mandatory=False):
+ conf.end_msg('yes')
+ conf.env.append_unique('CXXFLAGS', [sanflag, '-fno-omit-frame-pointer'])
+ conf.env.append_unique('LINKFLAGS', [sanflag])
+ else:
+ conf.end_msg('no', color='RED')
+ conf.fatal('%s sanitizer is not supported by the current compiler' % san)
diff --git a/wscript b/wscript
index 76c39a8..af7e4e9 100644
--- a/wscript
+++ b/wscript
@@ -11,9 +11,10 @@
def options(opt):
opt.load(['compiler_cxx', 'gnu_dirs', 'c_osx'])
- opt.load(['default-compiler-flags', 'coverage', 'osx-security', 'pch',
- 'boost', 'cryptopp', 'sqlite3', 'openssl',
- 'doxygen', 'sphinx_build', 'type_traits', 'compiler-features'],
+ opt.load(['default-compiler-flags', 'compiler-features', 'type_traits',
+ 'coverage', 'pch', 'sanitizers', 'osx-security',
+ 'boost', 'cryptopp', 'openssl', 'sqlite3',
+ 'doxygen', 'sphinx_build'],
tooldir=['.waf-tools'])
opt = opt.add_option_group('Library Options')
@@ -65,9 +66,11 @@
if not conf.options.enable_shared and not conf.options.enable_static:
conf.fatal("Either static library or shared library must be enabled")
- conf.load(['compiler_cxx', 'gnu_dirs', 'c_osx', 'default-compiler-flags',
- 'osx-security', 'pch', 'boost', 'cryptopp', 'sqlite3', 'openssl',
- 'type_traits', 'compiler-features', 'doxygen', 'sphinx_build'])
+ conf.load(['compiler_cxx', 'gnu_dirs', 'c_osx',
+ 'default-compiler-flags', 'compiler-features', 'type_traits',
+ 'pch', 'sanitizers', 'osx-security',
+ 'boost', 'cryptopp', 'openssl', 'sqlite3',
+ 'doxygen', 'sphinx_build'])
conf.env['WITH_TESTS'] = conf.options.with_tests
conf.env['WITH_TOOLS'] = conf.options.with_tools
@@ -156,8 +159,7 @@
int(VERSION_SPLIT[2]),
VERSION_MAJOR=VERSION_SPLIT[0],
VERSION_MINOR=VERSION_SPLIT[1],
- VERSION_PATCH=VERSION_SPLIT[2],
- )
+ VERSION_PATCH=VERSION_SPLIT[2])
libndn_cxx = dict(
target="ndn-cxx",
@@ -169,8 +171,7 @@
use='version BOOST CRYPTOPP OPENSSL SQLITE3 RT PTHREAD',
includes=". src",
export_includes="src",
- install_path='${LIBDIR}',
- )
+ install_path='${LIBDIR}')
if bld.env['HAVE_OSX_SECURITY']:
libndn_cxx['source'] += bld.path.ant_glob('src/security/**/*-osx.cpp')
@@ -208,13 +209,13 @@
if bld.env['CXXFLAGS_%s' % lib]:
pkgconfig_cxxflags += Utils.to_list(bld.env['CXXFLAGS_%s' % lib])
- EXTRA_FRAMEWORKS = "";
+ EXTRA_FRAMEWORKS = ""
if bld.env['HAVE_OSX_SECURITY']:
EXTRA_FRAMEWORKS = "-framework CoreFoundation -framework Security"
def uniq(alist):
- set = {}
- return [set.setdefault(e,e) for e in alist if e not in set]
+ seen = set()
+ return [x for x in alist if x not in seen and not seen.add(x)]
pkconfig = bld(features="subst",
source="libndn-cxx.pc.in",
@@ -229,10 +230,8 @@
EXTRA_LINKFLAGS=" ".join(uniq(pkgconfig_linkflags)),
EXTRA_INCLUDES=" ".join([('-I%s' % i) for i in uniq(pkgconfig_includes)]),
EXTRA_CXXFLAGS=" ".join(uniq(pkgconfig_cxxflags)),
- EXTRA_FRAMEWORKS=EXTRA_FRAMEWORKS,
- )
+ EXTRA_FRAMEWORKS=EXTRA_FRAMEWORKS)
- # Unit tests
if bld.env['WITH_TESTS']:
bld.recurse('tests')
@@ -277,7 +276,7 @@
version(bld)
if not bld.env.DOXYGEN:
- Logs.error("ERROR: cannot build documentation (`doxygen' is not found in $PATH)")
+ Logs.error("ERROR: cannot build documentation (`doxygen' not found in $PATH)")
else:
bld(features="subst",
name="doxygen-conf",
@@ -289,8 +288,7 @@
HTML_FOOTER="../build/docs/named_data_theme/named_data_footer-with-analytics.html" \
if os.getenv('GOOGLE_ANALYTICS', None) \
else "../docs/named_data_theme/named_data_footer.html",
- GOOGLE_ANALYTICS=os.getenv('GOOGLE_ANALYTICS', ""),
- )
+ GOOGLE_ANALYTICS=os.getenv('GOOGLE_ANALYTICS', ""))
bld(features="doxygen",
doxyfile='docs/doxygen.conf',
@@ -300,7 +298,7 @@
version(bld)
if not bld.env.SPHINX_BUILD:
- bld.fatal("ERROR: cannot build documentation (`sphinx-build' is not found in $PATH)")
+ bld.fatal("ERROR: cannot build documentation (`sphinx-build' not found in $PATH)")
else:
bld(features="sphinx",
outdir="docs",
@@ -308,7 +306,6 @@
config="docs/conf.py",
VERSION=VERSION)
-
def version(ctx):
if getattr(Context.g_module, 'VERSION_BASE', None):
return