Main Page   Class Hierarchy   Compound List   File List   Compound Members   File Members  

cmt_triggers.cxx

Go to the documentation of this file.
00001 /*
00002 
00003 From Frank Behner, John Allison 13th February 1999.
00004 From Christian Arnault               Oct.     2000
00005 
00006 */
00007 
00008 #include <stdio.h>
00009 #include <stdlib.h>
00010 #include <ctype.h>
00011 
00012 #include "cmt_triggers.h"
00013 #include "cmt_std.h"
00014 #include "cmt_string.h"
00015 #include "cmt_system.h"
00016 #include "cmt_awk.h"
00017 #include "cmt_use.h"
00018 #include "cmt_symbol.h"
00019 #include "cmt_constituent.h"
00020 
00021 //--------------------------------------------------
00022 class Libmap
00023 {
00024 public:
00025   typedef cmt_vector<Libmap> LibmapVector;
00026 
00027   static Libmap& find (const cmt_string& name, const cmt_string& package);
00028   static Libmap& add (const cmt_string& name, const cmt_string& package);
00029   static LibmapVector& libmaps ();
00030   static Libmap& find_with_trigger (const cmt_string& name);
00031   static Libmap& null ();
00032 
00033 public:
00034   Libmap ();
00035 
00036   void add_trigger (const cmt_string& trigger_name);
00037   void add_use (const cmt_string& use_name);
00038   int operator != (const Libmap& other) const;
00039   int operator == (const Libmap& other) const;
00040   void set_used ();
00041 
00042   cmt_string name;
00043   cmt_string package;
00044   CmtSystem::cmt_string_vector triggers;
00045   bool used;
00046   CmtSystem::cmt_string_vector uses;
00047 };
00048 //--------------------------------------------------
00049 
00050 //--------------------------------------------------
00051 Libmap& Libmap::find (const cmt_string& name, const cmt_string& package)
00052 {
00053   LibmapVector& table = libmaps ();
00054 
00055   for (int i = 0; i < table.size (); i++)
00056     {
00057       Libmap& libmap = table[i];
00058 
00059 #ifdef USE_PACKAGE_SCOPE
00060       if ((name == libmap.name) &&
00061           (package == libmap.package)) return (libmap);
00062 #else
00063       if (name == libmap.name) return (libmap);
00064 #endif
00065     }
00066 
00067   return (null ());
00068 }
00069 
00070 Libmap& Libmap::add (const cmt_string& name, const cmt_string& package)
00071 {
00072   {
00073     Libmap& libmap = find (name, package);
00074 
00075     if (libmap != null ()) return (libmap);
00076   }
00077 
00078   LibmapVector& table = libmaps ();
00079 
00080   Libmap& libmap = table.add ();
00081 
00082   libmap.name = name;
00083   libmap.package = package;
00084 
00085   return (libmap);
00086 }
00087 
00088 Libmap::LibmapVector& Libmap::libmaps ()
00089 {
00090   static cmt_vector<Libmap> table;
00091 
00092   return (table);
00093 }
00094 
00095 Libmap::Libmap () : used (false)
00096 {
00097 }
00098 
00099 void Libmap::add_trigger (const cmt_string& trigger_name)
00100 {
00101   cmt_string& trigger = triggers.add ();
00102 
00103   trigger = trigger_name;
00104 }
00105 
00106 void Libmap::add_use (const cmt_string& use_name)
00107 {
00108   cmt_string& use = uses.add ();
00109 
00110   use = use_name;
00111 }
00112 
00113 Libmap& Libmap::find_with_trigger (const cmt_string& name)
00114 {
00115   LibmapVector& table = libmaps ();
00116 
00117   for (int i = 0; i < table.size (); i++)
00118     {
00119       Libmap& libmap = table[i];
00120 
00121       for (int j = 0; j < libmap.triggers.size (); j++)
00122         {
00123           const cmt_string& trigger = libmap.triggers[j];
00124 
00125           if (name == trigger) return (libmap);
00126         }
00127     }
00128 
00129   return (null ());
00130 }
00131 
00132 Libmap& Libmap::null ()
00133 {
00134   static Libmap null_libmap;
00135 
00136   return (null_libmap);
00137 }
00138 
00139 int Libmap::operator != (const Libmap& other) const
00140 {
00141   return (this != &other);
00142 }
00143 
00144 int Libmap::operator == (const Libmap& other) const
00145 {
00146   return (this == &other);
00147 }
00148 
00149 void Libmap::set_used ()
00150 {
00151   if (used) return;
00152 
00153   used = true;
00154 
00155   cmt_string package_name;
00156   cmt_string use_name;
00157 
00158   for (int i = 0; i < uses.size (); i++)
00159     {
00160       const cmt_string& use = uses[i];
00161 
00162       int pos = use.find ("::");
00163 
00164       if (pos == cmt_string::npos)
00165         {
00166           package_name = "";
00167           use_name = use;
00168         }
00169       else
00170         {
00171           use.substr (0, pos, package_name);
00172           use.substr (pos + 2, use_name);
00173 
00174           Libmap& libmap = find (use_name, package_name);
00175           if (libmap != null ())
00176             {
00177               libmap.set_used ();
00178             }
00179         }
00180     }
00181 }
00182 //--------------------------------------------------
00183 
00184 //--------------------------------------------------
00185 //
00186 //  This class analyzes a trigger description file (ie a file
00187 // named <constituent>.triggers and located in the cmt directory of
00188 // a package).
00189 //
00190 //  The file is expected to include lines of the form:
00191 //
00192 //    <constituent>_implied_libs=<lib> <lib> ...
00193 //    <constituent>_triggers=<trigger> <trigger> ...
00194 //
00195 //  with <lib> having the form:
00196 //
00197 //    <package>::<constituent>
00198 //     eg: Cm::Cm
00199 //
00200 //    or more simply
00201 //
00202 //    <constituent>
00203 //
00204 //  and <trigger> being an include file path (in the same form as
00205 //  the one used in the dependency files)
00206 //
00207 //     eg: $(CMROOT)/src/Cm.h
00208 //         $(AGDDROOT)/AGDD/AGDD.h
00209 // 
00210 //
00211 //    When reading one trigger description file, one Libmap object is 
00212 // created, and its list of uses and triggers are filled in.
00213 //
00214 //--------------------------------------------------
00215 class TriggerAnalyzer : public FAwk
00216 {
00217 public:
00218   TriggerAnalyzer (const cmt_string& package_name);
00219   void begin ();
00220   void filter (const cmt_string& line);
00221   void end ();
00222 
00223 private:
00224   cmt_string package;
00225 };
00226 //--------------------------------------------------
00227 
00228 //--------------------------------------------------
00229 TriggerAnalyzer::TriggerAnalyzer (const cmt_string& package_name) :
00230   package (package_name)
00231 {
00232 }
00233 
00234 void TriggerAnalyzer::begin ()
00235 {
00236 }
00237 
00238 void TriggerAnalyzer::filter (const cmt_string& line)
00239 {
00240   int pos = line.find ("=");
00241   if (pos == 0)
00242     {
00243       if (!Cmt::get_quiet ())
00244         {
00245           cerr << "Syntax error in trigger file : empty name" << endl;
00246         }
00247       exit (0);
00248     }
00249   if (pos == cmt_string::npos)
00250     {
00251       if (!Cmt::get_quiet ())
00252         {
00253           cerr << "Syntax error in trigger file : no = sign" << endl;
00254         }
00255       exit (0);
00256     }
00257 
00258   cmt_string name;
00259   cmt_string text;
00260   CmtSystem::cmt_string_vector words;
00261 
00262   line.substr (0, pos, name);
00263   line.substr (pos + 1, text);
00264   CmtSystem::split (text, " ", words);
00265 
00266   if (name.find ("_triggers") != cmt_string::npos)
00267     {
00268       name.replace ("_triggers", "");
00269 
00270       Libmap& libmap = Libmap::add (name, package);
00271 
00272       for (int i = 0; i < words.size (); i++)
00273         {
00274           const cmt_string& w = words[i];
00275           libmap.add_trigger (w);
00276         }
00277     }
00278   else if (name.find ("_implied_libraries") != cmt_string::npos)
00279     {
00280       name.replace ("_implied_libraries", "");
00281 
00282       Libmap& libmap = Libmap::add (name, package);
00283 
00284       for (int i = 0; i < words.size (); i++)
00285         {
00286           const cmt_string& w = words[i];
00287           libmap.add_use (w);
00288         }
00289     }
00290   else
00291     {
00292       if (!Cmt::get_quiet ())
00293         {
00294           cerr << "Syntax error in trigger file : bad keyword (" << 
00295               name << ")" << endl;
00296         }
00297       exit (0);
00298     }
00299 }
00300 
00301 void TriggerAnalyzer::end ()
00302 {
00303 }
00304 //--------------------------------------------------
00305 
00306 //--------------------------------------------------
00307 //
00308 //  This filter scans the CMT dependency file of a constituent.
00309 //
00310 //  The file should contains a set of entries, each composed of one line:
00311 //
00312 //      <module-name>_dependencies=<dependency> <dependency> ...
00313 //
00314 //  (Each such line actually defines one make macro used to trigger the
00315 //   rebuild of the corresponding module)
00316 //
00317 //  Dependencies may typically be:
00318 //     o the module source itself
00319 //     o a local dependency (ie. one which is preficed by one of the
00320 //              include dirs)
00321 //     o an external dependency (all other cases)
00322 //
00323 //  Local dependencies will generate triggers for this constituent (filling
00324 //  up the "triggers" unique-vector)
00325 //
00326 //  External dependencies will trigger the use of one Libmap object (thus
00327 //  filling up the "uses" unique-vector)
00328 //
00329 //  At the end of the scan, the results are printed to standard output
00330 //  with a format of a trigger description file.
00331 //
00332 //    For libraries, only the first level list is output (ie. only Libmap
00333 //  object directly triggered by dependencies of that constituent are
00334 //  listed)
00335 //
00336 //    For applications, indirect dependencies are considered and resolved
00337 //  recursively.
00338 //
00339 //--------------------------------------------------
00340 class DependencyAnalyzer : public FAwk
00341 {
00342 public:
00343   DependencyAnalyzer (const cmt_string& package_name, 
00344                       Constituent& constituent_ref);
00345   void begin ();
00346   void filter (const cmt_string& line);
00347   virtual void end ();
00348 
00349 protected:
00350 
00351   void add_trigger (const cmt_string& name);
00352   void add_use (Libmap& libmap);
00353 
00354   CmtSystem::cmt_string_vector include_dirs;
00355   cmt_vector<Libmap*> uses;
00356   CmtSystem::cmt_string_vector triggers;
00357   Constituent& constituent;
00358   cmt_string package;
00359   cmt_string package_upper;
00360 };
00361 
00362 class LibraryAnalyzer : public DependencyAnalyzer
00363 {
00364 public:
00365   LibraryAnalyzer (const cmt_string& package_name, 
00366                    Constituent& constituent_ref);
00367   void end ();
00368 };
00369 
00370 class ApplicationAnalyzer : public DependencyAnalyzer
00371 {
00372 public:
00373   ApplicationAnalyzer (const cmt_string& package_name, 
00374                        Constituent& constituent_ref);
00375   void end ();
00376 };
00377 //--------------------------------------------------
00378 
00379 //--------------------------------------------------
00380 DependencyAnalyzer::DependencyAnalyzer (const cmt_string& package_name, 
00381                                         Constituent& constituent_ref) :
00382         package (package_name),
00383         constituent (constituent_ref)
00384 {
00385   cmt_string dirs;
00386 
00387   int pos;
00388   char c;
00389 
00390   package_upper = package;
00391 
00392   for (pos = 0; pos < package_upper.size (); pos++)
00393     {
00394       c = package_upper[pos];
00395       package_upper[pos] = toupper (c);
00396     }
00397 
00398   CmtSystem::execute ("cmt show include_dirs", dirs);
00399   dirs.replace_all ("\n", "");
00400   CmtSystem::split (dirs, " ", include_dirs);
00401 }
00402 
00403 void DependencyAnalyzer::begin ()
00404 {
00405 }
00406 
00407 void DependencyAnalyzer::filter (const cmt_string& line)
00408 {
00409     /* Clip target out of dependency file... */
00410   int pos = line.find ("=");
00411   if ((pos == 0) || (pos == cmt_string::npos))
00412     {
00413       if (!Cmt::get_quiet ())
00414         {
00415           cerr << "  ERROR: Syntax in dependency file: " << line << endl;
00416           cerr << "  Missing = or target name." << endl;
00417         }
00418       exit (1);
00419     }
00420 
00421   cmt_string module;
00422 
00423   line.substr (0, pos, module);
00424   module.trim ();
00425   module.replace ("_dependencies", "");
00426 
00427   if (module == "cmt_path_make") return;
00428 
00429   int underscore = module.find_last_of ("_");
00430 
00431   if (underscore != cmt_string::npos)
00432     {
00433       module[underscore] = '.';
00434     }
00435 
00436   static cmt_string dependencies;
00437 
00438   line.substr (pos + 1, dependencies);
00439 
00440   if (dependencies == "") 
00441     {
00442       cerr << "  WARNING: It seems there is nothing after \'=\' "
00443           "in dependency file " << m_file_name << endl;
00444       return;
00445     }
00446 
00447   CmtSystem::cmt_string_vector deps;
00448 
00449   CmtSystem::split (dependencies, " ", deps);
00450 
00451   for (int i = 0; i < deps.size (); i++)
00452     {
00453       const cmt_string& dep = deps[i];
00454 
00455         //
00456         // dep may either be:
00457         //  o the module itself
00458         //  o a file in one of include_dirs
00459         //  o something else
00460         //
00461 
00462       if (dep.find (module) != cmt_string::npos)
00463         {
00464           // This is the module itself.
00465         }
00466       else
00467         {
00468           bool found = false;
00469 
00470           for (int j = 0; j < include_dirs.size (); j++)
00471             {
00472               const cmt_string& dir = include_dirs[j];
00473 
00474               if (dep.find (dir) == 0)
00475                 {
00476                   // This is a local dependency.
00477 
00478                   cmt_string name = dep;
00479 
00480                   if (dir == "$(src)")
00481                     {
00482                       cmt_string new_dir;
00483 
00484                       new_dir = "$(";
00485                       new_dir += package_upper;
00486                       new_dir += "ROOT)/src/";
00487 
00488                       name.replace (dir, new_dir);
00489                     }
00490 
00491                   if (CmtSystem::file_separator () == '\\')
00492                     {
00493                       name.replace_all (CmtSystem::file_separator (), "/");
00494                     }
00495 
00496                   Libmap& libmap = Libmap::find_with_trigger (name);
00497 
00498                   if (libmap != Libmap::null ())
00499                     {
00500                       add_use (libmap);
00501                     }
00502                   else
00503                     {
00504                       add_trigger (name);
00505                     }
00506 
00507                   found = true;
00508                   break;
00509                 }
00510             }
00511 
00512           if (!found)
00513             {
00514               cmt_string name = dep;
00515 
00516               if (CmtSystem::file_separator () == '\\')
00517                 {
00518                   name.replace_all (CmtSystem::file_separator (), "/");
00519                 }
00520 
00521               // This is an external dependency.
00522 
00523               Libmap& libmap = Libmap::find_with_trigger (name);
00524 
00525               if (libmap != Libmap::null ())
00526                 {
00527                   add_use (libmap);
00528                 }
00529             }
00530         }
00531     }
00532 }
00533 
00534 void DependencyAnalyzer::end ()
00535 {
00536 }
00537 
00538 void DependencyAnalyzer::add_trigger (const cmt_string& name)
00539 {
00540   for (int i = 0; i < triggers.size (); i++)
00541     {
00542       const cmt_string& trigger = triggers[i];
00543 
00544       if (trigger == name) return;
00545     }
00546 
00547   cmt_string& new_trigger = triggers.add ();
00548 
00549   new_trigger = name;
00550 }
00551 
00552 void DependencyAnalyzer::add_use (Libmap& libmap)
00553 {
00554   for (int i = 0; i < uses.size (); i++)
00555     {
00556       const Libmap& ref = *(uses[i]);
00557 
00558       if (ref == libmap) return;
00559     }
00560 
00561   uses.push_back (&libmap);
00562 }
00563 
00564 LibraryAnalyzer::LibraryAnalyzer (const cmt_string& package_name, 
00565                                   Constituent& constituent_ref) :
00566     DependencyAnalyzer (package_name, constituent_ref)
00567 {
00568 }
00569 
00570 void LibraryAnalyzer::end ()
00571 {
00572   cmt_string macro_name;
00573   cmt_string output;
00574 
00575   int i;
00576 
00577   if (uses.size () > 0)
00578     {
00579       for (i = 0; i < uses.size (); i++)
00580         {
00581           Libmap& libmap = *(uses[i]);
00582 
00583           libmap.set_used ();
00584         }
00585 
00586       Libmap::LibmapVector& table = Libmap::libmaps ();
00587 
00588       macro_name = constituent.name;
00589       macro_name += "_implied_libraries";
00590 
00591       output  = "macro_prepend ";
00592       output += macro_name;
00593       output += " \"";
00594       for (i = 0; i < table.size (); i++)
00595         {
00596           Libmap& libmap = table[i];
00597           
00598           if (libmap.used)
00599             {
00600 #ifdef USE_PACKAGE_SCOPE
00601               output += libmap.package;
00602               output += "::";
00603 #endif
00604               output += libmap.name;
00605               output += " ";
00606             }
00607         }
00608       output += "\"";
00609 
00610       Cmt::parse_requirements_text (output, "", 0);
00611 
00612       Symbol* macro = Symbol::find (macro_name);
00613       output = macro_name;
00614       output += "=";
00615       output += macro->build_macro_value ();
00616 
00617       cout << output << endl;
00618     }
00619 
00620   if (triggers.size () > 0)
00621     {
00622       macro_name = constituent.name;
00623       macro_name += "_triggers";
00624 
00625       output  = "macro_prepend ";
00626       output += macro_name;
00627       output += " \"";
00628       for (i = 0; i < triggers.size (); i++)
00629         {
00630           const cmt_string& trigger = triggers[i];
00631           
00632           output += trigger;
00633           output += " ";
00634         }
00635       output += "\"";
00636 
00637       Cmt::parse_requirements_text (output, "", 0);
00638 
00639       Symbol* macro = Symbol::find (macro_name);
00640       output = macro_name;
00641       output += "=";
00642       output += macro->build_macro_value ();
00643 
00644       cout << output << endl;
00645     }
00646 }
00647 
00648 ApplicationAnalyzer::ApplicationAnalyzer (const cmt_string& package_name, 
00649                                           Constituent& constituent_ref) :
00650     DependencyAnalyzer (package_name, constituent_ref)
00651 {
00652 }
00653 
00654 void ApplicationAnalyzer::end ()
00655 {
00656   cmt_string macro_name;
00657   cmt_string output;
00658 
00659   int i;
00660 
00661   if (uses.size () > 0)
00662     {
00663       for (i = 0; i < uses.size (); i++)
00664         {
00665           Libmap& libmap = *(uses[i]);
00666 
00667           libmap.set_used ();
00668         }
00669 
00670       Libmap::LibmapVector& table = Libmap::libmaps ();
00671 
00672       macro_name = constituent.name;
00673       macro_name += "linkopts";
00674 
00675       output  = "macro_prepend ";
00676       output += macro_name;
00677       output += " \"";
00678       for (i = 0; i < table.size (); i++)
00679         {
00680           Libmap& libmap = table[i];
00681           
00682           if (libmap.used)
00683             {
00684               output += "$(implied_library_prefix)";
00685               output += libmap.name;
00686               output += "$(implied_library_suffix) ";
00687             }
00688         }
00689       output += "\"";
00690 
00691       Cmt::parse_requirements_text (output, "", 0);
00692 
00693       Symbol* macro = Symbol::find (macro_name);
00694       output = macro_name;
00695       output += "=";
00696       output += macro->build_macro_value ();
00697 
00698       cout << output << endl;
00699     }
00700 }
00701 //--------------------------------------------------
00702 
00703 //--------------------------------------------------
00704 //
00705 //  The UseAnalyzer is called first to reach all used packages.
00706 // For each package found, it retreives the *.triggers files
00707 // which contain the trigger descriptions for every constituent
00708 // of the package.
00709 //
00710 //  For each trigger description file found, a TriggerAnalyzer is run
00711 // which in turn fills in the database of Libmap objects.
00712 //
00713 //--------------------------------------------------
00714 class UseAnalyzer
00715 {
00716 public:
00717   void run (const cmt_string& constituent);
00718   void run (const cmt_string& location, 
00719             const cmt_string& package,
00720             const cmt_string& filter_out = "");
00721 };
00722 //--------------------------------------------------
00723 
00724 //--------------------------------------------------
00725 void UseAnalyzer::run (const cmt_string& constituent)
00726 {
00727   Use* use = &(Use::current ());
00728 
00729   run ("./", use->package, constituent);
00730 
00731   Use::UsePtrVector& uses = Use::uses ();
00732   for (int i = 0; i < uses.size (); i++)
00733     {
00734       use = uses[i];
00735 
00736       cmt_string s;
00737                                   
00738       s = use->real_path;
00739       s += CmtSystem::file_separator ();
00740       s += use->package;
00741       s += CmtSystem::file_separator ();
00742       s += use->version;
00743       s += CmtSystem::file_separator ();
00744                                   
00745       if (use->style == mgr_style) s += "mgr";
00746       else s += "cmt";
00747 
00748       s += CmtSystem::file_separator ();
00749 
00750       run (s, use->package);
00751     }
00752 }
00753 
00754 void UseAnalyzer::run (const cmt_string& location, 
00755                        const cmt_string& package,
00756                        const cmt_string& filter_out)
00757 {
00758   static cmt_regexp expression ("[.]triggers$");
00759 
00760   TriggerAnalyzer analyzer (package);
00761 
00762   CmtSystem::cmt_string_vector files;
00763 
00764   CmtSystem::scan_dir (location, expression, files);
00765 
00766   cmt_string name;
00767 
00768   for (int i = 0; i < files.size (); i++)
00769     {
00770       const cmt_string& file = files[i];
00771 
00772       if (filter_out != "")
00773         {
00774           CmtSystem::basename (file, ".triggers", name);
00775           if (name == filter_out) continue;
00776         }
00777 
00778       analyzer.run (file);
00779     }
00780 }
00781 //--------------------------------------------------
00782 
00783 
00784 //--------------------------------------------------
00785 void TriggerGenerator::run (const cmt_string& constituent_name)
00786 {
00787   Constituent* constituent = Constituent::find (constituent_name);
00788 
00789   Use* use = &(Use::current ());
00790   cmt_string package = use->package;
00791 
00792     // UseAnalyzer use_analyzer (package);
00793     // use_analyzer.run ("cmt show uses -quiet");
00794 
00795   UseAnalyzer use_analyzer;
00796   use_analyzer.run (constituent_name);
00797 
00798   cmt_string file_name;
00799 
00800   file_name = "./";
00801   file_name += constituent_name;
00802   file_name += "_dependencies.";
00803 #ifdef WIN32
00804   file_name += "nmake";
00805 #else
00806   file_name += "make";
00807 #endif
00808 
00809   DependencyAnalyzer* analyzer = 0;
00810 
00811   if (constituent->type == Library)
00812     {
00813       analyzer = new LibraryAnalyzer (package, *constituent);
00814     }
00815   else if (constituent->type == Application)
00816     {
00817       analyzer = new ApplicationAnalyzer (package, *constituent);
00818     }
00819   else
00820     {
00821       return;
00822     }
00823 
00824   if (analyzer->run (file_name) == Awk::failed)
00825     {
00826       cerr << "  File " << file_name << " not found" << endl;
00827     }
00828 
00829   delete analyzer;
00830 }
00831 //--------------------------------------------------

Generated at Thu May 16 16:27:09 2002 for CMT by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000