source: CMT/v1r20b1/source/cmt_triggers.cxx@ 327

Last change on this file since 327 was 11, checked in by arnault, 21 years ago

Changing eol-style property

  • Property svn:eol-style set to native
File size: 18.5 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.