build+ci: enable code-coverage reporting

This required changing the CI scripts to run the
unit tests against the debug version of NLSR.

Also sync default-compiler-flags.py with NFD.

Change-Id: I31f37e3dfef2c1237393512e0c238f5e6bcbe525
diff --git a/.jenkins.d/10-build.sh b/.jenkins.d/10-build.sh
index 358251d..fcf207c 100755
--- a/.jenkins.d/10-build.sh
+++ b/.jenkins.d/10-build.sh
@@ -14,8 +14,8 @@
 sudo env "PATH=$PATH" ./waf --color=yes distclean
 
 if [[ $JOB_NAME != *"code-coverage" && $JOB_NAME != *"limited-build" ]]; then
-  # Configure/build in debug mode with tests
-  ./waf --color=yes configure --with-tests --debug
+  # Configure/build in optimized mode with tests
+  ./waf --color=yes configure --with-tests
   ./waf --color=yes build -j${WAF_JOBS:-1}
 
   # Cleanup
@@ -29,16 +29,16 @@
   sudo env "PATH=$PATH" ./waf --color=yes distclean
 fi
 
-# Configure/build in optimized mode with tests
+# Configure/build in debug mode with tests
 if [[ $JOB_NAME == *"code-coverage" ]]; then
     COVERAGE="--with-coverage"
 elif [[ -n $BUILD_WITH_ASAN || -z $TRAVIS ]]; then
     ASAN="--with-sanitizer=address"
 fi
-./waf --color=yes configure --with-tests $COVERAGE $ASAN
+./waf --color=yes configure --debug --with-tests $COVERAGE $ASAN
 ./waf --color=yes build -j${WAF_JOBS:-1}
 
-# (tests will be run against optimized version)
+# (tests will be run against debug version)
 
 # Install
 sudo env "PATH=$PATH" ./waf --color=yes install
diff --git a/.jenkins.d/30-coverage.sh b/.jenkins.d/30-coverage.sh
new file mode 100755
index 0000000..981bdc0
--- /dev/null
+++ b/.jenkins.d/30-coverage.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+set -e
+
+JDIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+source "$JDIR"/util.sh
+
+set -x
+
+if [[ $JOB_NAME == *"code-coverage" ]]; then
+    lcov --quiet \
+         --capture \
+         --directory . \
+         --no-external \
+         --rc lcov_branch_coverage=1 \
+         --output-file build/coverage-with-tests.info
+
+    lcov --quiet \
+         --remove build/coverage-with-tests.info "$PWD/tests/*" \
+         --rc lcov_branch_coverage=1 \
+         --output-file build/coverage.info
+
+    genhtml --branch-coverage \
+            --demangle-cpp \
+            --frames \
+            --legend \
+            --output-directory build/coverage \
+            --title "NLSR unit tests" \
+            build/coverage.info
+fi
diff --git a/.waf-tools/coverage.py b/.waf-tools/coverage.py
index 0a3db65..ce92883 100644
--- a/.waf-tools/coverage.py
+++ b/.waf-tools/coverage.py
@@ -1,10 +1,6 @@
 # -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-#
-# Copyright (c) 2014, Regents of the University of California
-#
-# GPL 3.0 license, see the COPYING.md file for more information
 
-from waflib import TaskGen
+from waflib import TaskGen, Logs
 
 def options(opt):
     opt.add_option('--with-coverage', action='store_true', default=False, dest='with_coverage',
@@ -12,6 +8,8 @@
 
 def configure(conf):
     if conf.options.with_coverage:
+        if not conf.options.debug:
+            conf.fatal("Code coverage flags require debug mode compilation (add --debug)")
         conf.check_cxx(cxxflags=['-fprofile-arcs', '-ftest-coverage', '-fPIC'],
                        linkflags=['-fprofile-arcs'], uselib_store='GCOV', mandatory=True)
 
diff --git a/.waf-tools/default-compiler-flags.py b/.waf-tools/default-compiler-flags.py
index 7544cec..e11f7f1 100644
--- a/.waf-tools/default-compiler-flags.py
+++ b/.waf-tools/default-compiler-flags.py
@@ -4,17 +4,37 @@
 
 def options(opt):
     opt.add_option('--debug', '--with-debug', action='store_true', default=False, dest='debug',
-                   help='''Compile in debugging mode without optimizations (-O0 or -Og)''')
+                   help='''Compile in debugging mode with minimal optimizations (-O0 or -Og)''')
 
 def configure(conf):
-    cxx = conf.env['CXX_NAME'] # CXX_NAME represents generic name of the compiler
+    conf.start_msg('Checking C++ compiler version')
+
+    cxx = conf.env['CXX_NAME'] # CXX_NAME is the generic name of the compiler
+    ccver = tuple(int(i) for i in conf.env['CC_VERSION'])
+    errmsg = ''
+    warnmsg = ''
     if cxx == 'gcc':
+        if ccver < (4, 8, 2):
+            errmsg = ('The version of gcc you are using is too old.\n'
+                      'The minimum supported gcc version is 4.8.2.')
         flags = GccFlags()
     elif cxx == 'clang':
+        if ccver < (3, 4, 0):
+            errmsg = ('The version of clang you are using is too old.\n'
+                      'The minimum supported clang version is 3.4.0.')
         flags = ClangFlags()
     else:
+        warnmsg = 'Note: %s compiler is unsupported' % cxx
         flags = CompilerFlags()
-        Logs.warn('The code has not yet been tested with %s compiler' % cxx)
+
+    if errmsg:
+        conf.end_msg('.'.join(conf.env['CC_VERSION']), color='RED')
+        conf.fatal(errmsg)
+    elif warnmsg:
+        conf.end_msg('.'.join(conf.env['CC_VERSION']), color='YELLOW')
+        Logs.warn(warnmsg)
+    else:
+        conf.end_msg('.'.join(conf.env['CC_VERSION']))
 
     areCustomCxxflagsPresent = (len(conf.env.CXXFLAGS) > 0)
 
@@ -80,6 +100,7 @@
     self.end_msg(' '.join(supportedFlags))
     self.env.prepend_value('LINKFLAGS', supportedFlags)
 
+
 class CompilerFlags(object):
     def getGeneralFlags(self, conf):
         """Get dict of CXXFLAGS, LINKFLAGS, and DEFINES that are always needed"""
@@ -97,18 +118,25 @@
     """
     This class defines basic flags that work for both gcc and clang compilers
     """
+    def getGeneralFlags(self, conf):
+        flags = super(GccBasicFlags, self).getGeneralFlags(conf)
+        flags['CXXFLAGS'] += ['-std=c++11']
+        return flags
+
     def getDebugFlags(self, conf):
         flags = super(GccBasicFlags, self).getDebugFlags(conf)
         flags['CXXFLAGS'] += ['-O0',
+                              '-Og', # gcc >= 4.8, clang >= 4.0
                               '-g3',
                               '-pedantic',
                               '-Wall',
                               '-Wextra',
                               '-Werror',
-                              '-Wno-unused-parameter',
-                              '-Wno-error=maybe-uninitialized', # Bug #1615
                               '-Wno-error=deprecated-declarations', # Bug #3795
+                              '-Wno-error=maybe-uninitialized', # Bug #1615
+                              '-Wno-unused-parameter',
                               ]
+        flags['LINKFLAGS'] += ['-fuse-ld=gold', '-Wl,-O1']
         return flags
 
     def getOptimizedFlags(self, conf):
@@ -120,32 +148,16 @@
                               '-Wextra',
                               '-Wno-unused-parameter',
                               ]
+        flags['LINKFLAGS'] += ['-fuse-ld=gold', '-Wl,-O1']
         return flags
 
 class GccFlags(GccBasicFlags):
-    def getGeneralFlags(self, conf):
-        flags = super(GccFlags, self).getGeneralFlags(conf)
-        version = tuple(int(i) for i in conf.env['CC_VERSION'])
-        if version < (4, 6, 0):
-            conf.fatal('The version of gcc you are using (%s) is too old.\n' %
-                       '.'.join(conf.env['CC_VERSION']) +
-                       'The minimum supported gcc version is 4.6.0.')
-        elif version < (4, 7, 0):
-            flags['CXXFLAGS'] += ['-std=c++0x']
-        else:
-            flags['CXXFLAGS'] += ['-std=c++11']
-        if version < (4, 8, 0):
-            flags['DEFINES'] += ['_GLIBCXX_USE_NANOSLEEP'] # Bug #2499
-        return flags
-
     def getDebugFlags(self, conf):
         flags = super(GccFlags, self).getDebugFlags(conf)
         version = tuple(int(i) for i in conf.env['CC_VERSION'])
         if version < (5, 1, 0):
             flags['CXXFLAGS'] += ['-Wno-missing-field-initializers']
-        flags['CXXFLAGS'] += ['-Og', # gcc >= 4.8
-                              '-fdiagnostics-color', # gcc >= 4.9
-                              ]
+        flags['CXXFLAGS'] += ['-fdiagnostics-color'] # gcc >= 4.9
         return flags
 
     def getOptimizedFlags(self, conf):
@@ -159,7 +171,6 @@
 class ClangFlags(GccBasicFlags):
     def getGeneralFlags(self, conf):
         flags = super(ClangFlags, self).getGeneralFlags(conf)
-        flags['CXXFLAGS'] += ['-std=c++11']
         if Utils.unversioned_sys_platform() == 'darwin':
             flags['CXXFLAGS'] += ['-stdlib=libc++']
             flags['LINKFLAGS'] += ['-stdlib=libc++']
@@ -168,24 +179,24 @@
     def getDebugFlags(self, conf):
         flags = super(ClangFlags, self).getDebugFlags(conf)
         flags['CXXFLAGS'] += ['-fcolor-diagnostics',
-                              '-Wno-unused-local-typedef', # Bugs #2657 and #3209
-                              '-Wno-error=unneeded-internal-declaration', # Bug #1588
                               '-Wno-error=deprecated-register',
+                              '-Wno-error=ignored-qualifiers',
+                              '-Wno-error=infinite-recursion', # Bug #3358
                               '-Wno-error=keyword-macro', # Bug #3235
+                              '-Wno-error=unneeded-internal-declaration', # Bug #1588
+                              '-Wno-keyword-macro',
                               '-Wno-nested-anon-types',
                               '-Wno-sign-compare',
-                              '-Wno-keyword-macro',
-                              '-Wno-error=ignored-qualifiers',
-                              '-Wno-error=infinite-recursion',
+                              '-Wno-unused-local-typedef', # Bugs #2657 and #3209
                               ]
         return flags
 
     def getOptimizedFlags(self, conf):
         flags = super(ClangFlags, self).getOptimizedFlags(conf)
         flags['CXXFLAGS'] += ['-fcolor-diagnostics',
-                              '-Wno-unused-local-typedef', # Bugs #2657 and #3209
+                              '-Wno-keyword-macro',
                               '-Wno-nested-anon-types',
                               '-Wno-sign-compare',
-                              '-Wno-keyword-macro',
+                              '-Wno-unused-local-typedef', # Bugs #2657 and #3209
                               ]
         return flags
diff --git a/.waf-tools/doxygen.py b/.waf-tools/doxygen.py
index ac8c70b..6d8066b 100644
--- a/.waf-tools/doxygen.py
+++ b/.waf-tools/doxygen.py
@@ -85,7 +85,7 @@
 
 			# Override with any parameters passed to the task generator
 			if getattr(self.generator, 'pars', None):
-				for k, v in self.generator.pars.iteritems():
+				for k, v in self.generator.pars.items():
 					self.pars[k] = v
 
 			self.doxy_inputs = getattr(self, 'doxy_inputs', [])
diff --git a/wscript b/wscript
index 1f25960..f8471ef 100644
--- a/wscript
+++ b/wscript
@@ -20,20 +20,19 @@
 NLSR, e.g., in COPYING.md file.  If not, see <http://www.gnu.org/licenses/>.
 """
 
-VERSION = '0.3.2'
+VERSION = "0.3.2"
 APPNAME = "nlsr"
-BUGREPORT = "http://redmine.named-data.net/projects/nlsr"
-URL = "http://named-data.net/doc/NLSR/"
+BUGREPORT = "https://redmine.named-data.net/projects/nlsr"
+URL = "https://named-data.net/doc/NLSR/"
 GIT_TAG_PREFIX = "NLSR-"
 
-from waflib import Build, Logs, Utils, Task, TaskGen, Configure, Context
-from waflib.Tools import c_preproc
+from waflib import Logs, Utils, Context
 import os
 
 def options(opt):
     opt.load(['compiler_cxx', 'gnu_dirs'])
     opt.load(['default-compiler-flags', 'coverage', 'sanitizers',
-              'boost',  'doxygen', 'sphinx_build'],
+              'boost', 'doxygen', 'sphinx_build'],
             tooldir=['.waf-tools'])
 
     nlsropt = opt.add_option_group('NLSR Options')
@@ -44,7 +43,7 @@
 
 def configure(conf):
     conf.load(['compiler_cxx', 'gnu_dirs',
-               'boost', 'default-compiler-flags',
+               'default-compiler-flags', 'boost',
                'doxygen', 'sphinx_build'])
 
     if 'PKG_CONFIG_PATH' not in os.environ: