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