source: CMT/v1r19/source/cmt_deps_builder.cxx @ 1

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

Import all tags

File size: 21.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#include "cmt_deps_builder.h"
8#include "cmt_system.h"
9#include "cmt_use.h"
10#include "cmt_include.h"
11#include "cmt_symbol.h"
12#include "cmt_log.h"
13
14//
15//  While parsing a C++ file, these are the possible usefull
16// states we can reach.
17//  Each state correspond to a specific state action function.
18//
19enum state_def
20{
21  at_start,                                // beginning of the file
22  in_line,                                // along a line
23  in_string,                        // inside a quoted string
24  in_char,                                // inside a quoted char
25  in_comment,                        // inside a multi-line comment
26  in_string_comment,        // inside a quoted string in a comment
27  in_char_comment,                // inside a quoted char in a comment
28  in_line_comment                // inside a single-line comment
29};
30
31//--------------------------------------------------
32static int build_deps (const cmt_string& name,
33                       const cmt_string& dir_name,
34                       int current_path_index,
35                       const CmtSystem::cmt_string_vector& include_paths,
36                       const CmtSystem::cmt_string_vector& substitutions,
37                       CmtSystem::cmt_string_vector& all_deps,
38                       CmtSystem::cmt_string_vector& deps);
39
40
41//--------------------------------------------------
42static void header_file_action (const char* header_file,
43                                const cmt_string& dir_name,
44                                int current_path_index,
45                                const CmtSystem::cmt_string_vector& include_paths,
46                                const CmtSystem::cmt_string_vector& substitutions,
47                                CmtSystem::cmt_string_vector& all_deps,
48                                CmtSystem::cmt_string_vector& deps)
49{
50  bool found = false;
51
52  for (int i = 0; i < all_deps.size (); i++)
53    {
54      if (all_deps[i] == header_file)
55        {
56          found = true;
57          break;
58        }
59    }
60 
61  if (!found)
62    {
63      all_deps.push_back (header_file);
64     
65      int path_index = build_deps (header_file,
66                                   dir_name,
67                                   current_path_index,
68                                   include_paths,
69                                   substitutions,
70                                   all_deps,
71                                   deps);
72     
73      if (path_index >= 0)
74        {
75          cmt_string full_name;
76         
77          if (path_index == 1)
78            {
79              full_name = dir_name;
80              full_name += CmtSystem::file_separator ();
81             
82              if (current_path_index >= 2)
83                {
84                  full_name.replace (include_paths[current_path_index - 2],
85                                     substitutions[current_path_index - 2]);
86                }
87            }
88          else if (path_index > 1)
89            {
90              full_name  = substitutions[path_index - 2];
91              full_name += CmtSystem::file_separator ();
92            }
93         
94          full_name += header_file;
95         
96          deps.push_back (full_name);
97        }
98    }
99}
100
101
102//--------------------------------------------------
103static char* at_start_action (char* ptr,
104                              state_def& state,
105                              const cmt_string& dir_name,
106                              int current_path_index,
107                              const CmtSystem::cmt_string_vector& include_paths,
108                              const CmtSystem::cmt_string_vector& substitutions,
109                              CmtSystem::cmt_string_vector& all_deps,
110                              CmtSystem::cmt_string_vector& deps)
111{
112  char term = 0;
113
114  if (*ptr == '#')
115    {
116      ptr++;
117      while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
118      if (!strncmp (ptr, "include", 7))
119        {
120          ptr += 7;
121
122          while (*ptr == ' ') ptr++;
123          if (*ptr == '<')
124            {
125              term = '>';
126              ptr++;
127            }
128          else if (*ptr == '"')
129            {
130              term = '"';
131              ptr++;
132            }
133          else
134            {
135              state = in_line;
136              ptr += strlen (ptr);
137              return (ptr);
138            }
139        }
140      else
141        {
142          state = in_line;
143          ptr += strlen (ptr);
144          return (ptr);
145        }
146    }
147  else if (!strncmp (ptr, "      include", 13))
148    {
149      ptr += 13;
150
151      while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
152      if (*ptr == '\'')
153        {
154          term = '\'';
155          ptr++;
156        }
157      else
158        {
159          state = in_line;
160          return (ptr);
161        }
162    }
163  else if (!strncmp (ptr, "\tinclude", 8))
164    {
165      ptr += 8;
166
167      while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
168      if (*ptr == '\'')
169        {
170          term = '\'';
171          ptr++;
172        }
173      else
174        {
175          state = in_line;
176          return (ptr);
177        }
178    }
179  else
180    {
181      state = in_line;
182      return (ptr);
183    }
184
185  char* end;
186
187  end = strchr (ptr, term);
188  if (end != 0)
189    {
190      *end = 0;
191    }
192 
193  const char* header_file = ptr;
194 
195  header_file_action (header_file,
196                      dir_name,
197                      current_path_index,
198                      include_paths,
199                      substitutions,
200                      all_deps,
201                      deps);
202 
203  if (end != 0)
204    {
205      *end = term;
206    }
207
208  state = in_line;
209  ptr += strlen (ptr);
210 
211  return (ptr);
212}
213
214//--------------------------------------------------
215static char* in_line_action (char* ptr, state_def& state)
216{
217  char* pattern = &ptr[strlen (ptr)];
218
219  char* pos = strchr (ptr, '"');
220  if (pos != 0)
221    {
222      if (pos < pattern)
223        {
224          state = in_string;
225          pattern = pos;
226        }
227    }
228
229  pos = strchr (ptr, '\'');
230  if (pos != 0)
231    {
232      if (pos < pattern)
233        {
234          state = in_char;
235          pattern = pos;
236        }
237    }
238
239  pos = strstr (ptr, "/*");   //*/
240  if (pos != 0)
241    {
242      if (pos < pattern)
243        {
244          state = in_comment;
245          pattern = pos + 1;
246        }
247    }
248
249  pos = strstr (ptr, "//");
250  if (pos != 0)
251    {
252      if (pos < pattern)
253        {
254          state = in_line_comment;
255          pattern = pos + 1;
256        }
257    }
258
259  if (state != in_line)
260    {
261      ptr = pattern + 1;
262    }
263  else
264    {
265      ptr += strlen (ptr);
266    }
267
268  return (ptr);
269}
270
271//--------------------------------------------------
272static char* in_string_action (char* ptr, state_def& state)
273{
274  char* pos = strchr (ptr, '"');
275  if (pos == 0)
276    {
277        // This string is not finished till the end of the line..
278        // we expect it continues to the nex line...
279      ptr += strlen (ptr);
280    }
281  else
282    {
283      pos--;
284      if (*pos == '\\')
285        {
286          ptr = pos + 2;
287        }
288      else
289        {
290          ptr = pos + 2;
291          state = in_line;
292        }
293    }
294
295  return (ptr);
296}
297
298//--------------------------------------------------
299static char* in_char_action (char* ptr, state_def& state)
300{
301  char* pos = strchr (ptr, '\'');
302  if (pos == 0)
303    {
304        // This string is not finished till the end of the line..
305        // we expect it continues to the nex line...
306      ptr += strlen (ptr);
307    }
308  else
309    {
310      pos--;
311      if (*pos == '\\')
312        {
313          ptr = pos + 2;
314        }
315      else
316        {
317          ptr = pos + 2;
318          state = in_line;
319        }
320    }
321
322  return (ptr);
323}
324
325//--------------------------------------------------
326static char* in_comment_action (char* ptr, state_def& state)
327{
328  char* pattern = &ptr[strlen (ptr)];
329  char* pos = strchr (ptr, '"');
330  if (pos != 0)
331    {
332      if (pos < pattern)
333        {
334          state = in_string_comment;
335          pattern = pos;
336        }
337    }
338  pos = strchr (ptr, '\'');
339  if (pos != 0)
340    {
341      if (pos < pattern)
342        {
343          state = in_char_comment;
344          pattern = pos;
345        }
346    }
347  pos = strstr (ptr, "*/");
348  if (pos != 0)
349    {
350      if (pos < pattern)
351        {
352          state = in_line;
353          pattern = pos + 1;
354        }
355    }
356
357  if (state == in_comment)
358    {
359      ptr += strlen (ptr);
360    }
361  else
362    {
363      ptr = pattern + 1;
364    }
365
366  return (ptr);
367}
368
369//--------------------------------------------------
370static char* in_string_comment_action (char* ptr, state_def& state)
371{
372  char* pos = strchr (ptr, '"');
373  if (pos == 0)
374    {
375        // This string is not finished till the end of the line..
376        // we expect it continues to the nex line...
377      ptr += strlen (ptr);
378    }
379  else
380    {
381      pos--;
382      if (*pos == '\\')
383        {
384          ptr = pos + 2;
385        }
386      else
387        {
388          ptr = pos + 2;
389          state = in_comment;
390        }
391    }
392
393  return (ptr);
394}
395
396//--------------------------------------------------
397static char* in_char_comment_action (char* ptr, state_def& state)
398{
399  char* pos = strchr (ptr, '\'');
400  if (pos == 0)
401    {
402        // This string is not finished till the end of the line..
403        // we expect it continues to the nex line...
404      ptr += strlen (ptr);
405    }
406  else
407    {
408      pos--;
409      if (*pos == '\\')
410        {
411          ptr = pos + 2;
412        }
413      else
414        {
415          ptr = pos + 2;
416          state = in_comment;
417        }
418    }
419
420  return (ptr);
421}
422
423//--------------------------------------------------
424static char* in_line_comment_action (char* ptr, state_def& state)
425{
426  ptr += strlen (ptr);
427
428  return (ptr);
429}
430
431//--------------------------------------------------
432static void build_deps_stream (istream& input,
433                               const cmt_string& dir_name,
434                               int current_path_index,
435                               const CmtSystem::cmt_string_vector& include_paths,
436                               const CmtSystem::cmt_string_vector& substitutions,
437                               CmtSystem::cmt_string_vector& all_deps,
438                               CmtSystem::cmt_string_vector& deps)
439{
440  Log;
441
442  if (input)
443    {
444      log << "CMT> build_deps_stream dir_name="
445          << dir_name << log_endl;
446
447      while (!input.eof ())
448        {
449          char line[16384];
450
451          input.getline (line, sizeof (line));
452          char* ptr = &line[0];
453          state_def state = at_start;
454
455          log << "CMT> build_deps_stream2 line=[" 
456              << line << "]" << log_endl;
457
458          while (strlen (ptr) > 0)
459            {
460              switch (state)
461                {
462                  case at_start:
463                    ptr = at_start_action (ptr,
464                                           state,
465                                           dir_name,
466                                           current_path_index,
467                                           include_paths,
468                                           substitutions,
469                                           all_deps,
470                                           deps);
471                    break;
472                  case in_line:
473                    ptr = in_line_action (ptr, state);
474                    break;
475                  case in_string:
476                    ptr = in_string_action (ptr, state);
477                    break;
478                  case in_char:
479                    ptr = in_char_action (ptr, state);
480                    break;
481                  case in_comment:
482                    ptr = in_comment_action (ptr, state);
483                    break;
484                  case in_string_comment:
485                    ptr = in_string_comment_action (ptr, state);
486                    break;
487                  case in_char_comment:
488                    ptr = in_char_comment_action (ptr, state);
489                    break;
490                  case in_line_comment:
491                    ptr = in_line_action (ptr, state);
492                    break;
493                }
494            }
495        }
496    }
497}
498
499//--------------------------------------------------
500static int build_deps (const cmt_string& name,
501                       const cmt_string& dir_name,
502                       int current_path_index,
503                       const CmtSystem::cmt_string_vector& include_paths,
504                       const CmtSystem::cmt_string_vector& substitutions,
505                       CmtSystem::cmt_string_vector& all_deps,
506                       CmtSystem::cmt_string_vector& deps)
507{
508  Log;
509
510  int result = -1;
511  cmt_string new_dir;
512
513  log << "CMT> build_deps name=" << name << " dir_name=" 
514      << dir_name << log_endl;
515
516    //
517    // Return 0 when the file is found in the current directory
518    //
519  if (CmtSystem::test_file (name))
520    {
521      ifstream input (name.c_str ());
522      if (input)
523        {
524          CmtSystem::dirname (name, new_dir);
525          build_deps_stream (input, new_dir, current_path_index,
526                             include_paths, substitutions,
527                             all_deps, deps);
528          return (0);
529        }
530    }
531
532  cmt_string full_name;
533
534  full_name = dir_name;
535  full_name += CmtSystem::file_separator ();
536  full_name += name;
537
538    //
539    // Return 1 when the file is found in the directory of the
540    // upper level source file
541    //
542  if (CmtSystem::test_file (full_name))
543    {
544      ifstream input (full_name.c_str ());
545      if (input)
546        {
547          CmtSystem::dirname (full_name, new_dir);
548          build_deps_stream (input, new_dir, current_path_index,
549                             include_paths, substitutions,
550                             all_deps, deps);
551          return (1);
552        }
553    }
554
555  int path_index = -1;
556
557    //
558    // Return [path_index + 2] when the include file is found at one of
559    // the include_paths
560    //
561  for (path_index = 0; path_index < include_paths.size (); path_index++)
562    {
563      full_name  = include_paths[path_index];
564      full_name += CmtSystem::file_separator ();
565      full_name += name;
566
567      log << "CMT> build_deps2 full_name=" << full_name << log_endl;
568
569      if (CmtSystem::test_file (full_name))
570        {
571          ifstream in (full_name.c_str ());
572          if (in)
573            {
574              CmtSystem::dirname (full_name, new_dir);
575
576              log << "CMT> build_deps3 new_dir=" << new_dir << log_endl;
577
578              build_deps_stream (in,
579                                 new_dir,
580                                 path_index + 2,
581                                 include_paths,
582                                 substitutions,
583                                 all_deps,
584                                 deps);
585
586              return (path_index + 2);
587            }
588        }
589    }
590
591  log << "CMT> build_deps3" << log_endl;
592
593  return (-1);
594}
595
596//--------------------------------------------------------------------------
597void DepsBuilder::clear ()
598{
599  m_include_paths.clear ();
600  m_substitutions.clear ();
601}
602
603//--------------------------------------------------------------------------
604void DepsBuilder::add (const cmt_string& path, const cmt_string& substitution)
605{
606  if (path[path.size () - 1] == CmtSystem::file_separator ())
607    {
608      cmt_string p = path;
609      p.erase (path.size () - 1);
610      m_include_paths.push_back (p);
611    }
612  else
613    {
614      m_include_paths.push_back (path);
615    }
616
617  m_substitutions.push_back (substitution);
618}
619
620//--------------------------------------------------------------------------
621void DepsBuilder::add_includes (const Use& use)
622{
623  Log;
624
625  const Include::IncludeVector& includes = use.includes;
626  int include_number;
627
628  for (include_number = 0;
629       include_number < includes.size ();
630       include_number++)
631    {
632      const Include& include = includes[include_number];
633
634      cmt_string temp = include.name;
635      cmt_string pattern;
636      cmt_string name;
637      char end_pattern;
638
639      int start = 0;
640
641      for (;;)
642        {
643          int begin;
644
645          begin = temp.find (start, "${");
646          if (begin != cmt_string::npos)
647            {
648              end_pattern = '}';
649            }
650          else
651            {
652              begin = temp.find (start, "$(");
653              if (begin != cmt_string::npos)
654                {
655                  end_pattern = ')';
656                }
657              else
658                {
659                  break;
660                }
661            }
662
663          start = begin + 2;
664
665          int end;
666          end = temp.find (start, end_pattern);
667          if (end == cmt_string::npos) break;
668          if (end < begin) break;
669          start = end + 1;
670
671          temp.substr (begin, end - begin + 1, pattern);
672          temp.substr (begin + 2, end - begin - 2, name);
673
674          Symbol* macro = Symbol::find (name);
675          if (macro != 0)
676            {
677              cmt_string value = macro->resolve_macro_value ();
678              value += CmtSystem::file_separator ();
679              temp.replace_all (pattern, value);
680            }
681          else
682            {
683              cmt_string value = CmtSystem::getenv (name);
684              value += CmtSystem::file_separator ();
685              temp.replace_all (pattern, value);
686            }
687        }
688
689      log << "include = " << temp << log_endl;
690
691      add (temp, include.name);
692    }
693}
694
695//--------------------------------------------------------------------------
696CmtSystem::cmt_string_vector& DepsBuilder::run (const cmt_string& file_name)
697{
698  m_deps.clear ();
699  m_all_deps.clear ();
700
701  cmt_string preprocessor;
702  Symbol* macro = Symbol::find ("preprocessor_command");
703  if (macro != 0)
704    {
705      preprocessor = macro->resolve_macro_value ();
706    }
707
708  if (preprocessor == "")
709    {
710        //
711        //   Since no preprocessor command is defined,
712        // we use the internal mechanism provided here.
713        //
714      cmt_string new_dir;
715
716      CmtSystem::dirname (file_name, new_dir);
717
718      build_deps (file_name,
719                  new_dir,
720                  0,
721                  m_include_paths,
722                  m_substitutions,
723                  m_all_deps,
724                  m_deps);
725    }
726  else
727    {
728        //
729        //  An external preprocessor command is defined. We expect it
730        // to follow a "standard" syntax for its output, ie:
731        //   o It starts with:
732        //       <module>.o: ...
733        //   o There may be many lines with trailing back-slashes
734        //   o All entries are space-separated
735        //   o One of the entries is the source file name itself
736        //
737        //  The preprocessor command expects the list of -I options
738        // (resolved from the "includes" macro) and the list of
739        // -D/-U options (resolved from the "*_pp_*flags" macros)
740        //
741
742        //
743        // Building the complete command (still the pp_*flags are
744        // missing)
745        //
746      preprocessor += " ";
747      macro = Symbol::find ("includes");
748      preprocessor += macro->resolve_macro_value ();
749      preprocessor += " ";
750      preprocessor += file_name;
751     
752      cmt_string output;
753     
754      CmtSystem::execute (preprocessor, output);
755
756        //
757        // Make the output as one single big line.
758        //
759
760      output.replace_all ("\n", " ");
761      output.replace_all ("\\ ", " ");
762     
763      CmtSystem::cmt_string_vector files;
764     
765      CmtSystem::split (output, " \t", files);
766
767        //
768        // Analyze each entry
769        //
770     
771      for (int i = 1; i < files.size (); i++)
772        {
773          const cmt_string& file = files[i];
774          if (file == file_name) continue;
775         
776          cmt_string dir;
777          cmt_string name;
778          cmt_string full_name;
779         
780          CmtSystem::dirname (file, dir);
781
782            //
783            // Only declared include_paths will be taken into account
784            // Others are considered as system include paths.
785            //
786         
787          for (int j = 0; j < m_include_paths.size (); j++)
788            {
789              const cmt_string& p = m_include_paths[j];
790              if (dir == p)
791                {
792                  CmtSystem::basename (file, name);
793                  full_name = m_substitutions[j];
794                  full_name += name;
795
796                    //
797                    // We add in the "m_deps" list the symbolic form
798                    // of the path rather that the expanded one.
799                    //
800                 
801                  m_deps.push_back (full_name);
802                 
803                  break;
804                }
805            }
806        }
807    }
808
809  return (m_deps);
810}
811
Note: See TracBrowser for help on using the repository browser.