summaryrefslogtreecommitdiff
path: root/ACE/apps/soreduce
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/apps/soreduce')
-rw-r--r--ACE/apps/soreduce/Library.cpp347
-rw-r--r--ACE/apps/soreduce/Library.h128
-rw-r--r--ACE/apps/soreduce/Makefile.am50
-rw-r--r--ACE/apps/soreduce/Obj_Module.cpp200
-rw-r--r--ACE/apps/soreduce/Obj_Module.h70
-rw-r--r--ACE/apps/soreduce/README163
-rw-r--r--ACE/apps/soreduce/SO_Group.cpp166
-rw-r--r--ACE/apps/soreduce/SO_Group.h48
-rw-r--r--ACE/apps/soreduce/Sig_List.cpp184
-rw-r--r--ACE/apps/soreduce/Sig_List.h49
-rw-r--r--ACE/apps/soreduce/Signature.cpp45
-rw-r--r--ACE/apps/soreduce/Signature.h50
-rw-r--r--ACE/apps/soreduce/soreduce.cpp51
-rw-r--r--ACE/apps/soreduce/soreduce.mpc15
14 files changed, 1566 insertions, 0 deletions
diff --git a/ACE/apps/soreduce/Library.cpp b/ACE/apps/soreduce/Library.cpp
new file mode 100644
index 00000000000..dcf0ea81301
--- /dev/null
+++ b/ACE/apps/soreduce/Library.cpp
@@ -0,0 +1,347 @@
+// -*- C++ -*-
+// $Id$
+
+// File: Library.cpp
+
+// Author: Phil Mesnier
+
+// This file contains the implementation of the classes responsible for
+// generating specialized mpc files for individual libraries, as well as
+// outputting usage metrics for the various object modules contained in the
+// library.
+
+#include "ace/OS_NS_dirent.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_sys_stat.h"
+#include "ace/OS_NS_ctype.h"
+#include "ace/Log_Msg.h"
+
+#include "Library.h"
+
+ACE_RCSID(src, Library, "$Id$")
+
+MPC_Generator::MPC_Generator (const ACE_CString& libname)
+ : mpcfile_(),
+ libname_(libname),
+ mpcfilename_()
+{
+ mpcfilename_ = libname_ + "_subset.mpc";
+}
+
+MPC_Generator::~MPC_Generator ()
+{
+}
+
+void
+MPC_Generator::write_file (const ACE_CString& file)
+{
+ mpcfile_ << " " << file << ".cpp" << endl;
+}
+
+void
+MPC_Generator::write_prolog (const ACE_CString& path)
+{
+ ACE_CString fname (path + "/" + mpcfilename_);
+ ACE_DEBUG ((LM_DEBUG, "writing file %s\n",fname.c_str()));
+ mpcfile_.open(fname.c_str());
+ if (!mpcfile_)
+ ACE_DEBUG ((LM_DEBUG,"mpc file open failed\n"));
+
+ mpcfile_
+ << "// Generated mpc file for producing a subset of the "
+ << libname_ << " library " << endl << endl
+ << "project(" << libname_ << "_subset)";
+
+ this->write_baseprojects ();
+
+ mpcfile_
+ << " {" << endl
+ << " sharedname = " << libname_ << "_subset" << endl
+ << " pch_header = " << endl
+ << " pch_source = " << endl;
+
+ this->write_projectinfo ();
+
+ mpcfile_ << endl
+ << " Source_Files {" << endl;
+}
+
+void
+MPC_Generator::write_epilog ()
+{
+ mpcfile_ << " }" << endl
+ << "}" << endl;
+ mpcfile_.close();
+}
+
+void
+MPC_Generator::write_baseprojects()
+{
+ mpcfile_ << ": acedefaults, aceversion, core";
+}
+
+void
+MPC_Generator::write_projectinfo()
+{
+ mpcfile_ << " libout = $(ACE_ROOT)/lib" << endl
+ << " dynamicflags = ACE_BUILD_DLL ACE_OS_BUILD_DLL" << endl;
+}
+
+//-----------------------------------------------------------------------------
+MPC_ACE_Dep_Lib::MPC_ACE_Dep_Lib (const ACE_CString& libname)
+ : MPC_Generator(libname)
+{}
+
+void
+MPC_ACE_Dep_Lib::write_baseprojects()
+{
+ mpcfile_ << ": acedefaults, aceversion";
+}
+
+void
+MPC_ACE_Dep_Lib::write_projectinfo()
+{
+ mpcfile_ << " libout = $(ACE_ROOT)/lib" << endl
+ << " libs += ACE_subset" << endl
+ << " after += ACE_subset" << endl;
+}
+
+//-----------------------------------------------------------------------------
+MPC_TAO_Lib::MPC_TAO_Lib (const ACE_CString& libname)
+ : MPC_ACE_Dep_Lib(libname)
+{}
+
+void
+MPC_TAO_Lib::write_baseprojects()
+{
+ MPC_ACE_Dep_Lib::write_baseprojects ();
+ mpcfile_ << ", taoversion, core, tao_output, taodefaults";
+}
+
+void
+MPC_TAO_Lib::write_projectinfo()
+{
+ MPC_ACE_Dep_Lib::write_projectinfo();
+ mpcfile_ << " dynamicflags = TAO_BUILD_DLL" << endl;
+}
+
+//-----------------------------------------------------------------------------
+MPC_TAO_Dep_Lib::MPC_TAO_Dep_Lib (const ACE_CString& libname)
+ : MPC_TAO_Lib(libname)
+{}
+
+void
+MPC_TAO_Dep_Lib::write_baseprojects()
+{
+ MPC_TAO_Lib::write_baseprojects ();
+ mpcfile_ << ", taoidldefaults";
+}
+
+void
+MPC_TAO_Dep_Lib::write_projectinfo()
+{
+ // Try our best to generate the dynamicflags
+ ACE_CString dflags;
+ for(size_t i = 0; i < this->libname_.length (); ++i) {
+ dflags += static_cast<char>(ACE_OS::ace_toupper (this->libname_[i]));
+ }
+ dflags += "_BUILD_DLL";
+
+ MPC_ACE_Dep_Lib::write_projectinfo();
+ mpcfile_ << " dynamicflags = " << dflags.c_str () << endl
+ << " libs += TAO_subset" << endl
+ << " after += TAO_subset" << endl
+ << " includes += $(TAO_ROOT)/orbsvcs" << endl
+ << " idlflags += -I$(TAO_ROOT)/orbsvcs" << endl;
+}
+
+//-----------------------------------------------------------------------------
+
+Library::Library (const char *name)
+ : name_(name),
+ path_(),
+ num_modules_(0),
+ num_exports_(0),
+ num_extrefs_(0),
+ modules_(0),
+ exported_(0),
+ mpcfile_(0)
+{
+ if (name_ == "ACE")
+ mpcfile_ = new MPC_Generator(name_);
+ else if (name_.find ("ACE_") == 0)
+ mpcfile_ = new MPC_ACE_Dep_Lib (name_);
+ else if (name_ == "TAO")
+ mpcfile_ = new MPC_TAO_Lib (name_);
+ else
+ mpcfile_ = new MPC_TAO_Dep_Lib (name_);
+}
+
+Library::~Library ()
+{
+ delete mpcfile_;
+ int i;
+ for (i = 0; i < num_modules_; delete modules_[i++]);
+ delete [] modules_;
+}
+
+void
+Library::set_path (const char *p)
+{
+ char abspath[1000];
+ memset (abspath,0,1000);
+ ssize_t abspathlen = ACE_OS::readlink(p,abspath,999);
+ ACE_CString path (p);
+ if (abspathlen > 0) {
+ abspath[abspathlen] = 0;
+ path = abspath;
+ }
+
+ ACE_CString::size_type 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;
+}
+
+extern "C" {
+
+static int
+selector (const dirent *d)
+{
+ return ACE_OS::strstr (d->d_name, ACE_TEXT (".o")) != 0;
+}
+
+static int
+comparator (const dirent **d1, const dirent **d2)
+{
+ return ACE_OS::strcmp ((*d1)->d_name, (*d2)->d_name);
+}
+
+} /* extern "C" */
+
+void
+Library::load_modules ()
+{
+ ACE_CString subdir = path_ + "/.shobj";
+
+ struct dirent **dent;
+ num_modules_ = ACE_OS::scandir(ACE_TEXT_CHAR_TO_TCHAR (subdir.c_str()),
+ &dent,selector,comparator);
+
+ if (num_modules_ > 0) {
+ modules_ = new Obj_Module * [num_modules_];
+ for (int i = 0; i < num_modules_; i++) {
+ ACE_CString ent_name (ACE_TEXT_ALWAYS_CHAR (dent[i]->d_name));
+ modules_[i] = new Obj_Module(ent_name);
+ modules_[i]->add_source (ACE_CString(subdir + "/" + ent_name).c_str());
+ ACE_OS::free(dent[i]);
+ };
+ }
+
+ if (num_modules_ > -1)
+ ACE_OS::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(ACE_TEXT_CHAR_TO_TCHAR (rcpath.c_str())) == -1 &&
+ errno != EEXIST)
+ 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_));
+
+ mpcfile_->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 *n_sig = modules_[i]->imports().first();
+ modules_[i]->imports().hasmore();
+ n_sig = modules_[i]->imports().next())
+ countfile << n_sig->name() << endl;
+ }
+ mpcfile_->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;
+ }
+
+ mpcfile_->write_epilog();
+}
diff --git a/ACE/apps/soreduce/Library.h b/ACE/apps/soreduce/Library.h
new file mode 100644
index 00000000000..af978c61f74
--- /dev/null
+++ b/ACE/apps/soreduce/Library.h
@@ -0,0 +1,128 @@
+// -*- 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 mpc file to build the reduce footprint library.
+
+#include "Obj_Module.h"
+
+// FUZZ: disable check_for_streams_include
+#include "ace/streams.h"
+
+// The MPC generator class serves as the base class used to output the
+// custom mpc files used to build the subsetted libraries.
+// The base class will make libACE_subset.so
+
+class MPC_Generator
+{
+public:
+ MPC_Generator (const ACE_CString& libname);
+ virtual ~MPC_Generator();
+
+ void write_prolog (const ACE_CString& );
+ void write_file (const ACE_CString& );
+ void write_epilog ();
+
+protected:
+ virtual void write_baseprojects();
+ virtual void write_projectinfo();
+
+ ofstream mpcfile_;
+ ACE_CString libname_;
+ ACE_CString mpcfilename_;
+};
+
+// Generate mpc files for libraries dependant on ACE, that are not TAO.
+class MPC_ACE_Dep_Lib : public MPC_Generator
+{
+public:
+ MPC_ACE_Dep_Lib (const ACE_CString& libname);
+
+protected:
+ virtual void write_baseprojects();
+ virtual void write_projectinfo();
+};
+
+// Generates mpc files for libTAO_subset.so
+class MPC_TAO_Lib : public MPC_ACE_Dep_Lib
+{
+public:
+ MPC_TAO_Lib (const ACE_CString& libname);
+
+protected:
+ virtual void write_baseprojects();
+ virtual void write_projectinfo();
+};
+
+// Generates makefiles for libs dependant on TAO. This has a problem when
+// building libraries in the orbsvcs tree.
+class MPC_TAO_Dep_Lib : public MPC_TAO_Lib
+{
+public:
+ MPC_TAO_Dep_Lib (const ACE_CString& );
+
+protected:
+ virtual void write_baseprojects();
+ virtual void write_projectinfo();
+};
+
+//----------------------------------------------------------------------------
+
+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 an mpc file 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_;
+ MPC_Generator *mpcfile_;
+};
+
+#endif /* _LIBRARY_H_ */
diff --git a/ACE/apps/soreduce/Makefile.am b/ACE/apps/soreduce/Makefile.am
new file mode 100644
index 00000000000..4f50d294e0d
--- /dev/null
+++ b/ACE/apps/soreduce/Makefile.am
@@ -0,0 +1,50 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## /acebuilds/ACE_wrappers-repository/bin/mwc.pl -include /acebuilds/MPC/config -include /acebuilds/MPC/templates -feature_file /acebuilds/ACE_wrappers-repository/local.features -noreldefs -type automake -exclude build,Kokyu
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+
+## Makefile.soreduce.am
+
+if !BUILD_ACE_FOR_TAO
+if !BUILD_USES_WCHAR
+noinst_PROGRAMS = soreduce
+
+soreduce_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+soreduce_SOURCES = \
+ Library.cpp \
+ Obj_Module.cpp \
+ SO_Group.cpp \
+ Sig_List.cpp \
+ Signature.cpp \
+ soreduce.cpp \
+ Library.h \
+ Obj_Module.h \
+ SO_Group.h \
+ Sig_List.h \
+ Signature.h
+
+soreduce_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_USES_WCHAR
+endif !BUILD_ACE_FOR_TAO
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/apps/soreduce/Obj_Module.cpp b/ACE/apps/soreduce/Obj_Module.cpp
new file mode 100644
index 00000000000..de508c32eff
--- /dev/null
+++ b/ACE/apps/soreduce/Obj_Module.cpp
@@ -0,0 +1,200 @@
+// -*- 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/OS_NS_string.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/Process.h"
+#include "ace/Pipe.h"
+#include "ace/Message_Block.h"
+#include "ace/Log_Msg.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 char *p, int imports_only)
+{
+ ACE_Process nmproc;
+ ACE_Process_Options nm_opts;
+ ACE_CString path (p);
+
+ ACE_CString::size_type 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
+
+ int result = nm_opts.command_line ("nm -C %s",src_name.c_str());
+ // Prevent compiler warning about "unused variable" if ACE_ASSERT is
+ // an empty macro.
+ ACE_UNUSED_ARG (result);
+ ACE_ASSERT (result == 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::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 ();
+ ACE_OS::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/ACE/apps/soreduce/Obj_Module.h b/ACE/apps/soreduce/Obj_Module.h
new file mode 100644
index 00000000000..1836b75e7ec
--- /dev/null
+++ b/ACE/apps/soreduce/Obj_Module.h
@@ -0,0 +1,70 @@
+// -*- 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"
+
+ACE_BEGIN_VERSIONED_NAMESPACE_DECL
+class ACE_Message_Block;
+ACE_END_VERSIONED_NAMESPACE_DECL
+
+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 char *, 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/ACE/apps/soreduce/README b/ACE/apps/soreduce/README
new file mode 100644
index 00000000000..5e0264bdab2
--- /dev/null
+++ b/ACE/apps/soreduce/README
@@ -0,0 +1,163 @@
+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. MPC files are generated. Rather than invoking the linker directly, an mpc
+ file is generated that may be used to build the libs. With these
+ mpc files, the actual library will be named (orig)_subset.
+
+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
+ACE: 61 out of 210 modules required
+writing file /opt/wustl/ACE_wrappers/build/native/ace/ACE_subset.mpc
+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 may not generate valid mpc files.
+
+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/TAO_CosNaming_subset.mpc
+Making directory /opt/wustl/ACE_wrappers/build/native/TAO/orbsvcs/orbsvcs/usage_metrics
+TAO_Svc_Utils: 8 out of 256 modules required
+writing file /opt/wustl/ACE_wrappers/build/native/TAO/orbsvcs/orbsvcs/TAO_Svc_Utils_subset.mpc
+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/TAO_IORTable_subset.mpc
+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/TAO_PortableServer_subset.mpc
+Making directory /opt/wustl/ACE_wrappers/build/native/TAO/tao/usage_metrics
+TAO: 160 out of 191 modules required
+writing file /opt/wustl/ACE_wrappers/build/native/TAO/tao/TAO_subset.mpc
+Making directory /opt/wustl/ACE_wrappers/build/native/ace/usage_metrics
+ACE: 75 out of 210 modules required
+writing file /opt/wustl/ACE_wrappers/build/native/ace/ACE_subset.mpc
+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/ACE/apps/soreduce/SO_Group.cpp b/ACE/apps/soreduce/SO_Group.cpp
new file mode 100644
index 00000000000..f369050a1dd
--- /dev/null
+++ b/ACE/apps/soreduce/SO_Group.cpp
@@ -0,0 +1,166 @@
+// -*- C++ -*-
+// $Id$
+
+// File: SO_Group.cpp
+
+#include "ace/OS_NS_string.h"
+#include "ace/OS_NS_unistd.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_ (128),
+ 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]);
+
+ int result = opts.command_line ("ldd %s",path);
+ // Prevent compiler warning about "unused variable" if ACE_ASSERT is
+ // an empty macro.
+ ACE_UNUSED_ARG (result);
+ ACE_ASSERT (result == 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 ();
+ ACE_OS::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/ACE/apps/soreduce/SO_Group.h b/ACE/apps/soreduce/SO_Group.h
new file mode 100644
index 00000000000..09758c8c7bb
--- /dev/null
+++ b/ACE/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/ACE/apps/soreduce/Sig_List.cpp b/ACE/apps/soreduce/Sig_List.cpp
new file mode 100644
index 00000000000..2f385790aff
--- /dev/null
+++ b/ACE/apps/soreduce/Sig_List.cpp
@@ -0,0 +1,184 @@
+// $Id$
+
+// File: Sig_List.cpp
+
+// Author: Phil Mesnier
+
+#include "ace/OS_NS_string.h"
+#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/ACE/apps/soreduce/Sig_List.h b/ACE/apps/soreduce/Sig_List.h
new file mode 100644
index 00000000000..9b4b0dc115f
--- /dev/null
+++ b/ACE/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/ACE/apps/soreduce/Signature.cpp b/ACE/apps/soreduce/Signature.cpp
new file mode 100644
index 00000000000..2d4d907e92b
--- /dev/null
+++ b/ACE/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/ACE/apps/soreduce/Signature.h b/ACE/apps/soreduce/Signature.h
new file mode 100644
index 00000000000..358a756aa7a
--- /dev/null
+++ b/ACE/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/ACE/apps/soreduce/soreduce.cpp b/ACE/apps/soreduce/soreduce.cpp
new file mode 100644
index 00000000000..4ac9e99aa16
--- /dev/null
+++ b/ACE/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;
+}
+
diff --git a/ACE/apps/soreduce/soreduce.mpc b/ACE/apps/soreduce/soreduce.mpc
new file mode 100644
index 00000000000..2fe7cc27101
--- /dev/null
+++ b/ACE/apps/soreduce/soreduce.mpc
@@ -0,0 +1,15 @@
+// $Id$
+
+project(soreduce) : aceexe {
+ avoids += uses_wchar ace_for_tao
+ exename = soreduce
+ Source_Files {
+ Signature.cpp
+ Sig_List.cpp
+ Obj_Module.cpp
+ Library.cpp
+ SO_Group.cpp
+ soreduce.cpp
+ }
+}
+