tools: refactor nfd-status

refs #3658

Change-Id: Ia347074bea802eba5f539208e276e849a60db8a4
diff --git a/tools/wscript b/tools/wscript
index ee1909e..f3dd5c9 100644
--- a/tools/wscript
+++ b/tools/wscript
@@ -4,26 +4,59 @@
 
 top = '..'
 
+TOOLS_DEPENDENCY = 'core-objects NDN_CXX BOOST LIBRESOLV'
+
 def build(bld):
-    # List all .cpp files (whole tool should be in one .cpp)
+    # single object tools
+    # tools/example-tool.cpp should a self-contained tool with a main function
+    # and it's built into build/bin/example-tool.
+    # These tools cannot be unit-tested.
     for i in bld.path.ant_glob(['*.cpp']):
         name = str(i)[:-len(".cpp")]
-        bld(features=['cxx', 'cxxprogram'],
+        bld(features='cxx cxxprogram',
             target="../bin/%s" % name,
-            source=[i] + bld.path.ant_glob(['%s/**/*.cpp' % name]),
-            use='core-objects NDN_CXX BOOST LIBRESOLV'
+            source=[i],
+            use=TOOLS_DEPENDENCY
             )
 
-    # List all directories files (tool can has multiple .cpp in the directory)
+
+    # sub-directory tools
+    # tools/example-tool/**/*.cpp is compiled and linked into build/bin/example-tool
+    # tools/example-tool/main.cpp must exist and it should contain the main function.
+    # All other objects are collected into 'tools-objects' and can be unit-tested.
+    testableObjects = []
     for name in bld.path.ant_glob(['*'], dir=True, src=False):
-        srcFiles = bld.path.ant_glob(['%s/**/*.cpp' % name])
+        mainFile = bld.path.find_node(['%s/main.cpp' % name])
+        if mainFile is None:
+          continue # not a C++ tool
+        srcFiles = bld.path.ant_glob(['%s/**/*.cpp' % name], excl=['%s/main.cpp' % name])
         if len(srcFiles) > 0:
-            bld(features=['cxx', 'cxxprogram'],
-                target="../bin/%s" % name,
+            srcObjects = 'tools-%s-objects' % name
+            bld(features='cxx',
+                name=srcObjects,
                 source=srcFiles,
-                use='core-objects NDN_CXX BOOST LIBRESOLV',
+                use=TOOLS_DEPENDENCY,
                 includes='%s' % name,
                 )
+            testableObjects.append(srcObjects)
+
+            bld(features='cxx cxxprogram',
+                target="../bin/%s" % name,
+                source=[mainFile],
+                use=TOOLS_DEPENDENCY + ' ' + srcObjects,
+                includes='%s' % name,
+                )
+        else:
+            bld(features='cxx cxxprogram',
+                target="../bin/%s" % name,
+                source=[mainFile],
+                use=TOOLS_DEPENDENCY,
+                includes='%s' % name,
+                )
+
+    bld(name='tools-objects',
+        export_includes='.',
+        use=testableObjects)
 
     bld(features="subst",
         source=bld.path.ant_glob(['*.sh', '*.py']),