source: CMT/v1r25/source/cmt_triggers.cxx

Last change on this file was 459, checked in by rybkin, 16 years ago

See C.L. 360

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