build: Reviving support for precompiled headers

This commit also includes an update of ./waf, which has several
improvements.  In particular, clang++ is now default compiler on OSX
platform.

This commit also includes reorganization of tests. All unit tests are
now under tests/unit-tests and integrated tests are under
tests/integrated.  This change allows small compilation optimization,
partially related to precompiled headers.

Change-Id: I4c171c04d18e9cb83e461264a35b9ed85ea4d50e
diff --git a/.gitignore b/.gitignore
index 21772b9..fc3231c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,7 @@
 *~
 
 # Mac OSX
-.DS_Store
+.DS_*
 
 # waf build system
 .waf-1*
diff --git a/.waf-tools/pch.py b/.waf-tools/pch.py
index b4f8f7f..087d633 100644
--- a/.waf-tools/pch.py
+++ b/.waf-tools/pch.py
@@ -1,38 +1,144 @@
 #! /usr/bin/env python
 # encoding: utf-8
+# Alexander Afanasyev (UCLA), 2014
 
-from waflib import Logs, Utils, Task, TaskGen
-from waflib.Tools import c_preproc
+"""
+Enable precompiled C++ header support (currently only clang++ and g++ are supported)
+
+To use this tool, wscript should look like:
+
+	def options(opt):
+		opt.load('pch')
+		# This will add `--with-pch` configure option.
+		# Unless --with-pch during configure stage specified, the precompiled header support is disabled
+
+	def configure(conf):
+		conf.load('pch')
+		# this will set conf.env.WITH_PCH if --with-pch is specified and the supported compiler is used
+		# Unless conf.env.WITH_PCH is set, the precompiled header support is disabled
+
+	def build(bld):
+		bld(features='cxx pch',
+			target='precompiled-headers',
+			name='precompiled-headers',
+			headers='a.h b.h c.h', # headers to pre-compile into `precompiled-headers`
+
+			# Other parameters to compile precompiled headers
+			# includes=...,
+			# export_includes=...,
+			# use=...,
+			# ...
+
+			# Exported parameters will be propagated even if precompiled headers are disabled
+		)
+
+		bld(
+			target='test',
+			features='cxx cxxprogram',
+			source='a.cpp b.cpp d.cpp main.cpp',
+			use='precompiled-headers',
+		)
+
+		# or
+
+		bld(
+			target='test',
+			features='pch cxx cxxprogram',
+			source='a.cpp b.cpp d.cpp main.cpp',
+			headers='a.h b.h c.h',
+		)
+
+Note that precompiled header must have multiple inclusion guards.  If the guards are missing, any benefit of precompiled header will be voided and compilation may fail in some cases.
+"""
+
+import os
+from waflib import Task, TaskGen, Logs, Utils
+from waflib.Tools import c_preproc, cxx
+
+
+PCH_COMPILER_OPTIONS = {
+	'clang++': [['-include'], '.pch', ['-x', 'c++-header']],
+	'g++':     [['-include'], '.gch', ['-x', 'c++-header']],
+}
+
 
 def options(opt):
-    opt.add_option('--with-pch', action='store_true', default=False, dest='with_pch',
-                   help='''Try to use precompiled header to speed up compilation '''
-                        '''(only gcc and clang)''')
+	opt.add_option('--without-pch', action='store_false', default=True, dest='with_pch', help='''Try to use precompiled header to speed up compilation (only g++ and clang++)''')
 
 def configure(conf):
-    conf.env['WITH_PCH'] = conf.options.with_pch
+	if (conf.options.with_pch and conf.env['COMPILER_CXX'] in PCH_COMPILER_OPTIONS.keys()):
+		conf.env.WITH_PCH = True
+		flags = PCH_COMPILER_OPTIONS[conf.env['COMPILER_CXX']]
+		conf.env.CXXPCH_F = flags[0]
+		conf.env.CXXPCH_EXT = flags[1]
+		conf.env.CXXPCH_FLAGS = flags[2]
 
 
+@TaskGen.feature('pch')
+@TaskGen.before('process_source')
+def apply_pch(self):
+	if not self.env.WITH_PCH:
+		return
+
+	if getattr(self.bld, 'pch_tasks', None) is None:
+		self.bld.pch_tasks = {}
+
+        if getattr(self, 'headers', None) is None:
+		return
+
+	self.headers = self.to_nodes(self.headers)
+
+	if getattr(self, 'name', None):
+		try:
+			task = self.bld.pch_tasks[self.name]
+			self.bld.fatal("Duplicated 'pch' task with name %r" % self.name)
+		except KeyError:
+			pass
+
+	out = '%s.%d%s' % (self.target, self.idx, self.env['CXXPCH_EXT'])
+	out = self.path.find_or_declare(out)
+	task = self.create_task('gchx', self.headers, out)
+
+	# target should be an absolute path of `out`, but without precompiled header extension
+	task.target = out.abspath()[:-len(out.suffix())]
+
+        self.pch_task = task
+	if getattr(self, 'name', None):
+		self.bld.pch_tasks[self.name] = task
+
 @TaskGen.feature('cxx')
-@TaskGen.before('process_source')
-def process_pch(self):
-    if getattr(self, 'pch', ''):
-        # for now support only gcc-compatible things
-        if self.env['COMPILER_CXX'] == 'g++':
-            nodes = self.to_nodes(self.pch, path=self.path)
-            for x in nodes:
-                z = self.create_task('gchx', x, x.change_ext('.hpp.gch'))
-                z.orig_self = self
+@TaskGen.after_method('process_source', 'propagate_uselib_vars')
+def add_pch(self):
+	if not (self.env['WITH_PCH'] and getattr(self, 'use', None) and getattr(self, 'compiled_tasks', None) and getattr(self.bld, 'pch_tasks', None)):
+		return
+
+	pch = None
+	# find pch task, if any
+
+	if getattr(self, 'pch_task', None):
+		pch = self.pch_task
+	else:
+		for use in Utils.to_list(self.use):
+			try:
+				pch = self.bld.pch_tasks[use]
+			except KeyError:
+				pass
+
+	if pch:
+		for x in self.compiled_tasks:
+			x.env.append_value('CXXFLAGS', self.env['CXXPCH_F'] + [pch.target])
 
 class gchx(Task.Task):
-    run_str = '${CXX} -x c++-header ${CXXFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ' + \
-                '${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ' + \
-                '${CXX_SRC_F}${SRC} ${CXX_TGT_F}${TGT}'
-    scan    = c_preproc.scan
-    ext_out = ['.hpp']
-    color   = 'BLUE'
+	run_str = '${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${CPPFLAGS} ${CXXPCH_FLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXXPCH_F:SRC} ${CXX_SRC_F}${SRC[0].abspath()} ${CXX_TGT_F}${TGT[0].abspath()}'
+	scan    = c_preproc.scan
+	color   = 'BLUE'
+	ext_out=['.h']
 
-    def post_run(self):
-        super(gchx, self).post_run()
-        self.orig_self.env['CXXFLAGS'] = ['-include', self.inputs[0].relpath()] + \
-                                         self.env['CXXFLAGS']
+	def runnable_status(self):
+		ret = Task.Task.runnable_status(self)
+		if ret == Task.SKIP_ME and self.env.CXX_NAME == 'clang':
+			t = os.stat(self.outputs[0].abspath()).st_mtime
+			for n in self.inputs:
+				if os.stat(n.abspath()).st_mtime > t:
+					return Task.RUN_ME
+		return ret
diff --git a/.waf-tools/sphinx_build.py b/.waf-tools/sphinx_build.py
index bd3905b..e61da6e 100644
--- a/.waf-tools/sphinx_build.py
+++ b/.waf-tools/sphinx_build.py
@@ -12,8 +12,8 @@
 
     def __str__(self):
         env = self.env
-        src_str = ' '.join([a.nice_path()for a in self.inputs])
-        tgt_str = ' '.join([a.nice_path()for a in self.outputs])
+        src_str = ' '.join([a.path_from(a.ctx.launch_node()) for a in self.inputs])
+        tgt_str = ' '.join([a.path_from(a.ctx.launch_node()) for a in self.outputs])
         if self.outputs: sep = ' -> '
         else: sep = ''
         return'%s [%s]: %s%s%s\n'%(self.__class__.__name__.replace('_task',''),
diff --git a/src/common-pch.hpp b/src/common-pch.hpp
index 3d6c56f..b82f79d 100644
--- a/src/common-pch.hpp
+++ b/src/common-pch.hpp
@@ -41,10 +41,18 @@
 // Other useful headers to precompile
 #include <boost/lexical_cast.hpp>
 #include <boost/asio.hpp>
+#include <boost/chrono.hpp>
 #include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/info_parser.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/regex.hpp>
+#include <boost/algorithm/string.hpp>
 
 #include <boost/iostreams/detail/ios.hpp>
 #include <boost/iostreams/categories.hpp>
 #include <boost/iostreams/stream.hpp>
 
+#include "security/cryptopp.hpp"
+
 #endif // NDN_COMMON_PCH_HPP
diff --git a/tests-integrated/boost-test.hpp b/tests-integrated/boost-test.hpp
deleted file mode 100644
index 1679841..0000000
--- a/tests-integrated/boost-test.hpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2014 Regents of the University of California.
- *
- * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
- *
- * ndn-cxx library is free software: you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
- *
- * You should have received copies of the GNU General Public License and GNU Lesser
- * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- */
-
-#ifndef NDN_TESTS_INTEGRATED_BOOST_TEST_HPP
-#define NDN_TESTS_INTEGRATED_BOOST_TEST_HPP
-
-// suppress warnings from Boost.Test
-#pragma GCC system_header
-#pragma clang system_header
-
-#include <boost/test/unit_test.hpp>
-#include <boost/concept_check.hpp>
-#include <boost/test/output_test_stream.hpp>
-
-#endif // NDN_TESTS_INTEGRATED_BOOST_TEST_HPP
diff --git a/tests-integrated/main.cpp b/tests-integrated/main.cpp
deleted file mode 100644
index 3d3a773..0000000
--- a/tests-integrated/main.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2014 Regents of the University of California.
- *
- * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
- *
- * ndn-cxx library is free software: you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
- *
- * You should have received copies of the GNU General Public License and GNU Lesser
- * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- */
-
-#define BOOST_TEST_MAIN 1
-#define BOOST_TEST_DYN_LINK 1
-
-#include "boost-test.hpp"
diff --git a/tests-integrated/test-all.hpp b/tests-integrated/test-all.hpp
deleted file mode 100644
index aa97e21..0000000
--- a/tests-integrated/test-all.hpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2014 Regents of the University of California.
- *
- * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
- *
- * ndn-cxx library is free software: you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
- *
- * You should have received copies of the GNU General Public License and GNU Lesser
- * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- */
-
-// This file is needed for experimental precompiled header support (gcc and clang)
-
-#ifndef NDN_TESTS_INTEGRATED_TEST_ALL_HPP
-#define NDN_TESTS_INTEGRATED_TEST_ALL_HPP
-
-#include "common.hpp"
-
-#endif // NDN_TESTS_INTEGRATED_TEST_ALL_HPP
diff --git a/tests-integrated/wscript b/tests-integrated/wscript
deleted file mode 100644
index 75f6b5c..0000000
--- a/tests-integrated/wscript
+++ /dev/null
@@ -1,25 +0,0 @@
-# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-
-from waflib import Utils
-
-top = '..'
-
-def build(bld):
-    unittests = bld.program (
-        target="../integrated-tests",
-        features="cxx cxxprogram",
-        source=bld.path.ant_glob(['**/*.cpp'],
-                                 excl=['**/*-osx.cpp', '**/*-sqlite3.cpp']),
-        use='ndn-cxx',
-        includes='.',
-        install_path=None,
-        )
-
-    if bld.env['HAVE_OSX_SECURITY']:
-        unittests.source += bld.path.ant_glob('**/*-osx.cpp')
-
-    # In case we want to make it optional later
-    unittests.source += bld.path.ant_glob('**/*-sqlite3.cpp')
-
-    if bld.env['WITH_PCH']:
-        unittests.pch = "test-all.hpp"
diff --git a/tests-integrated/test-faces.cpp b/tests/integrated/test-faces.cpp
similarity index 100%
rename from tests-integrated/test-faces.cpp
rename to tests/integrated/test-faces.cpp
diff --git a/tests-integrated/security/test-validator-config.cpp b/tests/integrated/test-validator-config.cpp
similarity index 100%
rename from tests-integrated/security/test-validator-config.cpp
rename to tests/integrated/test-validator-config.cpp
diff --git a/tests/integrated/wscript b/tests/integrated/wscript
new file mode 100644
index 0000000..d5d9af7
--- /dev/null
+++ b/tests/integrated/wscript
@@ -0,0 +1,29 @@
+# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+from waflib import Utils
+
+top = '..'
+
+def build(bld):
+    unittests = bld(
+        target="integrated-test-objects",
+        name="integrated-test-objects",
+        features="cxx",
+        source=bld.path.ant_glob(['**/*.cpp'],
+                                 excl=['main.cpp', '**/*-osx.cpp', '**/*-sqlite3.cpp']),
+        use='tests-base',
+        includes='.',
+        install_path=None,
+        )
+
+    if bld.env['HAVE_OSX_SECURITY']:
+        unittests.source += bld.path.ant_glob('**/*-osx.cpp')
+
+    # In case we want to make it optional later
+    unittests.source += bld.path.ant_glob('**/*-sqlite3.cpp')
+
+    bld.program(
+        target="../integrated-tests",
+        use="integrated-test-objects",
+        source="main.cpp",
+        install_path=None)
diff --git a/tests/test-all.hpp b/tests/test-all.hpp
deleted file mode 100644
index 0461e46..0000000
--- a/tests/test-all.hpp
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2013-2014 Regents of the University of California.
- *
- * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
- *
- * ndn-cxx library is free software: you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
- *
- * You should have received copies of the GNU General Public License and GNU Lesser
- * General Public License along with ndn-cxx, e.g., in COPYING.md file.  If not, see
- * <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
- */
-
-// This file is needed for experimental precompiled header support (gcc and clang)
-
-#ifndef NDN_TESTS_TEST_ALL_HPP
-#define NDN_TESTS_TEST_ALL_HPP
-
-#include "common.hpp"
-
-#endif
diff --git a/tests/management/test-nfd-channel-status.cpp b/tests/unit-tests/management/test-nfd-channel-status.cpp
similarity index 100%
rename from tests/management/test-nfd-channel-status.cpp
rename to tests/unit-tests/management/test-nfd-channel-status.cpp
diff --git a/tests/management/test-nfd-control-command.cpp b/tests/unit-tests/management/test-nfd-control-command.cpp
similarity index 100%
rename from tests/management/test-nfd-control-command.cpp
rename to tests/unit-tests/management/test-nfd-control-command.cpp
diff --git a/tests/management/test-nfd-control-parameters.cpp b/tests/unit-tests/management/test-nfd-control-parameters.cpp
similarity index 100%
rename from tests/management/test-nfd-control-parameters.cpp
rename to tests/unit-tests/management/test-nfd-control-parameters.cpp
diff --git a/tests/management/test-nfd-control-response.cpp b/tests/unit-tests/management/test-nfd-control-response.cpp
similarity index 100%
rename from tests/management/test-nfd-control-response.cpp
rename to tests/unit-tests/management/test-nfd-control-response.cpp
diff --git a/tests/management/test-nfd-controller.cpp b/tests/unit-tests/management/test-nfd-controller.cpp
similarity index 100%
rename from tests/management/test-nfd-controller.cpp
rename to tests/unit-tests/management/test-nfd-controller.cpp
diff --git a/tests/management/test-nfd-face-event-notification.cpp b/tests/unit-tests/management/test-nfd-face-event-notification.cpp
similarity index 100%
rename from tests/management/test-nfd-face-event-notification.cpp
rename to tests/unit-tests/management/test-nfd-face-event-notification.cpp
diff --git a/tests/management/test-nfd-face-status.cpp b/tests/unit-tests/management/test-nfd-face-status.cpp
similarity index 100%
rename from tests/management/test-nfd-face-status.cpp
rename to tests/unit-tests/management/test-nfd-face-status.cpp
diff --git a/tests/management/test-nfd-fib-entry.cpp b/tests/unit-tests/management/test-nfd-fib-entry.cpp
similarity index 100%
rename from tests/management/test-nfd-fib-entry.cpp
rename to tests/unit-tests/management/test-nfd-fib-entry.cpp
diff --git a/tests/management/test-nfd-forwarder-status.cpp b/tests/unit-tests/management/test-nfd-forwarder-status.cpp
similarity index 100%
rename from tests/management/test-nfd-forwarder-status.cpp
rename to tests/unit-tests/management/test-nfd-forwarder-status.cpp
diff --git a/tests/management/test-nfd-strategy-choice.cpp b/tests/unit-tests/management/test-nfd-strategy-choice.cpp
similarity index 100%
rename from tests/management/test-nfd-strategy-choice.cpp
rename to tests/unit-tests/management/test-nfd-strategy-choice.cpp
diff --git a/tests/security/config-file-empty-home/.ndn/client.conf b/tests/unit-tests/security/config-file-empty-home/.ndn/client.conf
similarity index 100%
rename from tests/security/config-file-empty-home/.ndn/client.conf
rename to tests/unit-tests/security/config-file-empty-home/.ndn/client.conf
diff --git a/tests/security/config-file-home/.ndn/client.conf b/tests/unit-tests/security/config-file-home/.ndn/client.conf
similarity index 100%
rename from tests/security/config-file-home/.ndn/client.conf
rename to tests/unit-tests/security/config-file-home/.ndn/client.conf
diff --git a/tests/security/config-file-malformed-home/.ndn/client.conf b/tests/unit-tests/security/config-file-malformed-home/.ndn/client.conf
similarity index 100%
rename from tests/security/config-file-malformed-home/.ndn/client.conf
rename to tests/unit-tests/security/config-file-malformed-home/.ndn/client.conf
diff --git a/tests/security/config-file-malformed2-home/.ndn/client.conf b/tests/unit-tests/security/config-file-malformed2-home/.ndn/client.conf
similarity index 100%
rename from tests/security/config-file-malformed2-home/.ndn/client.conf
rename to tests/unit-tests/security/config-file-malformed2-home/.ndn/client.conf
diff --git a/tests/security/identity-fixture.cpp b/tests/unit-tests/security/identity-fixture.cpp
similarity index 100%
rename from tests/security/identity-fixture.cpp
rename to tests/unit-tests/security/identity-fixture.cpp
diff --git a/tests/security/test-certificate-cache.cpp b/tests/unit-tests/security/test-certificate-cache.cpp
similarity index 100%
rename from tests/security/test-certificate-cache.cpp
rename to tests/unit-tests/security/test-certificate-cache.cpp
diff --git a/tests/security/test-encode-decode-certificate.cpp b/tests/unit-tests/security/test-encode-decode-certificate.cpp
similarity index 100%
rename from tests/security/test-encode-decode-certificate.cpp
rename to tests/unit-tests/security/test-encode-decode-certificate.cpp
diff --git a/tests/security/test-keychain.cpp b/tests/unit-tests/security/test-keychain.cpp
similarity index 95%
rename from tests/security/test-keychain.cpp
rename to tests/unit-tests/security/test-keychain.cpp
index b1de28d..9a2300d 100644
--- a/tests/security/test-keychain.cpp
+++ b/tests/unit-tests/security/test-keychain.cpp
@@ -56,7 +56,7 @@
 {
   using namespace boost::filesystem;
 
-  setenv("TEST_HOME", "tests/security/config-file-home", 1);
+  setenv("TEST_HOME", "tests/unit-tests/security/config-file-home", 1);
 
   BOOST_REQUIRE_NO_THROW(KeyChain());
 
@@ -70,7 +70,7 @@
 {
   using namespace boost::filesystem;
 
-  setenv("TEST_HOME", "tests/security/config-file-empty-home", 1);
+  setenv("TEST_HOME", "tests/unit-tests/security/config-file-empty-home", 1);
 
   BOOST_REQUIRE_NO_THROW(KeyChain());
 
@@ -84,7 +84,7 @@
 {
   using namespace boost::filesystem;
 
-  setenv("TEST_HOME", "tests/security/config-file-malformed-home", 1);
+  setenv("TEST_HOME", "tests/unit-tests/security/config-file-malformed-home", 1);
 
   BOOST_REQUIRE_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected.
 }
@@ -93,7 +93,7 @@
 {
   using namespace boost::filesystem;
 
-  setenv("TEST_HOME", "tests/security/config-file-malformed2-home", 1);
+  setenv("TEST_HOME", "tests/unit-tests/security/config-file-malformed2-home", 1);
 
   BOOST_REQUIRE_THROW(KeyChain(), KeyChain::Error); // Wrong configuration. Error expected.
 }
diff --git a/tests/security/test-sec-public-info-sqlite3.cpp b/tests/unit-tests/security/test-sec-public-info-sqlite3.cpp
similarity index 100%
rename from tests/security/test-sec-public-info-sqlite3.cpp
rename to tests/unit-tests/security/test-sec-public-info-sqlite3.cpp
diff --git a/tests/security/test-sec-tpm-file.cpp b/tests/unit-tests/security/test-sec-tpm-file.cpp
similarity index 100%
rename from tests/security/test-sec-tpm-file.cpp
rename to tests/unit-tests/security/test-sec-tpm-file.cpp
diff --git a/tests/security/test-sec-tpm-osx.cpp b/tests/unit-tests/security/test-sec-tpm-osx.cpp
similarity index 100%
rename from tests/security/test-sec-tpm-osx.cpp
rename to tests/unit-tests/security/test-sec-tpm-osx.cpp
diff --git a/tests/security/test-signature-sha256.cpp b/tests/unit-tests/security/test-signature-sha256.cpp
similarity index 100%
rename from tests/security/test-signature-sha256.cpp
rename to tests/unit-tests/security/test-signature-sha256.cpp
diff --git a/tests/security/test-signed-interest.cpp b/tests/unit-tests/security/test-signed-interest.cpp
similarity index 100%
rename from tests/security/test-signed-interest.cpp
rename to tests/unit-tests/security/test-signed-interest.cpp
diff --git a/tests/security/test-validator.cpp b/tests/unit-tests/security/test-validator.cpp
similarity index 100%
rename from tests/security/test-validator.cpp
rename to tests/unit-tests/security/test-validator.cpp
diff --git a/tests/test-block.cpp b/tests/unit-tests/test-block.cpp
similarity index 99%
rename from tests/test-block.cpp
rename to tests/unit-tests/test-block.cpp
index ae66927..c653177 100644
--- a/tests/test-block.cpp
+++ b/tests/unit-tests/test-block.cpp
@@ -19,6 +19,7 @@
  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
  */
 
+
 #include "encoding/encoding-buffer.hpp"
 #include "encoding/buffer-stream.hpp"
 
diff --git a/tests/test-data.cpp b/tests/unit-tests/test-data.cpp
similarity index 100%
rename from tests/test-data.cpp
rename to tests/unit-tests/test-data.cpp
diff --git a/tests/test-exclude.cpp b/tests/unit-tests/test-exclude.cpp
similarity index 100%
rename from tests/test-exclude.cpp
rename to tests/unit-tests/test-exclude.cpp
diff --git a/tests/test-interest.cpp b/tests/unit-tests/test-interest.cpp
similarity index 100%
rename from tests/test-interest.cpp
rename to tests/unit-tests/test-interest.cpp
diff --git a/tests/test-key-locator.cpp b/tests/unit-tests/test-key-locator.cpp
similarity index 100%
rename from tests/test-key-locator.cpp
rename to tests/unit-tests/test-key-locator.cpp
diff --git a/tests/test-name.cpp b/tests/unit-tests/test-name.cpp
similarity index 100%
rename from tests/test-name.cpp
rename to tests/unit-tests/test-name.cpp
diff --git a/tests/test-version.cpp b/tests/unit-tests/test-version.cpp
similarity index 100%
rename from tests/test-version.cpp
rename to tests/unit-tests/test-version.cpp
diff --git a/tests/transport/dummy-face.hpp b/tests/unit-tests/transport/dummy-face.hpp
similarity index 93%
rename from tests/transport/dummy-face.hpp
rename to tests/unit-tests/transport/dummy-face.hpp
index 3ecec7b..fd724b0 100644
--- a/tests/transport/dummy-face.hpp
+++ b/tests/unit-tests/transport/dummy-face.hpp
@@ -19,8 +19,8 @@
  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
  */
 
-#ifndef NDN_TESTS_TRANSPORT_DUMMY_FACE_HPP
-#define NDN_TESTS_TRANSPORT_DUMMY_FACE_HPP
+#ifndef NDN_TESTS_UNIT_TESTS_TRANSPORT_DUMMY_FACE_HPP
+#define NDN_TESTS_UNIT_TESTS_TRANSPORT_DUMMY_FACE_HPP
 
 #include "face.hpp"
 #include "transport/transport.hpp"
@@ -113,4 +113,4 @@
 
 } // namespace ndn
 
-#endif // NDN_TESTS_TRANSPORT_DUMMY_FACE_HPP
+#endif // NDN_TESTS_UNIT_TESTS_TRANSPORT_DUMMY_FACE_HPP
diff --git a/tests/transport/test-homes/missing-unix-socket-missing-protocol/.ndn/client.conf b/tests/unit-tests/transport/test-homes/missing-unix-socket-missing-protocol/.ndn/client.conf
similarity index 100%
rename from tests/transport/test-homes/missing-unix-socket-missing-protocol/.ndn/client.conf
rename to tests/unit-tests/transport/test-homes/missing-unix-socket-missing-protocol/.ndn/client.conf
diff --git a/tests/transport/test-homes/missing-unix-socket-with-ndnd-protocol/.ndn/client.conf b/tests/unit-tests/transport/test-homes/missing-unix-socket-with-ndnd-protocol/.ndn/client.conf
similarity index 100%
rename from tests/transport/test-homes/missing-unix-socket-with-ndnd-protocol/.ndn/client.conf
rename to tests/unit-tests/transport/test-homes/missing-unix-socket-with-ndnd-protocol/.ndn/client.conf
diff --git a/tests/transport/test-homes/missing-unix-socket-with-protocol/.ndn/client.conf b/tests/unit-tests/transport/test-homes/missing-unix-socket-with-protocol/.ndn/client.conf
similarity index 100%
rename from tests/transport/test-homes/missing-unix-socket-with-protocol/.ndn/client.conf
rename to tests/unit-tests/transport/test-homes/missing-unix-socket-with-protocol/.ndn/client.conf
diff --git a/tests/transport/test-homes/ok/.ndn/client.conf b/tests/unit-tests/transport/test-homes/ok/.ndn/client.conf
similarity index 100%
rename from tests/transport/test-homes/ok/.ndn/client.conf
rename to tests/unit-tests/transport/test-homes/ok/.ndn/client.conf
diff --git a/tests/transport/test-unix-transport.cpp b/tests/unit-tests/transport/test-unix-transport.cpp
similarity index 86%
rename from tests/transport/test-unix-transport.cpp
rename to tests/unit-tests/transport/test-unix-transport.cpp
index 513191c..6c20302 100644
--- a/tests/transport/test-unix-transport.cpp
+++ b/tests/unit-tests/transport/test-unix-transport.cpp
@@ -48,7 +48,7 @@
 
 BOOST_AUTO_TEST_CASE(TestGetDefaultSocketNameOk)
 {
-  setenv("HOME", "tests/transport/test-homes/ok", 1);
+  setenv("HOME", "tests/unit-tests/transport/test-homes/ok", 1);
 
   ConfigFile config;
   BOOST_REQUIRE_EQUAL(UnixTransport::getDefaultSocketName(config), "/tmp/test/nfd.sock");
@@ -56,21 +56,21 @@
 
 BOOST_AUTO_TEST_CASE(TestGetDefaultSocketNameMissingSocketMissingProtocol)
 {
-  setenv("HOME", "tests/transport/test-homes/missing-unix-socket-missing-protocol", 1);
+  setenv("HOME", "tests/unit-tests/transport/test-homes/missing-unix-socket-missing-protocol", 1);
   ConfigFile config;
   BOOST_REQUIRE_EQUAL(UnixTransport::getDefaultSocketName(config), "/var/run/nfd.sock");
 }
 
 BOOST_AUTO_TEST_CASE(TestGetDefaultSocketNameMissingSocketNdndProtocol)
 {
-  setenv("HOME", "tests/transport/test-homes/missing-unix-socket-with-ndnd-protocol", 1);
+  setenv("HOME", "tests/unit-tests/transport/test-homes/missing-unix-socket-with-ndnd-protocol", 1);
   ConfigFile config;
   BOOST_REQUIRE_EQUAL(UnixTransport::getDefaultSocketName(config), "/tmp/.ndnd.sock");
 }
 
 BOOST_AUTO_TEST_CASE(TestGetDefaultSocketNameMissingSocketWithProtocol)
 {
-  setenv("HOME", "tests/transport/test-homes/missing-unix-socket-with-protocol", 1);
+  setenv("HOME", "tests/unit-tests/transport/test-homes/missing-unix-socket-with-protocol", 1);
   ConfigFile config;
   BOOST_REQUIRE_EQUAL(UnixTransport::getDefaultSocketName(config), "/var/run/nfd.sock");
 }
diff --git a/tests/util/config-file-home/.ndn/client.conf b/tests/unit-tests/util/config-file-home/.ndn/client.conf
similarity index 100%
rename from tests/util/config-file-home/.ndn/client.conf
rename to tests/unit-tests/util/config-file-home/.ndn/client.conf
diff --git a/tests/util/config-file-malformed-home/.ndn/client.conf b/tests/unit-tests/util/config-file-malformed-home/.ndn/client.conf
similarity index 100%
rename from tests/util/config-file-malformed-home/.ndn/client.conf
rename to tests/unit-tests/util/config-file-malformed-home/.ndn/client.conf
diff --git a/tests/util/test-config-file.cpp b/tests/unit-tests/util/test-config-file.cpp
similarity index 93%
rename from tests/util/test-config-file.cpp
rename to tests/unit-tests/util/test-config-file.cpp
index 720d81e..9a0b680 100644
--- a/tests/util/test-config-file.cpp
+++ b/tests/unit-tests/util/test-config-file.cpp
@@ -53,7 +53,7 @@
   using namespace boost::filesystem;
   // std::cerr << "current home = " << std::getenv("HOME") << std::endl;
 
-  setenv("HOME", "tests/util/config-file-home", 1);
+  setenv("HOME", "tests/unit-tests/util/config-file-home", 1);
 
   path homePath(absolute(std::getenv("HOME")));
   homePath /= ".ndn/client.conf";
@@ -78,7 +78,7 @@
 {
   // std::cerr << "current home = " << std::getenv("HOME") << std::endl;
 
-  setenv("HOME", "tests/util/does/not/exist", 1);
+  setenv("HOME", "tests/unit-tests/util/does/not/exist", 1);
   try
     {
       ConfigFile config;
@@ -94,7 +94,7 @@
   using namespace boost::filesystem;
   // std::cerr << "current home = " << std::getenv("HOME") << std::endl;
 
-  setenv("HOME", "tests/util/config-file-malformed-home", 1);
+  setenv("HOME", "tests/unit-tests/util/config-file-malformed-home", 1);
 
   bool fileWasMalformed = false;
   try
diff --git a/tests/util/test-io.cpp b/tests/unit-tests/util/test-io.cpp
similarity index 100%
rename from tests/util/test-io.cpp
rename to tests/unit-tests/util/test-io.cpp
diff --git a/tests/util/test-regex.cpp b/tests/unit-tests/util/test-regex.cpp
similarity index 100%
rename from tests/util/test-regex.cpp
rename to tests/unit-tests/util/test-regex.cpp
diff --git a/tests/util/test-scheduler.cpp b/tests/unit-tests/util/test-scheduler.cpp
similarity index 100%
rename from tests/util/test-scheduler.cpp
rename to tests/unit-tests/util/test-scheduler.cpp
diff --git a/tests/util/test-time.cpp b/tests/unit-tests/util/test-time.cpp
similarity index 100%
rename from tests/util/test-time.cpp
rename to tests/unit-tests/util/test-time.cpp
diff --git a/tests/wscript b/tests/wscript
index cbe5e88..5a602d3 100644
--- a/tests/wscript
+++ b/tests/wscript
@@ -5,21 +5,58 @@
 top = '..'
 
 def build(bld):
-    unittests = bld.program (
-        target="../unit-tests",
-        features="cxx cxxprogram",
-        source=bld.path.ant_glob(['**/*.cpp'],
-                                 excl=['**/*-osx.cpp', '**/*-sqlite3.cpp']),
+    bld(features=['cxx', 'pch'],
+        name='tests-base',
+        target='tests-base',
+        headers=['../src/common-pch.hpp', 'boost-test.hpp'],
         use='ndn-cxx',
         includes='.',
+        )
+
+    unit_tests = bld(
+        target="unit-test-objects",
+        name="unit-test-objects",
+        features="cxx",
+        source=bld.path.ant_glob(['unit-tests/**/*.cpp'],
+                                 excl=['**/*-osx.cpp', '**/*-sqlite3.cpp']),
+        use='tests-base',
+        includes='.',
+        install_path=None,
+        )
+
+    integrated = bld(
+        target="integrated-test-objects",
+        name="integrated-test-objects",
+        features="cxx",
+        source=bld.path.ant_glob(['integrated/**/*.cpp'],
+                                 excl=['**/*-osx.cpp', '**/*-sqlite3.cpp']),
+        use='tests-base',
+        includes='.',
         install_path=None,
         )
 
     if bld.env['HAVE_OSX_SECURITY']:
-        unittests.source += bld.path.ant_glob('**/*-osx.cpp')
+        unit_tests.source += bld.path.ant_glob('unit-tests/**/*-osx.cpp')
+        integrated.source += bld.path.ant_glob('integrated/**/*-osx.cpp')
 
     # In case we want to make it optional later
-    unittests.source += bld.path.ant_glob('**/*-sqlite3.cpp')
+    unit_tests.source += bld.path.ant_glob('unit-tests/**/*-sqlite3.cpp')
+    integrated.source += bld.path.ant_glob('integrated/**/*-sqlite3.cpp')
 
-    if bld.env['WITH_PCH']:
-        unittests.pch = "test-all.hpp"
+    unit_test_main = bld(
+        target='unit-tests-main',
+        name='unit-tests-main',
+        features='cxx',
+        source=bld.path.ant_glob(['*.cpp']),
+        use='ndn-cxx',
+    )
+
+    bld(features="cxx cxxprogram",
+        target="../unit-tests",
+        use="unit-test-objects unit-tests-main",
+        install_path=None)
+
+    bld(features="cxx cxxprogram",
+        target="../integrated-tests",
+        use="integrated-test-objects unit-tests-main",
+        install_path=None)
diff --git a/waf b/waf
index 78a44f3..7828844 100755
--- a/waf
+++ b/waf
Binary files differ
diff --git a/wscript b/wscript
index 62743e0..ef522e9 100644
--- a/wscript
+++ b/wscript
@@ -50,7 +50,7 @@
     conf.check_cxx(lib='pthread', uselib_store='PTHREAD', define_name='HAVE_PTHREAD',
                    mandatory=False)
     conf.check_cxx(lib='rt', uselib_store='RT', define_name='HAVE_RT', mandatory=False)
-    conf.check_cxx(cxxflags=['-fPIC'], uselib_store='cxxstlib', mandatory=False)
+    conf.check_cxx(cxxflags=['-fPIC'], uselib_store='PIC', mandatory=False)
 
     conf.check_osx_security(mandatory=False)
 
@@ -116,21 +116,19 @@
         )
 
     libndn_cxx = bld(
-        features=['cxx', 'cxxstlib'], # 'cxxshlib',
+        features=['pch', 'cxx', 'cxxstlib'], # 'cxxshlib',
         # vnum=VERSION,
         target="ndn-cxx",
         name="ndn-cxx",
         source=bld.path.ant_glob('src/**/*.cpp',
                                    excl=['src/**/*-osx.cpp', 'src/**/*-sqlite3.cpp']),
+        headers='src/common-pch.hpp',
         use='version BOOST OPENSSL CRYPTOPP SQLITE3 RT PIC PTHREAD',
         includes=". src",
         export_includes="src",
         install_path='${LIBDIR}',
         )
 
-    if bld.env['WITH_PCH']:
-        libndn_cxx.pch="src/common.hpp"
-
     if bld.env['HAVE_OSX_SECURITY']:
         libndn_cxx.source += bld.path.ant_glob('src/**/*-osx.cpp')
         libndn_cxx.mac_app = True
@@ -184,7 +182,6 @@
     # Unit tests
     if bld.env['WITH_TESTS']:
         bld.recurse('tests')
-        bld.recurse('tests-integrated')
 
     if bld.env['WITH_TOOLS']:
         bld.recurse("tools")