source: CMT/v1r12p20020606/src/cmt_triggers.cxx @ 1

Last change on this file since 1 was 1, checked in by arnault, 19 years ago

Import all tags

File size: 18.9 KB
Line 
1/*
2
3From Frank Behner, John Allison 13th February 1999.
4From Christian Arnault               Oct.     2000
5
6*/
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <ctype.h>
11
12#include "cmt_triggers.h"
13#include "cmt_std.h"
14#include "cmt_string.h"
15#include "cmt_system.h"
16#include "cmt_awk.h"
17#include "cmt_use.h"
18#include "cmt_symbol.h"
19#include "cmt_constituent.h"
20
21//--------------------------------------------------
22class Libmap
23{
24public:
25  typedef cmt_vector<Libmap> LibmapVector;
26
27  static Libmap& find (const cmt_string& name, const cmt_string& package);
28  static Libmap& add (const cmt_string& name, const cmt_string& package);
29  static LibmapVector& libmaps ();
30  static Libmap& find_with_trigger (const cmt_string& name);
31  static Libmap& null ();
32
33public:
34  Libmap ();
35
36  void add_trigger (const cmt_string& trigger_name);
37  void add_use (const cmt_string& use_name);
38  int operator != (const Libmap& other) const;
39  int operator == (const Libmap& other) const;
40  void set_used ();
41
42  cmt_string name;
43  cmt_string package;
44  CmtSystem::cmt_string_vector triggers;
45  bool used;
46  CmtSystem::cmt_string_vector uses;
47};
48//--------------------------------------------------
49
50//--------------------------------------------------
51Libmap& Libmap::find (const cmt_string& name, const cmt_string& package)
52{
53  LibmapVector& table = libmaps ();
54
55  for (int i = 0; i < table.size (); i++)
56    {
57      Libmap& libmap = table[i];
58
59#ifdef USE_PACKAGE_SCOPE
60      if ((name == libmap.name) &&
61          (package == libmap.package)) return (libmap);
62#else
63      if (name == libmap.name) return (libmap);
64#endif
65    }
66
67  return (null ());
68}
69
70Libmap& Libmap::add (const cmt_string& name, const cmt_string& package)
71{
72  {
73    Libmap& libmap = find (name, package);
74
75    if (libmap != null ()) return (libmap);
76  }
77
78  LibmapVector& table = libmaps ();
79
80  Libmap& libmap = table.add ();
81
82  libmap.name = name;
83  libmap.package = package;
84
85  return (libmap);
86}
87
88Libmap::LibmapVector& Libmap::libmaps ()
89{
90  static cmt_vector<Libmap> table;
91
92  return (table);
93}
94
95Libmap::Libmap () : used (false)
96{
97}
98
99void Libmap::add_trigger (const cmt_string& trigger_name)
100{
101  cmt_string& trigger = triggers.add ();
102
103  trigger = trigger_name;
104}
105
106void Libmap::add_use (const cmt_string& use_name)
107{
108  cmt_string& use = uses.add ();
109
110  use = use_name;
111}
112
113Libmap& Libmap::find_with_trigger (const cmt_string& name)
114{
115  LibmapVector& table = libmaps ();
116
117  for (int i = 0; i < table.size (); i++)
118    {
119      Libmap& libmap = table[i];
120
121      for (int j = 0; j < libmap.triggers.size (); j++)
122        {
123          const cmt_string& trigger = libmap.triggers[j];
124
125          if (name == trigger) return (libmap);
126        }
127    }
128
129  return (null ());
130}
131
132Libmap& Libmap::null ()
133{
134  static Libmap null_libmap;
135
136  return (null_libmap);
137}
138
139int Libmap::operator != (const Libmap& other) const
140{
141  return (this != &other);
142}
143
144int Libmap::operator == (const Libmap& other) const
145{
146  return (this == &other);
147}
148
149void Libmap::set_used ()
150{
151  if (used) return;
152
153  used = true;
154
155  cmt_string package_name;
156  cmt_string use_name;
157
158  for (int i = 0; i < uses.size (); i++)
159    {
160      const cmt_string& use = uses[i];
161
162      int pos = use.find ("::");
163
164      if (pos == cmt_string::npos)
165        {
166          package_name = "";
167          use_name = use;
168        }
169      else
170        {
171          use.substr (0, pos, package_name);
172          use.substr (pos + 2, use_name);
173
174          Libmap& libmap = find (use_name, package_name);
175          if (libmap != null ())
176            {
177              libmap.set_used ();
178            }
179        }
180    }
181}
182//--------------------------------------------------
183
184//--------------------------------------------------
185//
186//  This class analyzes a trigger description file (ie a file
187// named <constituent>.triggers and located in the cmt directory of
188// a package).
189//
190//  The file is expected to include lines of the form:
191//
192//    <constituent>_implied_libs=<lib> <lib> ...
193//    <constituent>_triggers=<trigger> <trigger> ...
194//
195//  with <lib> having the form:
196//
197//    <package>::<constituent>
198//     eg: Cm::Cm
199//
200//    or more simply
201//
202//    <constituent>
203//
204//  and <trigger> being an include file path (in the same form as
205//  the one used in the dependency files)
206//
207//     eg: $(CMROOT)/src/Cm.h
208//         $(AGDDROOT)/AGDD/AGDD.h
209//
210//
211//    When reading one trigger description file, one Libmap object is
212// created, and its list of uses and triggers are filled in.
213//
214//--------------------------------------------------
215class TriggerAnalyzer : public FAwk
216{
217public:
218  TriggerAnalyzer (const cmt_string& package_name);
219  void begin ();
220  void filter (const cmt_string& line);
221  void end ();
222
223private:
224  cmt_string package;
225};
226//--------------------------------------------------
227
228//--------------------------------------------------
229TriggerAnalyzer::TriggerAnalyzer (const cmt_string& package_name) :
230  package (package_name)
231{
232}
233
234void TriggerAnalyzer::begin ()
235{
236}
237
238void TriggerAnalyzer::filter (const cmt_string& line)
239{
240  int pos = line.find ("=");
241  if (pos == 0)
242    {
243      if (!Cmt::get_quiet ())
244        {
245          cerr << "Syntax error in trigger file : empty name" << endl;
246        }
247      exit (0);
248    }
249  if (pos == cmt_string::npos)
250    {
251      if (!Cmt::get_quiet ())
252        {
253          cerr << "Syntax error in trigger file : no = sign" << endl;
254        }
255      exit (0);
256    }
257
258  cmt_string name;
259  cmt_string text;
260  CmtSystem::cmt_string_vector words;
261
262  line.substr (0, pos, name);
263  line.substr (pos + 1, text);
264  CmtSystem::split (text, " ", words);
265
266  if (name.find ("_triggers") != cmt_string::npos)
267    {
268      name.replace ("_triggers", "");
269
270      Libmap& libmap = Libmap::add (name, package);
271
272      for (int i = 0; i < words.size (); i++)
273        {
274          const cmt_string& w = words[i];
275          libmap.add_trigger (w);
276        }
277    }
278  else if (name.find ("_implied_libraries") != cmt_string::npos)
279    {
280      name.replace ("_implied_libraries", "");
281
282      Libmap& libmap = Libmap::add (name, package);
283
284      for (int i = 0; i < words.size (); i++)
285        {
286          const cmt_string& w = words[i];
287          libmap.add_use (w);
288        }
289    }
290  else
291    {
292      if (!Cmt::get_quiet ())
293        {
294          cerr << "Syntax error in trigger file : bad keyword (" << 
295              name << ")" << endl;
296        }
297      exit (0);
298    }
299}
300
301void TriggerAnalyzer::end ()
302{
303}
304//--------------------------------------------------
305
306//--------------------------------------------------
307//
308//  This filter scans the CMT dependency file of a constituent.
309//
310//  The file should contains a set of entries, each composed of one line:
311//
312//      <module-name>_dependencies=<dependency> <dependency> ...
313//
314//  (Each such line actually defines one make macro used to trigger the
315//   rebuild of the corresponding module)
316//
317//  Dependencies may typically be:
318//     o the module source itself
319//     o a local dependency (ie. one which is preficed by one of the
320//              include dirs)
321//     o an external dependency (all other cases)
322//
323//  Local dependencies will generate triggers for this constituent (filling
324//  up the "triggers" unique-vector)
325//
326//  External dependencies will trigger the use of one Libmap object (thus
327//  filling up the "uses" unique-vector)
328//
329//  At the end of the scan, the results are printed to standard output
330//  with a format of a trigger description file.
331//
332//    For libraries, only the first level list is output (ie. only Libmap
333//  object directly triggered by dependencies of that constituent are
334//  listed)
335//
336//    For applications, indirect dependencies are considered and resolved
337//  recursively.
338//
339//--------------------------------------------------
340class DependencyAnalyzer : public FAwk
341{
342public:
343  DependencyAnalyzer (const cmt_string& package_name, 
344                      Constituent& constituent_ref);
345  void begin ();
346  void filter (const cmt_string& line);
347  virtual void end ();
348
349protected:
350
351  void add_trigger (const cmt_string& name);
352  void add_use (Libmap& libmap);
353
354  CmtSystem::cmt_string_vector include_dirs;
355  cmt_vector<Libmap*> uses;
356  CmtSystem::cmt_string_vector triggers;
357  Constituent& constituent;
358  cmt_string package;
359  cmt_string package_upper;
360};
361
362class LibraryAnalyzer : public DependencyAnalyzer
363{
364public:
365  LibraryAnalyzer (const cmt_string& package_name, 
366                   Constituent& constituent_ref);
367  void end ();
368};
369
370class ApplicationAnalyzer : public DependencyAnalyzer
371{
372public:
373  ApplicationAnalyzer (const cmt_string& package_name, 
374                       Constituent& constituent_ref);
375  void end ();
376};
377//--------------------------------------------------
378
379//--------------------------------------------------
380DependencyAnalyzer::DependencyAnalyzer (const cmt_string& package_name, 
381                                        Constituent& constituent_ref) :
382        package (package_name),
383        constituent (constituent_ref)
384{
385  cmt_string dirs;
386
387  int pos;
388  char c;
389
390  package_upper = package;
391
392  for (pos = 0; pos < package_upper.size (); pos++)
393    {
394      c = package_upper[pos];
395      package_upper[pos] = toupper (c);
396    }
397
398  CmtSystem::execute ("cmt show include_dirs", dirs);
399  dirs.replace_all ("\n", "");
400  CmtSystem::split (dirs, " ", include_dirs);
401}
402
403void DependencyAnalyzer::begin ()
404{
405}
406
407void DependencyAnalyzer::filter (const cmt_string& line)
408{
409    /* Clip target out of dependency file... */
410  int pos = line.find ("=");
411  if ((pos == 0) || (pos == cmt_string::npos))
412    {
413      if (!Cmt::get_quiet ())
414        {
415          cerr << "  ERROR: Syntax in dependency file: " << line << endl;
416          cerr << "  Missing = or target name." << endl;
417        }
418      exit (1);
419    }
420
421  cmt_string module;
422
423  line.substr (0, pos, module);
424  module.trim ();
425  module.replace ("_dependencies", "");
426
427  if (module == "cmt_path_make") return;
428
429  int underscore = module.find_last_of ("_");
430
431  if (underscore != cmt_string::npos)
432    {
433      module[underscore] = '.';
434    }
435
436  static cmt_string dependencies;
437
438  line.substr (pos + 1, dependencies);
439
440  if (dependencies == "") 
441    {
442      cerr << "  WARNING: It seems there is nothing after \'=\' "
443          "in dependency file " << m_file_name << endl;
444      return;
445    }
446
447  CmtSystem::cmt_string_vector deps;
448
449  CmtSystem::split (dependencies, " ", deps);
450
451  for (int i = 0; i < deps.size (); i++)
452    {
453      const cmt_string& dep = deps[i];
454
455        //
456        // dep may either be:
457        //  o the module itself
458        //  o a file in one of include_dirs
459        //  o something else
460        //
461
462      if (dep.find (module) != cmt_string::npos)
463        {
464          // This is the module itself.
465        }
466      else
467        {
468          bool found = false;
469
470          for (int j = 0; j < include_dirs.size (); j++)
471            {
472              const cmt_string& dir = include_dirs[j];
473
474              if (dep.find (dir) == 0)
475                {
476                  // This is a local dependency.
477
478                  cmt_string name = dep;
479
480                  if (dir == "$(src)")
481                    {
482                      cmt_string new_dir;
483
484                      new_dir = "$(";
485                      new_dir += package_upper;
486                      new_dir += "ROOT)/src/";
487
488                      name.replace (dir, new_dir);
489                    }
490
491                  if (CmtSystem::file_separator () == '\\')
492                    {
493                      name.replace_all (CmtSystem::file_separator (), "/");
494                    }
495
496                  Libmap& libmap = Libmap::find_with_trigger (name);
497
498                  if (libmap != Libmap::null ())
499                    {
500                      add_use (libmap);
501                    }
502                  else
503                    {
504                      add_trigger (name);
505                    }
506
507                  found = true;
508                  break;
509                }
510            }
511
512          if (!found)
513            {
514              cmt_string name = dep;
515
516              if (CmtSystem::file_separator () == '\\')
517                {
518                  name.replace_all (CmtSystem::file_separator (), "/");
519                }
520
521              // This is an external dependency.
522
523              Libmap& libmap = Libmap::find_with_trigger (name);
524
525              if (libmap != Libmap::null ())
526                {
527                  add_use (libmap);
528                }
529            }
530        }
531    }
532}
533
534void DependencyAnalyzer::end ()
535{
536}
537
538void DependencyAnalyzer::add_trigger (const cmt_string& name)
539{
540  for (int i = 0; i < triggers.size (); i++)
541    {
542      const cmt_string& trigger = triggers[i];
543
544      if (trigger == name) return;
545    }
546
547  cmt_string& new_trigger = triggers.add ();
548
549  new_trigger = name;
550}
551
552void DependencyAnalyzer::add_use (Libmap& libmap)
553{
554  for (int i = 0; i < uses.size (); i++)
555    {
556      const Libmap& ref = *(uses[i]);
557
558      if (ref == libmap) return;
559    }
560
561  uses.push_back (&libmap);
562}
563
564LibraryAnalyzer::LibraryAnalyzer (const cmt_string& package_name, 
565                                  Constituent& constituent_ref) :
566    DependencyAnalyzer (package_name, constituent_ref)
567{
568}
569
570void LibraryAnalyzer::end ()
571{
572  cmt_string macro_name;
573  cmt_string output;
574
575  int i;
576
577  if (uses.size () > 0)
578    {
579      for (i = 0; i < uses.size (); i++)
580        {
581          Libmap& libmap = *(uses[i]);
582
583          libmap.set_used ();
584        }
585
586      Libmap::LibmapVector& table = Libmap::libmaps ();
587
588      macro_name = constituent.name;
589      macro_name += "_implied_libraries";
590
591      output  = "macro_prepend ";
592      output += macro_name;
593      output += " \"";
594      for (i = 0; i < table.size (); i++)
595        {
596          Libmap& libmap = table[i];
597         
598          if (libmap.used)
599            {
600#ifdef USE_PACKAGE_SCOPE
601              output += libmap.package;
602              output += "::";
603#endif
604              output += libmap.name;
605              output += " ";
606            }
607        }
608      output += "\"";
609
610      Cmt::parse_requirements_text (output, "", 0);
611
612      Symbol* macro = Symbol::find (macro_name);
613      output = macro_name;
614      output += "=";
615      output += macro->build_macro_value ();
616
617      cout << output << endl;
618    }
619
620  if (triggers.size () > 0)
621    {
622      macro_name = constituent.name;
623      macro_name += "_triggers";
624
625      output  = "macro_prepend ";
626      output += macro_name;
627      output += " \"";
628      for (i = 0; i < triggers.size (); i++)
629        {
630          const cmt_string& trigger = triggers[i];
631         
632          output += trigger;
633          output += " ";
634        }
635      output += "\"";
636
637      Cmt::parse_requirements_text (output, "", 0);
638
639      Symbol* macro = Symbol::find (macro_name);
640      output = macro_name;
641      output += "=";
642      output += macro->build_macro_value ();
643
644      cout << output << endl;
645    }
646}
647
648ApplicationAnalyzer::ApplicationAnalyzer (const cmt_string& package_name, 
649                                          Constituent& constituent_ref) :
650    DependencyAnalyzer (package_name, constituent_ref)
651{
652}
653
654void ApplicationAnalyzer::end ()
655{
656  cmt_string macro_name;
657  cmt_string output;
658
659  int i;
660
661  if (uses.size () > 0)
662    {
663      for (i = 0; i < uses.size (); i++)
664        {
665          Libmap& libmap = *(uses[i]);
666
667          libmap.set_used ();
668        }
669
670      Libmap::LibmapVector& table = Libmap::libmaps ();
671
672      macro_name = constituent.name;
673      macro_name += "linkopts";
674
675      output  = "macro_prepend ";
676      output += macro_name;
677      output += " \"";
678      for (i = 0; i < table.size (); i++)
679        {
680          Libmap& libmap = table[i];
681         
682          if (libmap.used)
683            {
684              output += "$(implied_library_prefix)";
685              output += libmap.name;
686              output += "$(implied_library_suffix) ";
687            }
688        }
689      output += "\"";
690
691      Cmt::parse_requirements_text (output, "", 0);
692
693      Symbol* macro = Symbol::find (macro_name);
694      output = macro_name;
695      output += "=";
696      output += macro->build_macro_value ();
697
698      cout << output << endl;
699    }
700}
701//--------------------------------------------------
702
703//--------------------------------------------------
704//
705//  The UseAnalyzer is called first to reach all used packages.
706// For each package found, it retreives the *.triggers files
707// which contain the trigger descriptions for every constituent
708// of the package.
709//
710//  For each trigger description file found, a TriggerAnalyzer is run
711// which in turn fills in the database of Libmap objects.
712//
713//--------------------------------------------------
714class UseAnalyzer
715{
716public:
717  void run (const cmt_string& constituent);
718  void run (const cmt_string& location, 
719            const cmt_string& package,
720            const cmt_string& filter_out = "");
721};
722//--------------------------------------------------
723
724//--------------------------------------------------
725void UseAnalyzer::run (const cmt_string& constituent)
726{
727  Use* use = &(Use::current ());
728
729  run ("./", use->package, constituent);
730
731  Use::UsePtrVector& uses = Use::uses ();
732  for (int i = 0; i < uses.size (); i++)
733    {
734      use = uses[i];
735
736      cmt_string s;
737                                 
738      s = use->real_path;
739      s += CmtSystem::file_separator ();
740      s += use->package;
741      s += CmtSystem::file_separator ();
742      s += use->version;
743      s += CmtSystem::file_separator ();
744                                 
745      if (use->style == mgr_style) s += "mgr";
746      else s += "cmt";
747
748      s += CmtSystem::file_separator ();
749
750      run (s, use->package);
751    }
752}
753
754void UseAnalyzer::run (const cmt_string& location, 
755                       const cmt_string& package,
756                       const cmt_string& filter_out)
757{
758  static cmt_regexp expression ("[.]triggers$");
759
760  TriggerAnalyzer analyzer (package);
761
762  CmtSystem::cmt_string_vector files;
763
764  CmtSystem::scan_dir (location, expression, files);
765
766  cmt_string name;
767
768  for (int i = 0; i < files.size (); i++)
769    {
770      const cmt_string& file = files[i];
771
772      if (filter_out != "")
773        {
774          CmtSystem::basename (file, ".triggers", name);
775          if (name == filter_out) continue;
776        }
777
778      analyzer.run (file);
779    }
780}
781//--------------------------------------------------
782
783
784//--------------------------------------------------
785void TriggerGenerator::run (const cmt_string& constituent_name)
786{
787  Constituent* constituent = Constituent::find (constituent_name);
788
789  Use* use = &(Use::current ());
790  cmt_string package = use->package;
791
792    // UseAnalyzer use_analyzer (package);
793    // use_analyzer.run ("cmt show uses -quiet");
794
795  UseAnalyzer use_analyzer;
796  use_analyzer.run (constituent_name);
797
798  cmt_string file_name;
799
800  file_name = "./";
801  file_name += constituent_name;
802  file_name += "_dependencies.";
803#ifdef WIN32
804  file_name += "nmake";
805#else
806  file_name += "make";
807#endif
808
809  DependencyAnalyzer* analyzer = 0;
810
811  if (constituent->type == Library)
812    {
813      analyzer = new LibraryAnalyzer (package, *constituent);
814    }
815  else if (constituent->type == Application)
816    {
817      analyzer = new ApplicationAnalyzer (package, *constituent);
818    }
819  else
820    {
821      return;
822    }
823
824  if (analyzer->run (file_name) == Awk::failed)
825    {
826      cerr << "  File " << file_name << " not found" << endl;
827    }
828
829  delete analyzer;
830}
831//--------------------------------------------------
Note: See TracBrowser for help on using the repository browser.