Main?Page | Class?Hierarchy | Class?List | File?List | Class?Members | File?Members

cmt_triggers.cxx

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

Generated on Mon May 2 10:25:06 2005 for CMT by 1.3.5