build: add PCHs for ndnsec and unit tests, fine-tune the existing ones

A full debug+tests build now takes 10% less time with gcc-9 and 21% less
with clang-10. Release builds (without tests) are only marginally faster
with gcc and 7% faster with clang.

Change-Id: I494778fe44cecc6209819a49f48a03f4d16c36af
diff --git a/ndn-cxx/encoding/nfd-constants.cpp b/ndn-cxx/encoding/nfd-constants.cpp
index 9547351..43770a9 100644
--- a/ndn-cxx/encoding/nfd-constants.cpp
+++ b/ndn-cxx/encoding/nfd-constants.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -23,7 +23,7 @@
 #include "ndn-cxx/util/ostream-joiner.hpp"
 #include "ndn-cxx/util/string-helper.hpp"
 
-#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/predicate.hpp>
 #include <boost/lexical_cast.hpp>
 #include <istream>
 #include <map>
diff --git a/ndn-cxx/encoding/tlv.hpp b/ndn-cxx/encoding/tlv.hpp
index a3b6979..f27c1cb 100644
--- a/ndn-cxx/encoding/tlv.hpp
+++ b/ndn-cxx/encoding/tlv.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -27,7 +27,6 @@
 #include <cstring>
 #include <iterator>
 #include <ostream>
-#include <type_traits>
 #include <vector>
 
 #include <boost/endian/conversion.hpp>
diff --git a/ndn-cxx/impl/common-pch.hpp b/ndn-cxx/impl/common-pch.hpp
index 877c6e7..003989c 100644
--- a/ndn-cxx/impl/common-pch.hpp
+++ b/ndn-cxx/impl/common-pch.hpp
@@ -26,29 +26,32 @@
 // and included before anything else
 
 #include "ndn-cxx/detail/common.hpp"
+#include "ndn-cxx/security/impl/openssl.hpp"
 
 // STL headers to precompile
-#include <array>
-#include <cstring>
-#include <fstream>
+#include <atomic>
 #include <iterator>
 #include <list>
-#include <map>
-#include <set>
-#include <sstream>
+#include <ostream>
 #include <unordered_map>
+#include <unordered_set>
 #include <vector>
 
 // Boost headers to precompile
-#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/algorithm/string/split.hpp>
+#include <boost/asio/basic_socket.hpp>
+#include <boost/bind/bind.hpp>
 #include <boost/chrono.hpp>
 #include <boost/endian/conversion.hpp>
-#include <boost/filesystem.hpp>
-#include <boost/iostreams/categories.hpp>
 #include <boost/iostreams/stream.hpp>
 #include <boost/lexical_cast.hpp>
+#include <boost/log/common.hpp>
+#include <boost/log/expressions/keyword.hpp>
 #include <boost/multi_index_container.hpp>
-#include <boost/range/adaptors.hpp>
-#include <boost/range/algorithm/copy.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/system/error_code.hpp>
 
 #endif // NDN_IMPL_COMMON_PCH_HPP
diff --git a/ndn-cxx/net/face-uri.cpp b/ndn-cxx/net/face-uri.cpp
index 191ab3c..56e5dab 100644
--- a/ndn-cxx/net/face-uri.cpp
+++ b/ndn-cxx/net/face-uri.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California,
+ * Copyright (c) 2013-2020 Regents of the University of California,
  *                         Arizona Board of Regents,
  *                         Colorado State University,
  *                         University Pierre & Marie Curie, Sorbonne University,
@@ -29,10 +29,11 @@
 #include "ndn-cxx/net/dns.hpp"
 #include "ndn-cxx/util/string-helper.hpp"
 
-#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/classification.hpp>
+#include <boost/algorithm/string/split.hpp>
 #include <boost/lexical_cast.hpp>
-#include <boost/mpl/vector.hpp>
 #include <boost/mpl/for_each.hpp>
+#include <boost/mpl/vector.hpp>
 
 #include <regex>
 #include <set>
diff --git a/ndn-cxx/security/pib/impl/pib-sqlite3.cpp b/ndn-cxx/security/pib/impl/pib-sqlite3.cpp
index ca73641..0246b9a 100644
--- a/ndn-cxx/security/pib/impl/pib-sqlite3.cpp
+++ b/ndn-cxx/security/pib/impl/pib-sqlite3.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -26,7 +26,6 @@
 
 #include <sqlite3.h>
 
-#include <boost/algorithm/string.hpp>
 #include <boost/filesystem.hpp>
 
 namespace ndn {
diff --git a/ndn-cxx/security/v2/certificate-bundle-fetcher.cpp b/ndn-cxx/security/v2/certificate-bundle-fetcher.cpp
index 2113a41..76ce514 100644
--- a/ndn-cxx/security/v2/certificate-bundle-fetcher.cpp
+++ b/ndn-cxx/security/v2/certificate-bundle-fetcher.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -20,7 +20,11 @@
  */
 
 #include "ndn-cxx/security/v2/certificate-bundle-fetcher.hpp"
+
 #include "ndn-cxx/face.hpp"
+#include "ndn-cxx/security/v2/certificate-request.hpp"
+#include "ndn-cxx/security/v2/certificate-storage.hpp"
+#include "ndn-cxx/security/v2/validation-state.hpp"
 #include "ndn-cxx/util/logger.hpp"
 
 namespace ndn {
@@ -100,13 +104,13 @@
   bundleInterest.setInterestLifetime(m_bundleInterestLifetime);
 
   m_face.expressInterest(bundleInterest,
-                         [=] (const Interest& interest, const Data& data) {
+                         [=] (const Interest&, const Data& data) {
                            dataCallback(data, true, certRequest, state, continueValidation);
                          },
-                         [=] (const Interest& interest, const lp::Nack& nack) {
+                         [=] (const Interest&, const lp::Nack& nack) {
                            nackCallback(nack, certRequest, state, continueValidation, bundleNamePrefix);
                          },
-                         [=] (const Interest& interest) {
+                         [=] (const Interest&) {
                            timeoutCallback(certRequest, state, continueValidation, bundleNamePrefix);
                          });
 }
@@ -128,13 +132,13 @@
   bundleInterest.setInterestLifetime(m_bundleInterestLifetime);
 
   m_face.expressInterest(bundleInterest,
-                         [=] (const Interest& interest, const Data& data) {
+                         [=] (const Interest&, const Data& data) {
                            dataCallback(data, false, certRequest, state, continueValidation);
                          },
-                         [=] (const Interest& interest, const lp::Nack& nack) {
+                         [=] (const Interest&, const lp::Nack& nack) {
                            nackCallback(nack, certRequest, state, continueValidation, fullBundleName);
                          },
-                         [=] (const Interest& interest) {
+                         [=] (const Interest&) {
                            timeoutCallback(certRequest, state, continueValidation, fullBundleName);
                          });
 }
@@ -221,7 +225,7 @@
     bundleName = name.getPrefix(-1);
   }
   bundleName.append("_BUNDLE");
-  bundleName.appendNumber(00);
+  bundleName.appendNumber(0);
 
   return bundleName;
 }
diff --git a/ndn-cxx/security/v2/certificate-bundle-fetcher.hpp b/ndn-cxx/security/v2/certificate-bundle-fetcher.hpp
index f14de46..6249a23 100644
--- a/ndn-cxx/security/v2/certificate-bundle-fetcher.hpp
+++ b/ndn-cxx/security/v2/certificate-bundle-fetcher.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -22,6 +22,8 @@
 #ifndef NDN_SECURITY_V2_CERTIFICATE_BUNDLE_FETCHER_HPP
 #define NDN_SECURITY_V2_CERTIFICATE_BUNDLE_FETCHER_HPP
 
+#include "ndn-cxx/name.hpp"
+#include "ndn-cxx/tag.hpp"
 #include "ndn-cxx/security/v2/certificate-fetcher-from-network.hpp"
 
 namespace ndn {
diff --git a/ndn-cxx/security/v2/certificate-fetcher-direct-fetch.cpp b/ndn-cxx/security/v2/certificate-fetcher-direct-fetch.cpp
index 7a4cb42..0fc4682 100644
--- a/ndn-cxx/security/v2/certificate-fetcher-direct-fetch.cpp
+++ b/ndn-cxx/security/v2/certificate-fetcher-direct-fetch.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -20,8 +20,11 @@
  */
 
 #include "ndn-cxx/security/v2/certificate-fetcher-direct-fetch.hpp"
+
 #include "ndn-cxx/face.hpp"
 #include "ndn-cxx/lp/tags.hpp"
+#include "ndn-cxx/security/v2/certificate-request.hpp"
+#include "ndn-cxx/security/v2/validation-state.hpp"
 
 namespace ndn {
 namespace security {
@@ -69,13 +72,13 @@
     }
     else {
       m_face.expressInterest(directInterest,
-                             [=] (const Interest& interest, const Data& data) {
+                             [=] (const Interest&, const Data& data) {
                                dataCallback(data, keyRequest, state, continueValidation);
                              },
-                             [=] (const Interest& interest, const lp::Nack& nack) {
+                             [=] (const Interest&, const lp::Nack& nack) {
                                nackCallback(nack, keyRequest, state, continueValidation);
                              },
-                             [=] (const Interest& interest) {
+                             [=] (const Interest&) {
                                timeoutCallback(keyRequest, state, continueValidation);
                              });
     }
diff --git a/ndn-cxx/security/v2/certificate-fetcher-from-network.cpp b/ndn-cxx/security/v2/certificate-fetcher-from-network.cpp
index df816b1..8ca0a51 100644
--- a/ndn-cxx/security/v2/certificate-fetcher-from-network.cpp
+++ b/ndn-cxx/security/v2/certificate-fetcher-from-network.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -20,7 +20,10 @@
  */
 
 #include "ndn-cxx/security/v2/certificate-fetcher-from-network.hpp"
+
 #include "ndn-cxx/face.hpp"
+#include "ndn-cxx/security/v2/certificate-request.hpp"
+#include "ndn-cxx/security/v2/validation-state.hpp"
 #include "ndn-cxx/util/logger.hpp"
 
 namespace ndn {
@@ -44,20 +47,20 @@
                                        const ValidationContinuation& continueValidation)
 {
   m_face.expressInterest(certRequest->interest,
-                         [=] (const Interest& interest, const Data& data) {
+                         [=] (const Interest&, const Data& data) {
                            dataCallback(data, certRequest, state, continueValidation);
                          },
-                         [=] (const Interest& interest, const lp::Nack& nack) {
+                         [=] (const Interest&, const lp::Nack& nack) {
                            nackCallback(nack, certRequest, state, continueValidation);
                          },
-                         [=] (const Interest& interest) {
+                         [=] (const Interest&) {
                            timeoutCallback(certRequest, state, continueValidation);
                          });
 }
 
 void
 CertificateFetcherFromNetwork::dataCallback(const Data& data,
-                                            const shared_ptr<CertificateRequest>& certRequest,
+                                            const shared_ptr<CertificateRequest>&,
                                             const shared_ptr<ValidationState>& state,
                                             const ValidationContinuation& continueValidation)
 {
diff --git a/ndn-cxx/security/v2/certificate-fetcher-from-network.hpp b/ndn-cxx/security/v2/certificate-fetcher-from-network.hpp
index 35b960a..81bbee5 100644
--- a/ndn-cxx/security/v2/certificate-fetcher-from-network.hpp
+++ b/ndn-cxx/security/v2/certificate-fetcher-from-network.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -27,6 +27,9 @@
 
 namespace ndn {
 
+class Data;
+class Face;
+
 namespace lp {
 class Nack;
 } // namespace lp
diff --git a/ndn-cxx/security/v2/certificate-fetcher-offline.cpp b/ndn-cxx/security/v2/certificate-fetcher-offline.cpp
index 589f9cd..9c32216 100644
--- a/ndn-cxx/security/v2/certificate-fetcher-offline.cpp
+++ b/ndn-cxx/security/v2/certificate-fetcher-offline.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -20,6 +20,8 @@
  */
 
 #include "ndn-cxx/security/v2/certificate-fetcher-offline.hpp"
+#include "ndn-cxx/security/v2/certificate-request.hpp"
+#include "ndn-cxx/security/v2/validation-state.hpp"
 
 namespace ndn {
 namespace security {
@@ -28,7 +30,7 @@
 void
 CertificateFetcherOffline::doFetch(const shared_ptr<CertificateRequest>& certRequest,
                                    const shared_ptr<ValidationState>& state,
-                                   const ValidationContinuation& continueValidation)
+                                   const ValidationContinuation&)
 {
   state->fail({ValidationError::Code::CANNOT_RETRIEVE_CERT,
                "Cannot fetch certificate " + certRequest->interest.getName().toUri() + " in offline mode"});
diff --git a/ndn-cxx/security/v2/certificate-fetcher.cpp b/ndn-cxx/security/v2/certificate-fetcher.cpp
index 672944f..717a3f1 100644
--- a/ndn-cxx/security/v2/certificate-fetcher.cpp
+++ b/ndn-cxx/security/v2/certificate-fetcher.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -20,6 +20,9 @@
  */
 
 #include "ndn-cxx/security/v2/certificate-fetcher.hpp"
+#include "ndn-cxx/security/v2/certificate-request.hpp"
+#include "ndn-cxx/security/v2/certificate-storage.hpp"
+#include "ndn-cxx/security/v2/validation-state.hpp"
 #include "ndn-cxx/util/logger.hpp"
 
 namespace ndn {
@@ -55,6 +58,7 @@
     continueValidation(*cert, state);
     return;
   }
+
   doFetch(certRequest, state,
           [continueValidation, this] (const Certificate& cert, const shared_ptr<ValidationState>& state) {
             m_certStorage->cacheUnverifiedCert(Certificate(cert));
diff --git a/ndn-cxx/security/v2/certificate-fetcher.hpp b/ndn-cxx/security/v2/certificate-fetcher.hpp
index 4a29a79..fcf6b87 100644
--- a/ndn-cxx/security/v2/certificate-fetcher.hpp
+++ b/ndn-cxx/security/v2/certificate-fetcher.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -22,17 +22,17 @@
 #ifndef NDN_SECURITY_V2_CERTIFICATE_FETCHER_HPP
 #define NDN_SECURITY_V2_CERTIFICATE_FETCHER_HPP
 
-#include "ndn-cxx/security/v2/certificate-request.hpp"
-#include "ndn-cxx/security/v2/certificate-storage.hpp"
-#include "ndn-cxx/security/v2/validation-state.hpp"
+#include "ndn-cxx/detail/common.hpp"
 
 namespace ndn {
-
-class Face;
-
 namespace security {
 namespace v2 {
 
+class Certificate;
+class CertificateRequest;
+class CertificateStorage;
+class ValidationState;
+
 /**
  * @brief Interface used by the validator to fetch missing certificates
  */
diff --git a/ndn-cxx/security/v2/trust-anchor-container.cpp b/ndn-cxx/security/v2/trust-anchor-container.cpp
index f77f233..7cf5b23 100644
--- a/ndn-cxx/security/v2/trust-anchor-container.cpp
+++ b/ndn-cxx/security/v2/trust-anchor-container.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -50,7 +50,8 @@
 {
   auto group = m_groups.find(groupId);
   if (group == m_groups.end()) {
-    std::tie(group, std::ignore) = m_groups.insert(make_shared<StaticTrustAnchorGroup>(m_anchors, groupId));
+    std::tie(group, std::ignore) = m_groups.insert(std::make_shared<StaticTrustAnchorGroup>(m_anchors,
+                                                                                            groupId));
   }
   auto* staticGroup = dynamic_cast<StaticTrustAnchorGroup*>(&**group);
   if (staticGroup == nullptr) {
@@ -67,7 +68,8 @@
     NDN_THROW(Error("Cannot create dynamic group, because group " + groupId + " already exists"));
   }
 
-  m_groups.insert(make_shared<DynamicTrustAnchorGroup>(m_anchors, groupId, path, refreshPeriod, isDir));
+  m_groups.insert(std::make_shared<DynamicTrustAnchorGroup>(m_anchors, groupId, path,
+                                                            refreshPeriod, isDir));
 }
 
 void
diff --git a/ndn-cxx/security/v2/validator-config/name-relation.cpp b/ndn-cxx/security/v2/validator-config/name-relation.cpp
index ec9991d..0f27aa9 100644
--- a/ndn-cxx/security/v2/validator-config/name-relation.cpp
+++ b/ndn-cxx/security/v2/validator-config/name-relation.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -21,7 +21,7 @@
 
 #include "ndn-cxx/security/v2/validator-config/name-relation.hpp"
 
-#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/predicate.hpp>
 
 namespace ndn {
 namespace security {
diff --git a/ndn-cxx/util/backports.hpp b/ndn-cxx/util/backports.hpp
index aac4eb6..e36cdaf 100644
--- a/ndn-cxx/util/backports.hpp
+++ b/ndn-cxx/util/backports.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -82,7 +82,6 @@
 #include "ndn-cxx/util/nonstd/any.hpp"
 #include "ndn-cxx/util/nonstd/optional.hpp"
 #include "ndn-cxx/util/nonstd/variant.hpp"
-#include "ndn-cxx/util/ostream-joiner.hpp"
 
 #ifndef NDN_CXX_HAVE_STD_TO_STRING
 #include <boost/lexical_cast.hpp>
diff --git a/ndn-cxx/util/scheduler.cpp b/ndn-cxx/util/scheduler.cpp
index e4b15d8..7b2b56a 100644
--- a/ndn-cxx/util/scheduler.cpp
+++ b/ndn-cxx/util/scheduler.cpp
@@ -94,7 +94,7 @@
 {
   BOOST_ASSERT(callback != nullptr);
 
-  auto i = m_queue.insert(make_shared<EventInfo>(after, std::move(callback)));
+  auto i = m_queue.insert(std::make_shared<EventInfo>(after, std::move(callback)));
   (*i)->queueIt = i;
 
   if (!m_isEventExecuting && i == m_queue.begin()) {
diff --git a/tests/make-interest-data.cpp b/tests/make-interest-data.cpp
index 4031507..09d879b 100644
--- a/tests/make-interest-data.cpp
+++ b/tests/make-interest-data.cpp
@@ -30,7 +30,7 @@
 makeInterest(const Name& name, bool canBePrefix, time::milliseconds lifetime,
              optional<Interest::Nonce> nonce)
 {
-  auto interest = make_shared<Interest>(name, lifetime);
+  auto interest = std::make_shared<Interest>(name, lifetime);
   interest->setCanBePrefix(canBePrefix);
   interest->setNonce(nonce);
   return interest;
@@ -39,7 +39,7 @@
 shared_ptr<Data>
 makeData(const Name& name)
 {
-  auto data = make_shared<Data>(name);
+  auto data = std::make_shared<Data>(name);
   return signData(data);
 }
 
diff --git a/tests/test-home-fixture.hpp b/tests/test-home-fixture.hpp
index 38fd3f1..63d5d88 100644
--- a/tests/test-home-fixture.hpp
+++ b/tests/test-home-fixture.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -28,7 +28,7 @@
 #include <fstream>
 #include <initializer_list>
 
-#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/replace.hpp>
 #include <boost/filesystem.hpp>
 
 namespace ndn {
diff --git a/tests/tests-pch.hpp b/tests/tests-pch.hpp
new file mode 100644
index 0000000..a81f7bf
--- /dev/null
+++ b/tests/tests-pch.hpp
@@ -0,0 +1,37 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2020 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_TESTS_PCH_HPP
+#define NDN_TESTS_TESTS_PCH_HPP
+
+#include "ndn-cxx/impl/common-pch.hpp"
+
+#include "ndn-cxx/data.hpp"
+#include "ndn-cxx/interest.hpp"
+#include "ndn-cxx/lp/nack.hpp"
+#include "ndn-cxx/security/v2/key-chain.hpp"
+
+#include "tests/boost-test.hpp"
+
+#include <fstream>
+#include <boost/filesystem.hpp>
+
+#endif // NDN_TESTS_TESTS_PCH_HPP
diff --git a/tests/unit/unit-tests-pch.hpp b/tests/unit/unit-tests-pch.hpp
new file mode 100644
index 0000000..54e15f9
--- /dev/null
+++ b/tests/unit/unit-tests-pch.hpp
@@ -0,0 +1,35 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2020 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_UNIT_UNIT_TESTS_PCH_HPP
+#define NDN_TESTS_UNIT_UNIT_TESTS_PCH_HPP
+
+#include "tests/tests-pch.hpp"
+
+#include "ndn-cxx/face.hpp"
+#include "ndn-cxx/ims/in-memory-storage.hpp"
+#include "ndn-cxx/security/transform.hpp"
+#include "ndn-cxx/security/v2/validator.hpp"
+#include "ndn-cxx/util/config-file.hpp"
+
+#include "tests/identity-management-fixture.hpp"
+
+#endif // NDN_TESTS_UNIT_UNIT_TESTS_PCH_HPP
diff --git a/tests/unit/util/backports.t.cpp b/tests/unit/util/backports.t.cpp
index b73465b..2404d03 100644
--- a/tests/unit/util/backports.t.cpp
+++ b/tests/unit/util/backports.t.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -20,18 +20,9 @@
  */
 
 #include "ndn-cxx/util/backports.hpp"
-#include "ndn-cxx/util/ostream-joiner.hpp"
 
 #include "tests/boost-test.hpp"
 
-#include <numeric>
-
-#if BOOST_VERSION >= 105900
-#include <boost/test/tools/output_test_stream.hpp>
-#else
-#include <boost/test/output_test_stream.hpp>
-#endif
-
 namespace ndn {
 namespace tests {
 
@@ -59,40 +50,6 @@
   BOOST_CHECK_EQUAL(x, 10);
 }
 
-BOOST_AUTO_TEST_CASE(OstreamJoiner)
-{
-  boost::test_tools::output_test_stream os;
-
-  auto joiner1 = ostream_joiner<char>(os, ' ');
-  auto joiner2 = make_ostream_joiner(os, ' ');
-  static_assert(std::is_same<decltype(joiner1), decltype(joiner2)>::value, "");
-
-  std::vector<int> v(5);
-  std::iota(v.begin(), v.end(), 1);
-  std::copy(v.begin(), v.end(), joiner2);
-  BOOST_CHECK(os.is_equal("1 2 3 4 5"));
-
-  auto joiner3 = make_ostream_joiner(os, "...");
-  std::copy(v.begin(), v.end(), joiner3);
-  BOOST_CHECK(os.is_equal("1...2...3...4...5"));
-
-  joiner3 = "one";
-  BOOST_CHECK(os.is_equal("one"));
-  joiner3 = "two";
-  BOOST_CHECK(os.is_equal("...two"));
-  ++joiner3 = "three";
-  BOOST_CHECK(os.is_equal("...three"));
-  joiner3++ = "four";
-  BOOST_CHECK(os.is_equal("...four"));
-
-  std::copy(v.begin(), v.end(), make_ostream_joiner(os, ""));
-  BOOST_CHECK(os.is_equal("12345"));
-
-  std::string delimiter("_");
-  std::copy(v.begin(), v.end(), make_ostream_joiner(os, delimiter));
-  BOOST_CHECK(os.is_equal("1_2_3_4_5"));
-}
-
 BOOST_AUTO_TEST_SUITE_END() // TestBackports
 BOOST_AUTO_TEST_SUITE_END() // Util
 
diff --git a/tests/unit/util/ostream-joiner.t.cpp b/tests/unit/util/ostream-joiner.t.cpp
new file mode 100644
index 0000000..2eaf2f9
--- /dev/null
+++ b/tests/unit/util/ostream-joiner.t.cpp
@@ -0,0 +1,78 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2020 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.
+ */
+
+#include "ndn-cxx/util/ostream-joiner.hpp"
+
+#include "tests/boost-test.hpp"
+
+#include <numeric>
+
+#if BOOST_VERSION >= 105900
+#include <boost/test/tools/output_test_stream.hpp>
+#else
+#include <boost/test/output_test_stream.hpp>
+#endif
+
+namespace ndn {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(Util)
+BOOST_AUTO_TEST_SUITE(TestOstreamJoiner)
+
+BOOST_AUTO_TEST_CASE(Basic)
+{
+  boost::test_tools::output_test_stream os;
+
+  auto joiner1 = ostream_joiner<char>(os, ' ');
+  auto joiner2 = make_ostream_joiner(os, ' ');
+  static_assert(std::is_same<decltype(joiner1), decltype(joiner2)>::value, "");
+
+  std::vector<int> v(5);
+  std::iota(v.begin(), v.end(), 1);
+  std::copy(v.begin(), v.end(), joiner2);
+  BOOST_CHECK(os.is_equal("1 2 3 4 5"));
+
+  auto joiner3 = make_ostream_joiner(os, "...");
+  std::copy(v.begin(), v.end(), joiner3);
+  BOOST_CHECK(os.is_equal("1...2...3...4...5"));
+
+  joiner3 = "one";
+  BOOST_CHECK(os.is_equal("one"));
+  joiner3 = "two";
+  BOOST_CHECK(os.is_equal("...two"));
+  ++joiner3 = "three";
+  BOOST_CHECK(os.is_equal("...three"));
+  joiner3++ = "four";
+  BOOST_CHECK(os.is_equal("...four"));
+
+  std::copy(v.begin(), v.end(), make_ostream_joiner(os, ""));
+  BOOST_CHECK(os.is_equal("12345"));
+
+  std::string delimiter("_");
+  std::copy(v.begin(), v.end(), make_ostream_joiner(os, delimiter));
+  BOOST_CHECK(os.is_equal("1_2_3_4_5"));
+}
+
+BOOST_AUTO_TEST_SUITE_END() // TestOstreamJoiner
+BOOST_AUTO_TEST_SUITE_END() // Util
+
+} // namespace tests
+} // namespace ndn
diff --git a/tests/unit/wscript b/tests/unit/wscript
index bc7ce0f..e91ac7f 100644
--- a/tests/unit/wscript
+++ b/tests/unit/wscript
@@ -1,6 +1,6 @@
 # -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
 
-top = '../..'
+top = '../../'
 
 def build(bld):
     configPath = 'UNIT_TEST_CONFIG_PATH="%s"' % bld.bldnode.make_node('tmp-files')
@@ -18,11 +18,13 @@
 
     bld.objects(target='unit-tests-objects',
                 source=srcFiles,
+                features='pch',
+                headers='unit-tests-pch.hpp',
                 use='tests-common',
                 defines=[configPath])
 
     # unit test binary
-    bld.program(target='../../unit-tests',
+    bld.program(target=top + 'unit-tests',
                 name='unit-tests',
                 source=['main.cpp'],
                 use='unit-tests-objects',
diff --git a/tests/wscript b/tests/wscript
index d343b1a..d7401ca 100644
--- a/tests/wscript
+++ b/tests/wscript
@@ -1,13 +1,13 @@
 # -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
 
-top = '..'
+top = '../'
 
 def build(bld):
     # common objects that can be shared among all tests
     bld.objects(target='tests-common',
-                features='pch',
                 source=bld.path.ant_glob('*.cpp'),
-                headers=['../ndn-cxx/impl/common-pch.hpp', 'boost-test.hpp'],
+                features='pch',
+                headers='tests-pch.hpp',
                 use='ndn-cxx BOOST')
 
     bld.recurse('benchmarks')
diff --git a/tools/ndnsec/accumulator.hpp b/tools/ndnsec/accumulator.hpp
new file mode 100644
index 0000000..7c08581
--- /dev/null
+++ b/tools/ndnsec/accumulator.hpp
@@ -0,0 +1,168 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2020 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_TOOLS_NDNSEC_ACCUMULATOR_HPP
+#define NDN_TOOLS_NDNSEC_ACCUMULATOR_HPP
+
+#include <boost/program_options/value_semantic.hpp>
+
+namespace ndn {
+namespace ndnsec {
+
+/**
+ * @brief An accumulating option value to handle multiple incrementing options.
+ *
+ * Based on https://gitorious.org/bwy/bwy/source/8753148c324ddfacb1f3cdc315650586bd7b75a4:use/accumulator.hpp
+ * @sa http://benjaminwolsey.de/node/103
+ */
+template<typename T>
+class AccumulatorType : public boost::program_options::value_semantic
+{
+public:
+  explicit
+  AccumulatorType(T* store)
+    : m_store(store)
+    , m_interval(1)
+    , m_default(0)
+  {
+  }
+
+  /// @brief Set the default value for this option.
+  AccumulatorType*
+  setDefaultValue(const T& t)
+  {
+    m_default = t;
+    return this;
+  }
+
+  /**
+   * @brief Set the interval for this option.
+   *
+   * Unlike for program_options::value, this specifies a value
+   * to be applied on each occurrence of the option.
+   */
+  AccumulatorType*
+  setInterval(const T& t)
+  {
+    m_interval = t;
+    return this;
+  }
+
+  std::string
+  name() const final
+  {
+    return std::string();
+  }
+
+  // There are no tokens for an AccumulatorType
+  unsigned
+  min_tokens() const final
+  {
+    return 0;
+  }
+
+  unsigned
+  max_tokens() const final
+  {
+    return 0;
+  }
+
+  // Accumulating from different sources is silly.
+  bool
+  is_composing() const final
+  {
+    return false;
+  }
+
+  // Requiring one or more appearances is unlikely.
+  bool
+  is_required() const final
+  {
+    return false;
+  }
+
+  /**
+   * @brief Parse options
+   *
+   * Every appearance of the option simply increments the value
+   * There should never be any tokens.
+   */
+  void
+  parse(boost::any& value_store, const std::vector<std::string>& new_tokens, bool utf8) const final
+  {
+    if (value_store.empty())
+      value_store = T();
+    boost::any_cast<T&>(value_store) += m_interval;
+  }
+
+  /**
+   * @brief If the option doesn't appear, this is the default value.
+   */
+  bool
+  apply_default(boost::any& value_store) const final
+  {
+    value_store = m_default;
+    return true;
+  }
+
+  /**
+   * @brief Notify the user function with the value of the value store.
+   */
+  void
+  notify(const boost::any& value_store) const final
+  {
+    const T* val = boost::any_cast<T>(&value_store);
+    if (m_store)
+      *m_store = *val;
+  }
+
+#if (BOOST_VERSION >= 105900) && (BOOST_VERSION < 106500)
+  bool
+  adjacent_tokens_only() const final
+  {
+    return false;
+  }
+#endif // (BOOST_VERSION >= 105900) && (BOOST_VERSION < 106500)
+
+private:
+  T* m_store;
+  T m_interval;
+  T m_default;
+};
+
+template <typename T>
+AccumulatorType<T>*
+accumulator()
+{
+  return new AccumulatorType<T>(nullptr);
+}
+
+template <typename T>
+AccumulatorType<T>*
+accumulator(T* store)
+{
+  return new AccumulatorType<T>(store);
+}
+
+} // namespace ndnsec
+} // namespace ndn
+
+#endif // NDN_TOOLS_NDNSEC_ACCUMULATOR_HPP
diff --git a/tools/ndnsec/cert-dump.cpp b/tools/ndnsec/cert-dump.cpp
index 8e74948..38d8ed5 100644
--- a/tools/ndnsec/cert-dump.cpp
+++ b/tools/ndnsec/cert-dump.cpp
@@ -22,6 +22,8 @@
 #include "ndnsec.hpp"
 #include "util.hpp"
 
+#include "ndn-cxx/util/io.hpp"
+
 #include <boost/asio/ip/tcp.hpp>
 #if BOOST_VERSION < 106700
 #include <boost/date_time/posix_time/posix_time_duration.hpp>
diff --git a/tools/ndnsec/cert-gen.cpp b/tools/ndnsec/cert-gen.cpp
index ec630c9..1749b2b 100644
--- a/tools/ndnsec/cert-gen.cpp
+++ b/tools/ndnsec/cert-gen.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -26,6 +26,7 @@
 #include "ndn-cxx/security/transform/buffer-source.hpp"
 #include "ndn-cxx/security/transform/public-key.hpp"
 #include "ndn-cxx/security/transform/stream-sink.hpp"
+#include "ndn-cxx/security/v2/additional-description.hpp"
 
 namespace ndn {
 namespace ndnsec {
diff --git a/tools/ndnsec/export.cpp b/tools/ndnsec/export.cpp
index 6d3c260..4429dd4 100644
--- a/tools/ndnsec/export.cpp
+++ b/tools/ndnsec/export.cpp
@@ -23,6 +23,7 @@
 #include "util.hpp"
 
 #include "ndn-cxx/security/impl/openssl.hpp"
+#include "ndn-cxx/util/io.hpp"
 
 #include <boost/scope_exit.hpp>
 
diff --git a/tools/ndnsec/import.cpp b/tools/ndnsec/import.cpp
index c58a6ed..fa67a44 100644
--- a/tools/ndnsec/import.cpp
+++ b/tools/ndnsec/import.cpp
@@ -23,6 +23,7 @@
 #include "util.hpp"
 
 #include "ndn-cxx/security/impl/openssl.hpp"
+#include "ndn-cxx/util/io.hpp"
 
 #include <boost/scope_exit.hpp>
 
diff --git a/tools/ndnsec/key-gen.cpp b/tools/ndnsec/key-gen.cpp
index 1d3d79a..553f06c 100644
--- a/tools/ndnsec/key-gen.cpp
+++ b/tools/ndnsec/key-gen.cpp
@@ -22,6 +22,8 @@
 #include "ndnsec.hpp"
 #include "util.hpp"
 
+#include "ndn-cxx/util/io.hpp"
+
 namespace ndn {
 namespace ndnsec {
 
diff --git a/tools/ndnsec/list.cpp b/tools/ndnsec/list.cpp
index 1aa2d4e..fbe1140 100644
--- a/tools/ndnsec/list.cpp
+++ b/tools/ndnsec/list.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -19,6 +19,7 @@
  * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
  */
 
+#include "accumulator.hpp"
 #include "ndnsec.hpp"
 #include "util.hpp"
 
diff --git a/tools/ndnsec/main.cpp b/tools/ndnsec/main.cpp
index 8548748..c0be01b 100644
--- a/tools/ndnsec/main.cpp
+++ b/tools/ndnsec/main.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -20,12 +20,12 @@
  */
 
 #include "ndnsec.hpp"
-#include "util.hpp"
 
 #include "ndn-cxx/util/logger.hpp"
 #include "ndn-cxx/version.hpp"
 
 #include <boost/exception/diagnostic_information.hpp>
+#include <iostream>
 
 NDN_LOG_INIT(ndnsec);
 
diff --git a/tools/ndnsec/ndnsec-pch.hpp b/tools/ndnsec/ndnsec-pch.hpp
new file mode 100644
index 0000000..ea537fa
--- /dev/null
+++ b/tools/ndnsec/ndnsec-pch.hpp
@@ -0,0 +1,31 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2020 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_TOOLS_NDNSEC_NDNSEC_PCH_HPP
+#define NDN_TOOLS_NDNSEC_NDNSEC_PCH_HPP
+
+#include "util.hpp"
+
+#include "ndn-cxx/util/io.hpp"
+
+#include <boost/asio/ip/tcp.hpp>
+
+#endif // NDN_TOOLS_NDNSEC_NDNSEC_PCH_HPP
diff --git a/tools/ndnsec/sign-req.cpp b/tools/ndnsec/sign-req.cpp
index d8d7486..f9f97e9 100644
--- a/tools/ndnsec/sign-req.cpp
+++ b/tools/ndnsec/sign-req.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -22,6 +22,8 @@
 #include "ndnsec.hpp"
 #include "util.hpp"
 
+#include "ndn-cxx/util/io.hpp"
+
 namespace ndn {
 namespace ndnsec {
 
diff --git a/tools/ndnsec/util.cpp b/tools/ndnsec/util.cpp
index 4895ed3..cb35b52 100644
--- a/tools/ndnsec/util.cpp
+++ b/tools/ndnsec/util.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -22,6 +22,7 @@
 #include "util.hpp"
 
 #include "ndn-cxx/security/impl/openssl.hpp"
+#include "ndn-cxx/util/io.hpp"
 
 #include <unistd.h>
 
diff --git a/tools/ndnsec/util.hpp b/tools/ndnsec/util.hpp
index 90c3284..873f6b0 100644
--- a/tools/ndnsec/util.hpp
+++ b/tools/ndnsec/util.hpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /*
- * Copyright (c) 2013-2019 Regents of the University of California.
+ * Copyright (c) 2013-2020 Regents of the University of California.
  *
  * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
  *
@@ -23,12 +23,8 @@
 #define NDN_TOOLS_NDNSEC_UTIL_HPP
 
 #include "ndn-cxx/security/key-chain.hpp"
-#include "ndn-cxx/security/v2/additional-description.hpp"
-#include "ndn-cxx/util/io.hpp"
 
-#include <fstream>
 #include <iostream>
-#include <string>
 
 #include <boost/program_options/options_description.hpp>
 #include <boost/program_options/parsers.hpp>
@@ -46,146 +42,11 @@
   }
 };
 
-bool
-getPassword(std::string& password, const std::string& prompt, bool shouldConfirm = true);
-
 security::v2::Certificate
 loadCertificate(const std::string& fileName);
 
-/**
- * @brief An accumulating option value to handle multiple incrementing options.
- *
- * Based on https://gitorious.org/bwy/bwy/source/8753148c324ddfacb1f3cdc315650586bd7b75a4:use/accumulator.hpp
- * @sa http://benjaminwolsey.de/node/103
- */
-template<typename T>
-class AccumulatorType : public boost::program_options::value_semantic
-{
-public:
-  explicit
-  AccumulatorType(T* store)
-    : m_store(store)
-    , m_interval(1)
-    , m_default(0)
-  {
-  }
-
-  /// @brief Set the default value for this option.
-  AccumulatorType*
-  setDefaultValue(const T& t)
-  {
-    m_default = t;
-    return this;
-  }
-
-  /**
-   * @brief Set the interval for this option.
-   *
-   * Unlike for program_options::value, this specifies a value
-   * to be applied on each occurrence of the option.
-   */
-  AccumulatorType*
-  setInterval(const T& t)
-  {
-    m_interval = t;
-    return this;
-  }
-
-  std::string
-  name() const final
-  {
-    return std::string();
-  }
-
-  // There are no tokens for an AccumulatorType
-  unsigned
-  min_tokens() const final
-  {
-    return 0;
-  }
-
-  unsigned
-  max_tokens() const final
-  {
-    return 0;
-  }
-
-  // Accumulating from different sources is silly.
-  bool
-  is_composing() const final
-  {
-    return false;
-  }
-
-  // Requiring one or more appearances is unlikely.
-  bool
-  is_required() const final
-  {
-    return false;
-  }
-
-  /**
-   * @brief Parse options
-   *
-   * Every appearance of the option simply increments the value
-   * There should never be any tokens.
-   */
-  void
-  parse(boost::any& value_store, const std::vector<std::string>& new_tokens, bool utf8) const final
-  {
-    if (value_store.empty())
-      value_store = T();
-    boost::any_cast<T&>(value_store) += m_interval;
-  }
-
-  /**
-   * @brief If the option doesn't appear, this is the default value.
-   */
-  bool
-  apply_default(boost::any& value_store) const final
-  {
-    value_store = m_default;
-    return true;
-  }
-
-  /**
-   * @brief Notify the user function with the value of the value store.
-   */
-  void
-  notify(const boost::any& value_store) const final
-  {
-    const T* val = boost::any_cast<T>(&value_store);
-    if (m_store)
-      *m_store = *val;
-  }
-
-#if (BOOST_VERSION >= 105900) && (BOOST_VERSION < 106500)
-  bool
-  adjacent_tokens_only() const final
-  {
-    return false;
-  }
-#endif // (BOOST_VERSION >= 105900) && (BOOST_VERSION < 106500)
-
-private:
-  T* m_store;
-  T m_interval;
-  T m_default;
-};
-
-template <typename T>
-AccumulatorType<T>*
-accumulator()
-{
-  return new AccumulatorType<T>(0);
-}
-
-template <typename T>
-AccumulatorType<T>*
-accumulator(T* store)
-{
-  return new AccumulatorType<T>(store);
-}
+bool
+getPassword(std::string& password, const std::string& prompt, bool shouldConfirm = true);
 
 } // namespace ndnsec
 } // namespace ndn
diff --git a/tools/ndnsec/wscript b/tools/ndnsec/wscript
new file mode 100644
index 0000000..9f61ae4
--- /dev/null
+++ b/tools/ndnsec/wscript
@@ -0,0 +1,14 @@
+# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+top = '../../'
+
+def build(bld):
+    bld.objects(target='tool-ndnsec-objects',
+                source=bld.path.ant_glob('*.cpp', excl=['main.cpp']),
+                features='pch',
+                headers='ndnsec-pch.hpp',
+                use='ndn-cxx')
+    bld.program(name='tool-ndnsec',
+                target=top + 'bin/ndnsec',
+                source=['main.cpp'],
+                use='tool-ndnsec-objects')
diff --git a/tools/wscript b/tools/wscript
index 29b8536..b8c2358 100644
--- a/tools/wscript
+++ b/tools/wscript
@@ -2,31 +2,36 @@
 
 from waflib import Utils
 
-top = '..'
+top = '../'
 
 def build(bld):
     # Single object tools:
-    # tools/example-tool.cpp is a self-contained tool with a main() function
-    # and is built as build/bin/example-tool.
-    # These tools cannot be unit-tested.
+    # tools/foo.cpp is a self-contained tool with a main() function
+    # and is built as build/bin/foo. These tools cannot be unit-tested.
     for tool in bld.path.ant_glob('*.cpp'):
         name = tool.change_ext('').path_from(bld.path.get_bld())
         bld.program(name='tool-%s' % name,
-                    target='../bin/%s' % name,
+                    target=top + 'bin/%s' % name,
                     source=[tool],
                     use='ndn-cxx')
 
     # Sub-directory tools:
-    # tools/example-tool/**/*.cpp is compiled and linked into build/bin/example-tool.
-    # tools/example-tool/main.cpp must exist and must contain the main() function.
-    # All other objects are collected into 'tools-objects' and can be unit-tested.
-    testableObjects = []
+    # tools/foo/**/*.cpp are compiled and linked into build/bin/foo.
+    # tools/foo/main.cpp must exist and must contain the main() function.
+    # All other objects are collected into 'tool-foo-objects' and can be unit-tested.
     for subdir in bld.path.ant_glob('*', dir=True, src=False):
+        name = subdir.path_from(bld.path)
+        subWscript = subdir.find_node('wscript')
+        if subWscript:
+            # if the subdir has a wscript, delegate to it
+            bld.recurse(name)
+            continue
+
         mainFile = subdir.find_node('main.cpp')
         if mainFile is None:
-            continue # not a C++ tool
+            # not a C++ tool, skip the subdir
+            continue
 
-        name = subdir.path_from(bld.path)
         srcFiles = subdir.ant_glob('**/*.cpp', excl=['main.cpp'])
         srcObjects = ''
         if srcFiles:
@@ -34,23 +39,17 @@
             bld.objects(target=srcObjects,
                         source=srcFiles,
                         use='ndn-cxx')
-            testableObjects.append(srcObjects)
-
         bld.program(name='tool-%s' % name,
-                    target='../bin/%s' % name,
+                    target=top + 'bin/%s' % name,
                     source=[mainFile],
                     use='ndn-cxx ' + srcObjects)
 
-    bld.objects(target='tools-objects',
-                source=[],
-                use=testableObjects)
-
     # Tool wrappers
     wrapperFiles = bld.path.ant_glob('wrapper/*.sh')
     bld(name='tool-wrappers',
         features='subst',
         source=wrapperFiles,
-        target=['../bin/%s' % node.change_ext('', '.sh').path_from(bld.path.find_dir('wrapper').get_bld())
+        target=[top + 'bin/%s' % node.change_ext('', '.sh').path_from(bld.path.find_dir('wrapper').get_bld())
                 for node in wrapperFiles],
         install_path='${BINDIR}',
         chmod=Utils.O755)
diff --git a/wscript b/wscript
index 3765aa4..1c536d1 100644
--- a/wscript
+++ b/wscript
@@ -181,7 +181,7 @@
 
     if bld.env.HAVE_OSX_FRAMEWORKS:
         # Need to disable precompiled headers for Objective-C++ code
-        bld(features=['cxx'],
+        bld(features='cxx',
             target='ndn-cxx-mm-objects',
             source=bld.path.ant_glob('ndn-cxx/**/*-osx.mm'),
             use='BOOST PTHREAD OSX_COREFOUNDATION OSX_SECURITY OSX_SYSTEMCONFIGURATION OSX_FOUNDATION OSX_COREWLAN',