summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorPhil Mesnier <mesnier_p@ociweb.com>2002-02-20 22:05:12 +0000
committerPhil Mesnier <mesnier_p@ociweb.com>2002-02-20 22:05:12 +0000
commitce92974a00aa4f32fb84d65d9a889fbc20fbb69c (patch)
tree3bad98fbf69bbb959df0b435352e27a350253fe1 /apps
parent89383cfb51aab9490fb5be8b2c8e0bdf11b2cf53 (diff)
downloadATCD-ce92974a00aa4f32fb84d65d9a889fbc20fbb69c.tar.gz
ChangeLog tag: Wed Feb 20 15:26:43 2002 Phil Mesnier <mesnier_p@ociweb.com>
Diffstat (limited to 'apps')
-rw-r--r--apps/soreduce/Library.cpp368
-rw-r--r--apps/soreduce/Library.h126
-rw-r--r--apps/soreduce/Makefile42
-rw-r--r--apps/soreduce/Obj_Module.cpp193
-rw-r--r--apps/soreduce/Obj_Module.h66
-rw-r--r--apps/soreduce/README153
-rw-r--r--apps/soreduce/SO_Group.cpp158
-rw-r--r--apps/soreduce/SO_Group.h48
-rw-r--r--apps/soreduce/Sig_List.cpp184
-rw-r--r--apps/soreduce/Sig_List.h49
-rw-r--r--apps/soreduce/Signature.cpp45
-rw-r--r--apps/soreduce/Signature.h50
-rw-r--r--apps/soreduce/soreduce.cpp51
13 files changed, 1533 insertions, 0 deletions
diff --git a/apps/soreduce/Library.cpp b/apps/soreduce/Library.cpp
new file mode 100644
index 00000000000..198d34aac99
--- /dev/null
+++ b/apps/soreduce/Library.cpp
@@ -0,0 +1,368 @@
+// -*- C++ -*-
+// $Id$
+
+// File: Library.cpp
+
+// Author: Phil Mesnier
+
+// This file contains the implementation of the classes responsible for
+// generating specialized makefiles for individual libraries, as well as
+// outputting usage metrics for the various object modules contained in the
+// library.
+
+
+#include <ace/OS.h>
+#include <ace/OS_Dirent.h>
+#include <ace/Log_Msg.h>
+#include <ace/streams.h>
+
+#include "Library.h"
+
+ACE_RCSID(src, Library, "$Id$")
+
+Makefile_Generator::Makefile_Generator (const ACE_CString& libname)
+ : makefile_(),
+ libname_(libname),
+ makefilename_()
+{
+ makefilename_ = "Makefile." + libname_ + "_subset";
+}
+
+Makefile_Generator::~Makefile_Generator ()
+{
+}
+
+void
+Makefile_Generator::write_file (const ACE_CString& file)
+{
+ makefile_ << " \\\n\t" << file << flush;
+}
+
+void
+Makefile_Generator::write_prolog (const ACE_CString& path)
+{
+ ACE_CString fname (path + "/" + makefilename_);
+ ACE_DEBUG ((LM_DEBUG, "writing file %s\n",fname.c_str()));
+ makefile_.open(fname.c_str());
+ if (!makefile_)
+ ACE_DEBUG ((LM_DEBUG,"makefile open failed\n"));
+
+ makefile_
+ << "#--------------------------------------------------------------------"
+ << endl;
+ makefile_
+ << "# Generated makefile for producing a subset of the "
+ << libname_ << " library " << endl;
+ makefile_
+ << "#--------------------------------------------------------------------"
+ << endl;
+
+ makefile_ << "\nMAKEFILE = " << makefilename_ << endl;
+ makefile_ << "LIB = lib" << libname_ << "_subset.a" << endl;
+ makefile_ << "SHLIB = lib" << libname_ << "_subset.$(SOEXT)" << endl;
+ makefile_ << "\nFILES =" << flush;
+}
+
+void
+Makefile_Generator::write_epilog ()
+{
+ makefile_ << "\n" << endl;
+ this->write_libdeps();
+ makefile_
+ << "#--------------------------------------------------------" << endl;
+ makefile_
+ << "# Include macros and targets" << endl;
+ makefile_
+ << "#--------------------------------------------------------" << endl;
+ makefile_
+ << "include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU" << endl;
+
+ this->write_initial_rules();
+
+ makefile_
+ << "\nLSRC = $(addsuffix .cpp,$(FILES))\n" << endl;
+
+ makefile_
+ << "include $(ACE_ROOT)/include/makeinclude/macros.GNU" << endl;
+ makefile_
+ << "include $(ACE_ROOT)/include/makeinclude/rules.common.GNU" << endl;
+ makefile_
+ << "include $(ACE_ROOT)/include/makeinclude/rules.nested.GNU" << endl;
+ makefile_
+ << "include $(ACE_ROOT)/include/makeinclude/rules.lib.GNU" << endl;
+ makefile_
+ << "include $(ACE_ROOT)/include/makeinclude/rules.local.GNU" << endl;
+
+ this->write_final_rules();
+
+ makefile_ << "\n" << endl;
+
+ makefile_
+ << "#-----------------------------------------------------------" << endl;
+ makefile_
+ << "# Dependencies" << endl;
+ makefile_
+ << "#-----------------------------------------------------------" << endl;
+ makefile_
+ << "# DO NOT DELETE THIS LINE -- g++dep uses it." << endl;
+ makefile_
+ << "# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY." << endl;
+ makefile_
+ << "# IF YOU PUT ANYTHING HERE IT WILL GO AWAY" << endl;
+
+ makefile_.close();
+}
+
+void
+Makefile_Generator::write_libdeps()
+{
+ // nothing to do
+}
+
+void
+Makefile_Generator::write_initial_rules()
+{
+ // nothing to do
+}
+
+void
+Makefile_Generator::write_final_rules()
+{
+ // nothing to do
+}
+
+//-----------------------------------------------------------------------------
+Make_ACE_Dep_Lib::Make_ACE_Dep_Lib (const ACE_CString& libname)
+ : Makefile_Generator(libname)
+{}
+
+void
+Make_ACE_Dep_Lib::write_libdeps()
+{
+ makefile_ << "ACE_SHLIBS = -lACE_subset" << endl;
+}
+
+//-----------------------------------------------------------------------------
+Make_TAO_Lib::Make_TAO_Lib (const ACE_CString& libname)
+ : Make_ACE_Dep_Lib(libname)
+{}
+
+void
+Make_TAO_Lib::write_libdeps()
+{
+ makefile_ << "ifndef TAO_ROOT" << endl;
+ makefile_ << "TAO_ROOT = $(ACE_ROOT)/TAO" << endl;
+ makefile_ << "endif" << endl;
+
+ makefile_ << "ACE_SHLIBS = -lACE_subset" << endl;
+}
+
+void
+Make_TAO_Lib::write_initial_rules()
+{
+ makefile_ << "include $(TAO_ROOT)/rules.tao.GNU" << endl;
+}
+
+void
+Make_TAO_Lib::write_final_rules()
+{
+ makefile_ << "include $(TAO_ROOT)/taoconfig.mk" << endl;
+}
+
+//-----------------------------------------------------------------------------
+Make_TAO_Dep_Lib::Make_TAO_Dep_Lib (const ACE_CString& libname)
+ : Make_TAO_Lib(libname)
+{}
+
+void
+Make_TAO_Dep_Lib::write_libdeps()
+{
+ makefile_ << "ifndef TAO_ROOT" << endl;
+ makefile_ << "TAO_ROOT = $(ACE_ROOT)/TAO" << endl;
+ makefile_ << "endif" << endl;
+
+ makefile_ << "ACE_SHLIBS = -lTAO_subset -lACE_subset" << endl;
+}
+
+//-----------------------------------------------------------------------------
+
+Library::Library (const ACE_TCHAR *name)
+ : name_(name),
+ path_(),
+ num_modules_(0),
+ num_exports_(0),
+ num_extrefs_(0),
+ modules_(0),
+ exported_(0),
+ makefile_(0)
+{
+ if (name_ == "ACE")
+ makefile_ = new Makefile_Generator(name_);
+ else if (name_.find ("ACE_") == 0)
+ makefile_ = new Make_ACE_Dep_Lib (name_);
+ else if (name_ == "TAO")
+ makefile_ = new Make_TAO_Lib (name_);
+ else
+ makefile_ = new Make_TAO_Dep_Lib (name_);
+}
+
+Library::~Library ()
+{
+ delete makefile_;
+ int i;
+ for (i = 0; i < num_modules_; delete modules_[i++]);
+ delete [] modules_;
+}
+
+void
+Library::set_path (const ACE_TCHAR *p)
+{
+ char abspath[1000];
+ memset (abspath,0,1000);
+ int abspathlen = readlink(p,abspath,999);
+ ACE_CString path (p);
+ if (abspathlen > 0) {
+ abspath[abspathlen] = 0;
+ path = abspath;
+ }
+
+ int pathsep = path.rfind('/');
+
+ if (pathsep == ACE_CString::npos) {
+ path_ = ".";
+ } else {
+ path_ = path.substr(0,pathsep);
+ }
+}
+
+const ACE_CString &
+Library::name () const
+{
+ return name_;
+}
+
+int
+Library::has_modules () const
+{
+ return num_modules_ > 0;
+}
+
+static int
+selector (const dirent *d)
+{
+ return ACE_OS_String::strstr (d->d_name, ".o") != 0;
+}
+
+static int
+comparator (const dirent **d1, const dirent **d2)
+{
+ return ACE_OS_String::strcmp ((*d1)->d_name, (*d2)->d_name);
+}
+
+void
+Library::load_modules ()
+{
+ ACE_CString subdir = path_ + "/.shobj";
+
+ struct dirent **dent;
+ num_modules_ = ACE_OS_Dirent::scandir(subdir.c_str(),
+ &dent,selector,comparator);
+
+ if (num_modules_ > 0) {
+ modules_ = new Obj_Module * [num_modules_];
+ for (int i = 0; i < num_modules_; i++) {
+ modules_[i] = new Obj_Module(dent[i]->d_name);
+ modules_[i]->add_source (ACE_CString(subdir + "/" + dent[i]->d_name).c_str());
+ ACE_OS_Memory::free(dent[i]);
+ };
+ }
+
+ if (num_modules_ > -1)
+ ACE_OS_Memory::free(dent);
+}
+
+void
+Library::resolve (Sig_List &undefs)
+{
+ if (num_modules_ < 1)
+ return;
+
+ for (const Signature *uname = undefs.first();
+ undefs.hasmore();
+ uname = undefs.next()) {
+ if (exported_.index_of(uname) != -1) {
+ undefs.remove_current();
+ }
+ else
+ for (int i = 0; i < num_modules_; i++)
+ if (modules_[i]->extref() == 0 &&
+ modules_[i]->exports().index_of(uname) != -1)
+ {
+ undefs.remove_current();
+ exported_.add (modules_[i]->exports());
+ for (const Signature *needed = modules_[i]->imports().first();
+ modules_[i]->imports().hasmore();
+ needed = modules_[i]->imports().next())
+ if (exported_.index_of(needed) == -1)
+ undefs.add (needed->name());
+ modules_[i]->add_extref();
+ num_extrefs_++;
+ break;
+ }
+ }
+}
+
+void
+Library::write_export_list (int show_ref_counts)
+{
+ if (num_modules_ < 1)
+ return;
+
+ ACE_CString excludedfilename = path_ + "/excluded_modules";
+ ACE_CString rcpath = path_ + "/usage_metrics";
+
+ ofstream exclusions (excludedfilename.c_str());
+ if (!exclusions) {
+ ACE_ERROR ((LM_ERROR, "%p\n", "open exclusions list"));
+ }
+
+ if (show_ref_counts) {
+ ACE_DEBUG ((LM_DEBUG, "Making directory %s\n",rcpath.c_str()));
+ if (ACE_OS::mkdir(rcpath.c_str()) == -1)
+ ACE_ERROR ((LM_ERROR, "%p\n", "mkdir"));
+ }
+
+ ACE_DEBUG ((LM_DEBUG,"%s: %d out of %d modules required\n",
+ name_.c_str(), num_extrefs_, num_modules_));
+
+ makefile_->write_prolog(path_);
+
+ for (int i = 0; i < num_modules_ ; i++)
+ if (modules_[i]->extref()) {
+ if (show_ref_counts) {
+ ACE_CString fname = rcpath + "/" + modules_[i]->name();
+ ofstream countfile (fname.c_str());
+ countfile << "Exported symbols:" << endl;
+ for (const Signature *sig = modules_[i]->exports().first();
+ modules_[i]->exports().hasmore();
+ sig = modules_[i]->exports().next())
+ {
+ countfile.width(5);
+ countfile << sig->used_count() << " " << sig->name() << endl;
+ }
+ countfile << "\nImported symbols:" << endl;
+ for (const Signature *sig = modules_[i]->imports().first();
+ modules_[i]->imports().hasmore();
+ sig = modules_[i]->imports().next())
+ countfile << sig->name() << endl;
+ }
+ makefile_->write_file(modules_[i]->name().substring(0,modules_[i]->name().length()-2));
+ } else {
+ // const char * modname = modules_[i]->name().c_str();
+ exclusions
+ << modules_[i]->name().substring(0,modules_[i]->name().length()-2)
+ << endl;
+ }
+
+ makefile_->write_epilog();
+}
diff --git a/apps/soreduce/Library.h b/apps/soreduce/Library.h
new file mode 100644
index 00000000000..46cb03feac7
--- /dev/null
+++ b/apps/soreduce/Library.h
@@ -0,0 +1,126 @@
+// -*- C++ -*-
+#ifndef _LIBRARY_H_
+#define _LIBRARY_H_
+
+// -*- C++ -*-
+// $Id$
+
+// File: Library.h
+
+// Author: Phil Mesnier
+
+// A Library is a collection of Obj_Modules that define a single shared
+// library. It is used to manipulate the list of unresolved references by
+// removing those that are resolved and adding those brought in by new modules
+// that are required to resolve references. The Library is responsible
+// for outputting a specialized makefile build the reduce footprint library.
+
+#include "Obj_Module.h"
+
+// The Makefile generator class serves as the base class used to output the
+// custom makefiles (or in the future, project files) used to build the
+// subsetted libraries.
+// The base class will make libACE_subset.so
+
+class Makefile_Generator
+{
+public:
+ Makefile_Generator (const ACE_CString& );
+ virtual ~Makefile_Generator();
+
+ void write_prolog (const ACE_CString& );
+ void write_file (const ACE_CString& );
+ void write_epilog ();
+
+protected:
+ virtual void write_libdeps();
+ virtual void write_initial_rules();
+ virtual void write_final_rules();
+
+ ofstream makefile_;
+ ACE_CString libname_;
+ ACE_CString makefilename_;
+};
+
+// Generate makefiles for libraries dependant on ACE, that are not TAO.
+class Make_ACE_Dep_Lib : public Makefile_Generator
+{
+public:
+ Make_ACE_Dep_Lib (const ACE_CString& );
+
+protected:
+ virtual void write_libdeps();
+};
+
+// Generates makefiles for libTAO_subset.so
+class Make_TAO_Lib : public Make_ACE_Dep_Lib
+{
+public:
+ Make_TAO_Lib (const ACE_CString& );
+
+protected:
+ virtual void write_libdeps();
+ virtual void write_initial_rules();
+ virtual void write_final_rules();
+};
+
+// Generates makefiles for libs dependant on TAO. This has a problem when
+// building libraries in the orbsvcs tree.
+class Make_TAO_Dep_Lib : public Make_TAO_Lib
+{
+public:
+ Make_TAO_Dep_Lib (const ACE_CString& );
+
+protected:
+ virtual void write_libdeps();
+};
+
+//----------------------------------------------------------------------------
+
+class Library
+{
+public:
+
+ Library (const ACE_TCHAR *name = 0 );
+ /// Constructor is responsible for loading all of the modules related to the
+ /// library
+ ~Library ();
+
+ // Resolve interates over the supplied list of undefined signatures to locate
+ // modules that contain definitions. Any symbol defined in a module marked as
+ // exported is simply removed from the undef list. Any symbol defined in a
+ // module not yet exported removed from the undef list, the module is marked
+ // as exported, and its unresolved symbols are added to the undef list.
+ void resolve (Sig_List &undefs);
+
+ // Outputs a list of files suitable for inclusion in a makefile to produce
+ // a subsetted library. If the argument is non-zero, reference countes for
+ // each module are also listed.
+ void write_export_list ( int );
+
+ // set the path to find the .so files
+ void set_path (const ACE_TCHAR *p );
+
+ // Load the actual .so files from the path.
+ void load_modules();
+
+ // returns the library name
+ const ACE_CString &name () const;
+
+ // returns non-zero if the module count is > 0.
+ int has_modules () const;
+
+private:
+ ACE_CString name_;
+ ACE_CString path_;
+
+ int num_modules_;
+ int num_exports_;
+ int num_extrefs_;
+
+ Obj_Module **modules_;
+ Sig_List exported_;
+ Makefile_Generator *makefile_;
+};
+
+#endif /* _LIBRARY_H_ */
diff --git a/apps/soreduce/Makefile b/apps/soreduce/Makefile
new file mode 100644
index 00000000000..2fe50972d21
--- /dev/null
+++ b/apps/soreduce/Makefile
@@ -0,0 +1,42 @@
+#----------------------------------------------------------------------------
+# $Id$
+#
+# Makefile for soreduce utility
+#----------------------------------------------------------------------------
+
+BIN = soreduce
+INSBIN = $(ACE_ROOT)/bin/soreduce
+
+FILES = Signature \
+ Sig_List \
+ Obj_Module \
+ Library \
+ SO_Group \
+ soreduce
+
+SRC = $(addsuffix .cpp,$(FILES))
+OBJ = $(addsuffix .o,$(FILES))
+
+BUILD = $(VBIN)
+
+INSTALL = $(VBIN:%=$(INSBIN)/%$(EXEEXT))
+
+#----------------------------------------------------------------------------
+# Include macros and targets
+#----------------------------------------------------------------------------
+
+include $(ACE_ROOT)/include/makeinclude/wrapper_macros.GNU
+include $(ACE_ROOT)/include/makeinclude/macros.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.common.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.nonested.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.bin.GNU
+include $(ACE_ROOT)/include/makeinclude/rules.local.GNU
+
+#----------------------------------------------------------------------------
+# Dependencies
+#----------------------------------------------------------------------------
+
+# DO NOT DELETE THIS LINE -- g++dep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
+
+# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
diff --git a/apps/soreduce/Obj_Module.cpp b/apps/soreduce/Obj_Module.cpp
new file mode 100644
index 00000000000..ac6881dd96f
--- /dev/null
+++ b/apps/soreduce/Obj_Module.cpp
@@ -0,0 +1,193 @@
+// -*- C++ -*-
+// $Id$
+
+// File: Obj_Module.cpp
+
+// Author: Phil Mesnier
+
+// This file contains the implementation of the classes responsible for
+// managing the contents of a single object module (.o file).
+
+#include <ace/Process.h>
+#include <ace/Pipe.h>
+#include <ace/Message_Block.h>
+
+#include "Obj_Module.h"
+
+
+ACE_RCSID(src, Obj_Module, "$Id$")
+
+
+//----------------------------------------------------------------------------
+
+Obj_Module::Obj_Module (const ACE_CString &name, int cap)
+ : name_ (name),
+ imports_(cap),
+ exports_(cap),
+ extrefs_(0)
+{
+}
+
+ACE_CString &
+Obj_Module::name()
+{
+ return name_;
+}
+
+Sig_List &
+Obj_Module::exports()
+{
+ return exports_;
+}
+
+Sig_List &
+Obj_Module::imports()
+{
+ return imports_;
+}
+
+int
+Obj_Module::extref()
+{
+ return extrefs_;
+}
+
+void
+Obj_Module::add_extref()
+{
+ extrefs_ ++;
+}
+
+void
+Obj_Module::remove_extref()
+{
+ extrefs_ --;
+}
+
+int
+Obj_Module::read_line (ACE_HANDLE src, ACE_Message_Block **buf)
+{
+ int eoln = 0;
+ // ACE_Time_Value timeout (1,0);
+ if (buf == 0 || *buf == 0) {
+ char dummy;
+ while (!eoln && ACE_OS::read(src,&dummy,1) == 1) {
+ eoln = (dummy == '\n');
+ }
+ return eoln;
+ }
+ // while (!eoln && ACE::recv(src,buf->wr_ptr(),1,&timeout) == 1) {
+ while (!eoln && ACE_OS::read(src,(*buf)->wr_ptr(),1) == 1) {
+ eoln = (*(*buf)->wr_ptr() == '\n');
+ (*buf)->wr_ptr(1);
+ if ((*buf)->space() == 0) {
+ (*buf)->cont(new ACE_Message_Block(102400));
+ *buf = (*buf)->cont();
+ }
+ }
+ return eoln;
+}
+
+void
+Obj_Module::add_source(const ACE_TCHAR *p, int imports_only)
+{
+ ACE_Process nmproc;
+ ACE_Process_Options nm_opts;
+ ACE_CString path (p);
+
+ int pathsep = path.rfind('/');
+
+ ACE_CString src_name;
+ ACE_CString workpath;
+
+ if (pathsep == ACE_CString::npos) {
+ src_name = path;
+ workpath = ".";
+ } else {
+ src_name = path.substr(pathsep+1);
+ workpath= path.substr(0,pathsep);
+ }
+
+ ACE_HANDLE pipe[2];
+ ACE_Pipe io(pipe);
+
+ nm_opts.working_directory (workpath.c_str());
+ nm_opts.set_handles (ACE_STDIN,pipe[1]);
+
+ // Options for the command line shown here are for the GNU nm 2.9.5
+
+ ACE_ASSERT(nm_opts.command_line ("nm -C %s",src_name.c_str()) == 0);
+
+ nmproc.spawn (nm_opts);
+ if (ACE_OS::close(pipe[1]) == -1)
+ ACE_DEBUG ((LM_DEBUG, "%p\n", "close"));
+ nm_opts.release_handles();
+
+ int import_lines = 0;
+ int export_lines = 0;
+ ACE_Message_Block im_buffer (102400);
+ ACE_Message_Block ex_buffer (102400);
+ ACE_Message_Block *im_buf_cur = &im_buffer;
+ ACE_Message_Block *ex_buf_cur = &ex_buffer;
+ char dummy;
+ int eoln = 1;
+ // ACE_Time_Value timeout (1,0);
+ int is_import = 1;
+ int is_export = 1;
+
+ while (eoln == 1) {
+ for (int i = 0; i < 10; i++) {
+ if (ACE_OS::read(pipe[0],&dummy,1) != 1) {
+ eoln = 2;
+ break;
+ }
+ }
+ if (eoln == 2)
+ break;
+ is_import = dummy == 'U';
+ is_export = !imports_only && (ACE_OS_String::strchr("BCDRTVW",dummy) != 0);
+
+ // if (ACE::recv(pipe[0],&dummy,1,&timeout) != 1)
+ if (ACE_OS::read(pipe[0],&dummy,1) != 1)
+ break;
+
+ eoln = this->read_line (pipe[0], is_import ? &im_buf_cur :
+ (is_export ? &ex_buf_cur : 0));
+ import_lines += is_import;
+ export_lines += is_export;
+ }
+ // ACE_DEBUG ((LM_DEBUG, "read %d import lines and %d export lines\n",
+ // import_lines, export_lines));
+
+ nmproc.wait ();
+ close (pipe[0]);
+
+ this->populate_sig_list (imports_,import_lines,&im_buffer);
+ if (!imports_only)
+ this->populate_sig_list (exports_,export_lines,&ex_buffer);
+}
+
+void
+Obj_Module::populate_sig_list (Sig_List &siglist,
+ int lines,
+ ACE_Message_Block *buf)
+{
+ char *c;
+ ACE_CString temp;
+ for (int i = 0; i < lines; i++) {
+ for (c = buf->rd_ptr();
+ c != buf->wr_ptr() && *c != '\n'; c++);
+ temp += ACE_CString(buf->rd_ptr(),(c - buf->rd_ptr()));
+ buf->rd_ptr(c+1);
+ if (*c == '\n') {
+ // ACE_DEBUG ((LM_DEBUG, "%s\n",temp.c_str()));
+ siglist.add (temp);
+ temp.clear();
+ } else {
+ buf = buf->cont();
+ if (buf == 0) {
+ siglist.add (temp);
+ }
+ }
+ }
+}
diff --git a/apps/soreduce/Obj_Module.h b/apps/soreduce/Obj_Module.h
new file mode 100644
index 00000000000..7d2dd489754
--- /dev/null
+++ b/apps/soreduce/Obj_Module.h
@@ -0,0 +1,66 @@
+// -*- C++ -*-
+// $Id$
+
+// File: Obj_Module.h
+
+// Author: Phil Mesnier
+
+#ifndef _OBJ_MODULE_H_
+#define _OBJ_MODULE_H_
+
+// Obj_Module encapsulates the result of applying nm to a single object module
+// in a shared library. Currently an object module consists of two types of
+// signatures, those that are exported, able to resolve references from others,
+// and those that are imported, needing resolution.
+//
+// Obj_Modules keep track of external references. In the end, any module that
+// has one or more external references to it must be included in the resulting
+// library. While the means exists to remove external references, perhaps
+// through further analysis of undefined signatures and their usage, this is
+// not currently done. Once a technique is discovered to allow for easy
+// determination that reference is truly unneeded this code may be useful.
+
+#include "Sig_List.h"
+
+class Obj_Module {
+public:
+ Obj_Module ( const ACE_CString &, int = 500);
+
+ // Returns the list of exported signatures, ie. those that are defined in
+ // this module
+ Sig_List & exports();
+
+ // Returns the list of signatures used by this module but not defined within
+ Sig_List & imports();
+
+ // Returns the name of the object module.
+ ACE_CString &name();
+
+ // Add_source invokes GNU nm on the supplied file and parses the output to
+ // build the list of imported and exported signatures. When replacing GNU
+ // nm to use a different tool, this method must be modified. In the future
+ // this could be a virtual to allow for specialization based on toolset.
+ void add_source (const ACE_TCHAR *, int = 0);
+
+ // Get the number of external references to this object module. At the end
+ // of processing, if the number of external references is 0, the module is
+ // not included in the final library.
+ int extref ();
+
+ // add a new external reference to this module.
+ void add_extref ();
+
+ // remove an exterenal reference. Currently, this function is not used.
+ void remove_extref();
+
+private:
+ void populate_sig_list (Sig_List &, int , ACE_Message_Block *);
+ int read_line (ACE_HANDLE src, ACE_Message_Block **buf);
+
+ ACE_CString name_;
+ Sig_List imports_;
+ Sig_List exports_;
+ int extrefs_;
+};
+
+#endif /* _OBJ_MODULE_H_ */
diff --git a/apps/soreduce/README b/apps/soreduce/README
new file mode 100644
index 00000000000..abe3d64f084
--- /dev/null
+++ b/apps/soreduce/README
@@ -0,0 +1,153 @@
+Shared Library Reduction Tool
+The motivation for this tool was the understanding that the ACE & TAO libraries
+were to be linked with the VxWorks kernel to allow multiple applications to be
+run simultaniously with a minimum of footprint consumed. Ordinarily a choice is
+made between static linking applications, where each application gets only the
+object modules needed, and shared object linkage, where multiple applications
+share access to full libraries. Frequently a shared library will contain code
+and data which is not used by any of the applications in a particular
+configuration. The Shared Library Reduction Tool builds libraries that include
+only the modules needed to support a specified set of applications.
+
+The analysis is performed very late in the application implementation, allowing
+the system implementors the freedom to use whatever TAO & ACE components are
+needed. Once an application is built and running, its shared object need may be
+evaluated. The evaluation is straight forward. Run the soreduce program,
+passing the path to all of the applications that will share the libraries. The
+soreduce program uses the following steps to generate its results.
+
+1. A list of undefined symbols and shared libraries is built by invoking the
+ldd and nm commands on each application. For now, soreduce assumes the GNU
+variant of these tools.
+
+2. For each shared library, soreduce tries to invoke nm on each of the
+intermediate object files used to build the library. It is important that
+target library directory has a current .shobj subdirectory.
+
+3. The list of undefined symbols is traversed. For each entry in the list, the
+modules loaded from step 2 are examined to look for a matching symbol. When one
+is found, the target symbol, and any others satisfied by the module are removed
+from the list, and any undefined symbols in the module are added to the list.
+This process is repeated until the entire list of undefined symbols is
+traversed without change.
+
+4. Makefiles are generated. Rather than invoking the linker directly, a make
+file is generated that may be used to build the libs. With these makefiles, the
+actual library will be named lib(orig)_subset.so.
+
+Analysis Artifacts
+Development of the shared library reduction tool also provided a secondary
+benefit. It is able to output usage metrics for the various modules, which may
+be useful for directing further hand-crafted reduction efforts. Using the GNU
+nm with more verbose output, it is possible to determine the first function
+using a given undefined symbol. While it is not (yet) possible to automate the
+refactoring of code based on this analysis, this information can provide a road
+map for breaking a single module into two or a few that will result in fewer
+incidental dependancies overall. However this speculation has not been tested.
+
+Test results
+Running soreduce providing itself as the sole client. The soreduce application
+is built on top of ACE, using just a few of ACE's features. Here is the output:
+
+bash$ ./soreduce soreduce
+discovering libraries
+loading object modules
+Libs subject to analysis:
+ ACE
+Starting analysis
+pass 0, undef count = 69
+pass 1, undef count = 207
+pass 2, undef count = 278
+pass 3, undef count = 271
+pass 4, undef count = 245
+pass 5, undef count = 235
+Writing results
+Making directory /opt/wustl/ACE_wrappers/build/native/ace/usage_metrics
+mkdir: File exists
+ACE: 61 out of 210 modules required
+writing file /opt/wustl/ACE_wrappers/build/native/ace/Makefile.ACE_subset
+Done.
+
+The size of libACE.so before rebuilding:
+
+bash$ size libACE.so
+ text data bss dec hex filename
+2361958 498760 12516 2873234 2bd792 libACE.so
+
+and after:
+
+bash$ size libACE_subset.so
+ text data bss dec hex filename
+ 987167 207452 7580 1202199 125817 libACE_subset.so
+
+
+2873234 - 1202199 = 1671035 bytes eliminated, a 58.2% reduction
+
+Here is another example, using the Naming Service, and its simple test client.
+Note that the orbsvcs results are bogus, the libraries are already fairly well
+factored so that the additional subsetting by soreduce is not effective. Also,
+due to the layout of the orbsvcs library source directory, the tool does not
+generate valid makefiles.
+
+bash$ $ACE_ROOT/apps/soreduce/soreduce Naming_Service/Naming_Service tests/Simple_Naming/client
+discovering libraries
+loading object modules
+Libs subject to analysis:
+ TAO_CosNaming
+ TAO_Svc_Utils
+ TAO_IORTable
+ TAO_PortableServer
+ TAO
+ ACE
+Starting analysis
+pass 0, undef count = 339
+pass 1, undef count = 580
+pass 2, undef count = 438
+pass 3, undef count = 278
+pass 4, undef count = 244
+pass 5, undef count = 246
+pass 6, undef count = 242
+Writing results
+Making directory /opt/wustl/ACE_wrappers/build/native/TAO/orbsvcs/orbsvcs/usage_metrics
+TAO_CosNaming: 11 out of 256 modules required
+writing file /opt/wustl/ACE_wrappers/build/native/TAO/orbsvcs/orbsvcs/Makefile.TAO_CosNaming_subset
+Making directory /opt/wustl/ACE_wrappers/build/native/TAO/orbsvcs/orbsvcs/usage_metrics
+mkdir: File exists
+TAO_Svc_Utils: 8 out of 256 modules required
+writing file /opt/wustl/ACE_wrappers/build/native/TAO/orbsvcs/orbsvcs/Makefile.TAO_Svc_Utils_subset
+Making directory /opt/wustl/ACE_wrappers/build/native/TAO/tao/IORTable/usage_metrics
+TAO_IORTable: 4 out of 4 modules required
+writing file /opt/wustl/ACE_wrappers/build/native/TAO/tao/IORTable/Makefile.TAO_IORTable_subset
+Making directory /opt/wustl/ACE_wrappers/build/native/TAO/tao/PortableServer/usage_metrics
+TAO_PortableServer: 26 out of 29 modules required
+writing file /opt/wustl/ACE_wrappers/build/native/TAO/tao/PortableServer/Makefile.TAO_PortableServer_subset
+Making directory /opt/wustl/ACE_wrappers/build/native/TAO/tao/usage_metrics
+mkdir: File exists
+TAO: 160 out of 191 modules required
+writing file /opt/wustl/ACE_wrappers/build/native/TAO/tao/Makefile.TAO_subset
+Making directory /opt/wustl/ACE_wrappers/build/native/ace/usage_metrics
+mkdir: File exists
+ACE: 75 out of 210 modules required
+writing file /opt/wustl/ACE_wrappers/build/native/ace/Makefile.ACE_subset
+Done.
+
+Size before & after:
+ text data bss dec hex filename
+2361958 498760 12516 2873234 2bd792 libACE.so
+3432206 704188 30992 4167386 3f96da libTAO.so
+1931145 326632 7528 2265305 2290d9 libTAO_PortableServer.so
+ 76561 12504 364 89429 15d55 libTAO_IORTable.so
+
+
+Sum: 9395354
+
+
+ text data bss dec hex filename
+1340017 275440 8140 1623597 18c62d libACE_subset.so
+3131226 643816 27984 3803026 3a0792 libTAO_subset.so
+1845515 308812 6896 2161223 20fa47 libTAO_PortableServer_subset.so
+ 76603 12508 364 89475 15d83 libTAO_IORTable_subset.so
+
+Sum: 7677321
+
+Savings: 1718033 or 18.3%
diff --git a/apps/soreduce/SO_Group.cpp b/apps/soreduce/SO_Group.cpp
new file mode 100644
index 00000000000..b00cdeeb019
--- /dev/null
+++ b/apps/soreduce/SO_Group.cpp
@@ -0,0 +1,158 @@
+
+#include <ace/OS.h>
+#include <ace/Log_Msg.h>
+
+#include <ace/Process.h>
+#include <ace/Pipe.h>
+
+#include "Library.h"
+#include "SO_Group.h"
+
+ACE_RCSID(src, SO_Group, "$Id$")
+
+
+SO_Group::SO_Group ()
+ : undef_wrapper_ ("nothing"),
+ undefs_(undef_wrapper_.imports()),
+ libs_ (0),
+ max_libs_ (30),
+ num_libs_(0)
+{
+ libs_ = new Library*[max_libs_];
+}
+
+SO_Group::~SO_Group ()
+{
+ for (int i = 0; i < num_libs_; delete libs_[i++]);
+ delete [] libs_;
+}
+
+void
+SO_Group::add_executable (const char * path)
+{
+ ACE_Process proc;
+ ACE_Process_Options opts;
+
+ ACE_HANDLE pipe[2];
+ ACE_Pipe io(pipe);
+
+ opts.set_handles (ACE_STDIN,pipe[1]);
+
+ ACE_ASSERT(opts.command_line ("ldd %s",path) == 0);
+
+ proc.spawn (opts);
+ if (ACE_OS::close(pipe[1]) == -1)
+ ACE_DEBUG ((LM_DEBUG, "%p\n", "close"));
+ opts.release_handles();
+
+ const int max_line_length = 1000;
+ char line[max_line_length];
+
+ while (1) {
+ ACE_OS::memset (line,0,max_line_length);
+ int len = 0;
+ int nread = 0;
+ int bogus = 0;
+ // skip initial whitespace
+ while ((nread = ACE_OS::read(pipe[0],line,1)) == 1 &&
+ (*line == ' ' || *line == '\t'));
+
+ if (nread != 1)
+ break;
+
+ // read the library name
+ len = 1;
+ while ((nread = ACE_OS::read(pipe[0],line + len,1)) == 1 &&
+ (line[len] != ' '))
+ if (! bogus && ++len == max_line_length)
+ {
+ bogus = 1;
+ break;
+ }
+ if (nread != 1 || bogus)
+ break;
+ line[len] = 0;
+ char * dot = ACE_OS::strchr (line,'.');
+ if (dot)
+ *dot = 0;
+ char * libname = line + 3; // skip over "lib"
+
+ // check to see if this is a new library
+ int found = 0;
+ for (int i = 0; !found && i < num_libs_; i++)
+ found = (libs_[i]->name() == libname);
+
+ if (!found) {
+ Library *nlib = new Library(libname);
+ ACE_OS::memset (line,0,max_line_length);
+
+ // skip over '=> '
+ if (ACE_OS::read(pipe[0],line,3) != 3)
+ break;
+
+ // get library path
+ len = 0;
+ while ((nread = ACE_OS::read(pipe[0],line + len,1)) == 1 &&
+ (line[len] != ' '))
+ if (! bogus && ++len == max_line_length)
+ {
+ bogus = 1;
+ break;
+ }
+ if (nread != 1 || bogus)
+ break;
+ line[len] = 0;
+ nlib->set_path (line);
+ libs_[num_libs_++] = nlib;
+ ACE_ASSERT (num_libs_ < max_libs_); // grow max libs?
+ }
+ // skip the rest of the line
+ while ((nread = ACE_OS::read(pipe[0],line,1)) == 1 && *line != '\n');
+ if (nread != 1)
+ break;
+ }
+ proc.wait ();
+ close (pipe[0]);
+
+ undef_wrapper_.add_source(path,1);
+ // now do the ldd, iterate over the results to add new libs, etc.
+}
+
+void
+SO_Group::analize ()
+{
+ for (int passcount = 0; undefs_.modified(); passcount++) {
+ ACE_DEBUG ((LM_DEBUG,"pass %d, undef count = %d\n",
+ passcount,undefs_.size()));
+ for (int i = 0; i < num_libs_; libs_[i++]->resolve(undefs_));
+ }
+}
+
+void
+SO_Group::write_results()
+{
+ for (int i = 0; i < num_libs_; libs_[i++]->write_export_list(1));
+}
+
+void
+SO_Group::load_modules()
+{
+ for (int i = 0; i < num_libs_; libs_[i++]->load_modules());
+}
+
+void
+SO_Group::list_libs()
+{
+ ACE_DEBUG ((LM_DEBUG,"Libs subject to analysis:\n"));
+ for (int i = 0; i < num_libs_; i++) {
+ if (libs_[i]->has_modules())
+ ACE_DEBUG ((LM_DEBUG," %s\n", libs_[i]->name().c_str()));
+ }
+}
+
+
+
+
+
+
+
diff --git a/apps/soreduce/SO_Group.h b/apps/soreduce/SO_Group.h
new file mode 100644
index 00000000000..09758c8c7bb
--- /dev/null
+++ b/apps/soreduce/SO_Group.h
@@ -0,0 +1,48 @@
+// -*- C++ -*-
+// $Id$
+
+// File: SO_Group.h
+
+// Author: Phil Mesnier
+
+#ifndef _SO_GROUP_H_
+#define _SO_GROUP_H_
+
+#include "Library.h"
+
+// A shared object group is a wrapper around all of the information needed to
+// analize a collection of applications so that common shared libraries can
+// be reduced.
+
+class SO_Group
+{
+public:
+ SO_Group ();
+ ~SO_Group ();
+
+ // For each executable named, run ldd to get the dependances list, For each
+ // library listed, see if there is a path to .shobj and add to the list of
+ // libraries if found. Finally, add the undefined symbols from the executable
+ // to the undefs collection.
+ void add_executable(const char * );
+
+ // Do the actual business of the program
+ void analize ();
+
+ // Output the results
+ void write_results ();
+
+ // load the object modules for the group
+ void load_modules ();
+
+ void list_libs();
+
+private:
+ Obj_Module undef_wrapper_;
+ Sig_List &undefs_;
+ Library **libs_;
+ int max_libs_;
+ int num_libs_;
+};
+
+#endif //_SO_GROUP_H_
diff --git a/apps/soreduce/Sig_List.cpp b/apps/soreduce/Sig_List.cpp
new file mode 100644
index 00000000000..4327a14bdc4
--- /dev/null
+++ b/apps/soreduce/Sig_List.cpp
@@ -0,0 +1,184 @@
+
+// $Id$
+
+// File: Sig_List.cpp
+
+// Author: Phil Mesnier
+
+#include "Sig_List.h"
+
+ACE_RCSID(src, Sig_List, "$Id$")
+
+//-----------------------------------------------------------------------------
+
+Sig_List::Sig_List (int cap)
+ : size_(0),
+ capacity_(cap),
+ index_(0),
+ has_nulls_(0),
+ modified_(0),
+ array_(0)
+{
+ array_ = new Signature*[capacity_];
+}
+
+Sig_List::~Sig_List ()
+{
+ for (int i = 0; i < size_; i++)
+ if (array_[i]) array_[i]->release();
+ delete [] array_;
+}
+
+void
+Sig_List::add (const ACE_CString &s)
+{
+ if (this->index_of (s) != -1)
+ return;
+ modified_ = 1;
+ if (has_nulls_)
+ for (int i = 0; i < size_; i++)
+ if (array_[i] == 0) {
+ array_[i] = new Signature (s);
+ has_nulls_ --;
+ return;
+ }
+ if (size_ == capacity_) {
+ int ncap = capacity_ * 2;
+ Signature ** narray = new Signature *[ncap];
+ ACE_OS::memcpy (narray,array_,capacity_ * sizeof(Signature*));
+ delete [] array_;
+ array_ = narray;
+ capacity_ = ncap;
+ }
+ array_[size_++] = new Signature(s);
+}
+
+void
+Sig_List::add (const Sig_List &other)
+{
+ if (capacity_ < size_ + other.capacity_) {
+ int ncap = size_ + other.capacity_ + 50;
+ Signature ** narray = new Signature *[ncap];
+ ACE_OS::memcpy (narray,array_,capacity_ * sizeof(Signature*));
+ delete [] array_;
+ array_ = narray;
+ capacity_ = ncap;
+ }
+ modified_ = 1;
+ for (int i = 0; i < other.size_; i++)
+ if (other.array_[i] != 0 &&
+ this->index_of (other.array_[i]->name()) == -1)
+ {
+ if (!has_nulls_)
+ array_[size_++] = other.array_[i]->dup();
+ else
+ for (int i = 0; i < size_; i++)
+ if (array_[i] == 0)
+ {
+ array_[i] = other.array_[i]->dup();
+ has_nulls_ --;
+ break;
+ }
+ }
+}
+
+void
+Sig_List::remove (const Signature &s)
+{
+ for (int i = 0; i < size_; i++)
+ if (array_[i] && array_[i]->name() == s.name()) {
+ array_[i]->release();
+ array_[i] = 0;
+ modified_ = 1;
+ if (i == size_ - 1)
+ size_ --;
+ else
+ has_nulls_ ++;
+ break;
+ }
+}
+
+void
+Sig_List::remove_current ()
+{
+ array_[index_]->release();
+ array_[index_] = 0;
+ modified_ = 1;
+ if (index_ == size_ - 1)
+ size_--;
+ else
+ has_nulls_++;
+}
+
+int
+Sig_List::index_of (const Signature *s)
+{
+ for (int i = 0; i < size_; i++)
+ if (array_[i] && array_[i]->name() == s->name()) {
+ array_[i]->used();
+ return i;
+ }
+ return -1;
+}
+
+int
+Sig_List::index_of (const ACE_CString &s)
+{
+ for (int i = 0; i < size_; i++)
+ if (array_[i] && array_[i]->name() == s) {
+ return i;
+ }
+ return -1;
+}
+
+
+const Signature *
+Sig_List::first()
+{
+ for (index_ = 0; index_ < size_; index_++)
+ if (array_[index_] != 0)
+ return array_[index_];
+ return 0;
+}
+
+const Signature *
+Sig_List::next()
+{
+ for (++index_; index_ < size_; index_++)
+ if (array_[index_] != 0)
+ return array_[index_];
+ return 0;
+}
+
+int
+Sig_List::hasmore ()
+{
+ return index_ < size_;
+}
+
+int
+Sig_List::size()
+{
+ return size_;
+}
+
+int
+Sig_List::modified()
+{
+ int rtn = modified_;
+ modified_ = 0;
+ int insert = 0;
+ if (has_nulls_) {
+ for (int i = 0; i < size_; i++)
+ if (array_[i] != 0) {
+ if (i != insert) {
+ array_[insert] = array_[i];
+ array_[i] = 0;
+ }
+ insert++;
+ }
+ size_ = insert+1;
+ has_nulls_ = 0;
+ }
+ return rtn;
+}
diff --git a/apps/soreduce/Sig_List.h b/apps/soreduce/Sig_List.h
new file mode 100644
index 00000000000..9b4b0dc115f
--- /dev/null
+++ b/apps/soreduce/Sig_List.h
@@ -0,0 +1,49 @@
+// -*- C++ -*-
+// $Id$
+
+// File: Sig_List.h
+
+// Author: Phil Mesnier
+
+
+#ifndef _SIG_LIST_H_
+#define _SIG_LIST_H_
+
+// A Sig_List is a specialized container of signatures. The initial use of a
+// Sig_List was to manage a variable length of undefined Signatures, so the
+// program could know when all possible resolutions were determined. As the
+// program grows in complexity, Sig_Lists are used to store other groups as
+// well. The methods provide simple list traversal, as well as efficient use
+// of space.
+
+#include "Signature.h"
+
+class Sig_List {
+public:
+ Sig_List (int cap = 500);
+ ~Sig_List ();
+ void add (const ACE_CString &s);
+ void add (const Sig_List &other);
+ void remove (const Signature &s);
+ void remove_current ();
+
+ int index_of (const Signature *s);
+ int index_of (const ACE_CString &s);
+ int hasmore();
+ const Signature *first();
+ const Signature *next();
+
+ int modified ();
+ int size();
+
+private:
+ int size_;
+ int capacity_;
+ int index_;
+ int has_nulls_;
+ int modified_;
+ Signature ** array_;
+};
+
+
+#endif /* _SIG_LIST_H_ */
diff --git a/apps/soreduce/Signature.cpp b/apps/soreduce/Signature.cpp
new file mode 100644
index 00000000000..2d4d907e92b
--- /dev/null
+++ b/apps/soreduce/Signature.cpp
@@ -0,0 +1,45 @@
+#include "Signature.h"
+
+ACE_RCSID(src, Signature, "$Id$")
+
+//-----------------------------------------------------------------------------
+
+Signature::Signature (const ACE_CString &name)
+ :name_(name),
+ ref_count_ (1),
+ used_ (0)
+{
+}
+
+void
+Signature::used ()
+{
+ used_++;
+}
+
+int
+Signature::used_count() const
+{
+ return used_;
+}
+
+const ACE_CString &
+Signature::name() const
+{
+ return name_;
+}
+
+Signature *
+Signature::dup()
+{
+ ref_count_++;
+ return this;
+}
+
+void
+Signature::release()
+{
+ if (--ref_count_ == 0)
+ delete this;
+}
+
diff --git a/apps/soreduce/Signature.h b/apps/soreduce/Signature.h
new file mode 100644
index 00000000000..358a756aa7a
--- /dev/null
+++ b/apps/soreduce/Signature.h
@@ -0,0 +1,50 @@
+// -*- C++ -*-
+// $Id$
+
+// File: Signature.h
+
+// Author: Phil Mesnier
+
+
+#ifndef _SIGNATURE_H_
+#define _SIGNATURE_H_
+
+// Signature class encapsulates a single line of nm output. This line may be
+// either an "undefined" name to be resolved, or text or data which resolves
+// the unknowns. Some of the features of the Signature class are currently
+// unused, such as owner_, which is anticipation of analysis that may lead to
+// further code reduction. The premise being that unresolved symbols that are
+// defined within otherwise unused code should not be resolved. However this
+// information is not available in the output of nm. Further research is
+// required.
+//
+// Signatures are reference counted to avoid duplication.
+
+#include <ace/SString.h>
+
+class Signature {
+public:
+
+ enum Kind {
+ text_,
+ undef_
+ };
+
+ Signature (const ACE_CString &);
+ void used ();
+ int used_count() const;
+
+ const ACE_CString &name() const;
+
+ Signature *dup();
+ void release();
+
+private:
+ ACE_CString name_;
+ int ref_count_;
+ int used_;
+ Signature * owner_;
+ Kind kind_;
+};
+
+#endif
diff --git a/apps/soreduce/soreduce.cpp b/apps/soreduce/soreduce.cpp
new file mode 100644
index 00000000000..4ac9e99aa16
--- /dev/null
+++ b/apps/soreduce/soreduce.cpp
@@ -0,0 +1,51 @@
+// $Id$
+
+// File: soreduce.cpp
+
+// Author: Phil Mesnier
+
+// theory of operation:
+// 1. Build a complete set of applications
+// 2. apply "nm" to each of the .o files that make up the libraries to subset
+// filter the results into two files for each, one with exported names, the
+// other with imported names.
+// 3. apply "nm" to all of the elements which use ace & tao. build a list of
+// imported names
+// 4. Repeat the following steps until no entries remain in the list of
+// imports
+// 4.1 Take a name from the list of imports, locate the module containing the
+// export of that name
+// 4.2 Add the exporting module to the list of required modules, add its list
+// of exports to the list of resolved exports, add its imported names to
+// the list of imports.
+// 4.4 Traverse the list of imported names to eliminate any found in the list
+// of exported names.
+// 4.5 go to step 4.1
+// 5. construct a new makefile for all required modules.
+//
+// Currently works only with GNU nm
+
+#include <ace/Log_Msg.h>
+
+#include "SO_Group.h"
+
+ACE_RCSID (src, soreduce, "$Id$")
+
+int
+main (int argc, char ** argv)
+{
+ SO_Group group;
+
+ ACE_DEBUG ((LM_DEBUG,"discovering libraries\n"));
+ for (int i = 1; i < argc; group.add_executable (argv[i++]));
+ ACE_DEBUG ((LM_DEBUG,"loading object modules\n"));
+ group.load_modules();
+ group.list_libs();
+ ACE_DEBUG ((LM_DEBUG,"Starting analysis\n"));
+ group.analize();
+ ACE_DEBUG ((LM_DEBUG,"Writing results\n"));
+ group.write_results();
+ ACE_DEBUG ((LM_DEBUG,"Done.\n"));
+ return 0;
+}
+