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