source: CMT/v1r25-branch/source/cmt_deps_builder.cxx @ 669

Last change on this file since 669 was 669, checked in by rybkin, 10 years ago

svn merge -r 666:668 HEAD

  • Property svn:eol-style set to native
File size: 28.2 KB
Line 
1//-----------------------------------------------------------
2// Copyright Christian Arnault LAL-Orsay CNRS
3// arnault@lal.in2p3.fr
4// Modified by Grigory Rybkin
5// See the complete license in cmt_license.txt "http://www.cecill.info".
6//-----------------------------------------------------------
7
8#include "cmt_deps_builder.h"
9#include "cmt_system.h"
10#include "cmt_use.h"
11#include "cmt_include.h"
12#include "cmt_symbol.h"
13#include "cmt_log.h"
14#include "cmt_error.h"
15
16//
17//  While parsing a C++ file, these are the possible usefull
18// states we can reach.
19//  Each state correspond to a specific state action function.
20//
21enum state_def
22  {
23    at_start,                                // beginning of the file
24    in_line,                                // along a line
25    in_string,                        // inside a quoted string
26    in_char,                                // inside a quoted char
27    in_comment,                        // inside a multi-line comment
28    in_string_comment,        // inside a quoted string in a comment
29    in_char_comment,                // inside a quoted char in a comment
30    in_line_comment                // inside a single-line comment
31  };
32
33//--------------------------------------------------
34static int locate (const cmt_string& name,
35                   const cmt_string& dir_name,
36                   const CmtSystem::cmt_string_vector& include_paths,
37                   const CmtSystem::cmt_string_vector& substitutions,
38                   cmt_string& full_name);
39
40//--------------------------------------------------
41static void build_deps_text (char* text,
42                             const cmt_string& dir_name,
43                             int current_path_index,
44                             const CmtSystem::cmt_string_vector& include_paths,
45                             const CmtSystem::cmt_string_vector& substitutions,
46                             const DepsBuilder::HeaderFilters& header_filters,
47                             CmtSystem::cmt_string_vector& all_deps,
48                             CmtSystem::cmt_string_vector& deps);
49
50//--------------------------------------------------
51static void header_file_action (const char* header_file,
52                                const cmt_string& dir_name,
53                                int current_path_index,
54                                const CmtSystem::cmt_string_vector& include_paths,
55                                const CmtSystem::cmt_string_vector& substitutions,
56                                const DepsBuilder::HeaderFilters& header_filters,
57                                CmtSystem::cmt_string_vector& all_deps,
58                                CmtSystem::cmt_string_vector& deps)
59{
60  Log;
61
62  for (int i = 0; i < all_deps.size (); i++)
63    {
64      const cmt_string& n = all_deps[i];
65
66      log << "CMT> check old header file name=" << n << " against " << header_file << log_endl;
67
68      if (n == header_file) return;
69    }
70
71  all_deps.push_back (header_file);
72
73  cmt_string header_file_path;
74  int path_index = locate (header_file,
75                           dir_name,
76                           include_paths,
77                           substitutions,
78                           header_file_path);
79
80  if (path_index < 0) return;
81
82  static int header_filters_size = header_filters.size ();
83  if (header_filters_size > 0)
84    {
85      // check the filter macros from
86      // find all macros named <package>_header_file_filter
87      // for all those macros, get the regexp and check the matches against the header file name
88      // if any match, select the stamp file instead of the header file
89      // the stamp file might be either a conventional name
90      //         <package>/cmt/cmt_all_headers.stamp
91      // or given in a macro eg <package>_header_stamp_file_name
92      //
93      for (int i = header_filters_size - 1; i >= 0; i--)
94        {
95          cmt_string stamp_file;
96          log << "|header_file_action> header " << header_file_path << " against stamp " << stamp_file << log_endl;
97          if (header_filters[i].use_stamp (header_file_path, stamp_file))
98            {
99              bool included = false;
100              for (int i = deps.size () - 1; i >= 0; i--)
101                {
102                  if (deps[i] == stamp_file)
103                    {
104                      included = true;
105                      break;
106                    }
107                }
108              if (!included) deps.push_back (stamp_file);
109              return;
110            }
111        }
112    }
113
114  log << "CMT> parsing new header file name=" << header_file << log_endl;
115
116///////////////////////////////////////////////////////////////////////////////////////////////////////
117  cmt_string text;
118  if (!text.read (header_file_path))
119    {
120      CmtError::set (CmtError::file_access_error, header_file_path);
121      return;
122    }
123  char* ptr = &text[0];
124  cmt_string new_dir;
125  CmtSystem::dirname (header_file_path, new_dir);
126
127  if (path_index == 0 || path_index == 1)
128    build_deps_text (ptr, new_dir,
129                     current_path_index,
130                     include_paths, substitutions,
131                     header_filters,
132                     all_deps, deps);
133  else
134    build_deps_text (ptr, new_dir,
135                     path_index,
136                     include_paths, substitutions,
137                     header_filters,
138                     all_deps, deps);
139///////////////////////////////////////////////////////////////////////////////////////////////////////
140     
141//path_index >= 0
142
143  cmt_string full_name;
144
145  if (path_index == 1)
146    {
147      full_name = dir_name;
148      full_name += CmtSystem::file_separator ();
149
150      if (current_path_index >= 2)
151        {
152          full_name.replace (include_paths[current_path_index - 2],
153                             substitutions[current_path_index - 2]);
154        }
155    }
156  else if (path_index > 1)
157    {
158      full_name  = substitutions[path_index - 2];
159      full_name += CmtSystem::file_separator ();
160    }
161
162  full_name += header_file;
163
164  deps.push_back (full_name);
165}
166
167
168//--------------------------------------------------
169static char* at_start_action (char* ptr,
170                              state_def& state,
171                              const cmt_string& dir_name,
172                              int current_path_index,
173                              const CmtSystem::cmt_string_vector& include_paths,
174                              const CmtSystem::cmt_string_vector& substitutions,
175                              const DepsBuilder::HeaderFilters& header_filters,
176                              CmtSystem::cmt_string_vector& all_deps,
177                              CmtSystem::cmt_string_vector& deps)
178{
179
180  char term = 0;
181  // To ignore leading spaces and tabs
182  while ( (*ptr == ' ') || (*ptr == '\t'))
183    {
184      ptr++;
185    }
186
187  if (*ptr == '#')
188    {
189      ptr++;
190
191      // skip spaces
192      while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
193
194      if (!strncmp (ptr, "include", 7))
195        {
196          // We have a #include statement
197
198          ptr += 7;
199
200          while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
201         
202          if (*ptr == '<')
203            {
204              term = '>';
205              ptr++;
206            }
207          else if (*ptr == '"')
208            {
209              term = '"';
210              ptr++;
211            }
212          else
213            {
214              // empty #include statement??
215              state = in_line;
216              ptr += strlen (ptr);
217              return (ptr);
218            }
219        }
220      else
221        {
222          // ignore other pre-processor statements
223
224          state = in_line;
225          ptr += strlen (ptr);
226          return (ptr);
227        }
228    }
229  else if (!strncmp (ptr, "include", 7) ||
230           !strncmp (ptr, "INCLUDE", 7))
231  //  else if (!strncmp (ptr, "      include", 13))
232    {
233      // fortran include statement
234
235      ptr += 7;
236      //ptr += 13;
237
238      while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
239
240      if (*ptr == '\'')
241        {
242          term = '\'';
243          ptr++;
244        }
245      else if (*ptr == '(')
246        {
247          term = ')';
248          ptr++;
249        }
250      else
251        {
252          state = in_line;
253          return (ptr);
254        }
255    }
256  /*
257  else if (!strncmp (ptr, "\tinclude", 8))
258    {
259      // fortran include statement
260
261      ptr += 8;
262
263      while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
264
265      if (*ptr == '\'')
266        {
267          term = '\'';
268          ptr++;
269        }
270      else
271        {
272          state = in_line;
273          return (ptr);
274        }
275    }
276  */
277  else
278    {
279      state = in_line;
280      return (ptr);
281    }
282
283  // At this point we do have to include a header file.
284
285  char* end;
286
287  end = strchr (ptr, term);
288  if (end != 0)
289    {
290      *end = 0;
291    }
292 
293  const char* header_file = ptr;
294 
295  header_file_action (header_file,
296                      dir_name,
297                      current_path_index,
298                      include_paths,
299                      substitutions,
300                      header_filters,
301                      all_deps,
302                      deps);
303 
304  if (end != 0)
305    {
306      *end = term;
307    }
308
309  state = in_line;
310  ptr += strlen (ptr);
311 
312  return (ptr);
313}
314
315/**
316   Any line with no header inclusion
317   step through comments and strings
318*/
319static char* in_line_action (char* ptr, state_def& state)
320{
321  //  char* pattern = ptr + strlen (ptr);\
322  //  int length = 0;
323
324  /*
325    search for the first occurrence of
326    {single-quote double-quote open-comment open-line-comment}
327
328    Must exclude escaped quotes \' and \"
329  */
330
331  char* beg = ptr;
332  while (char* p = strpbrk (beg, "\"\'/"))
333    if (*p == '"')
334      {
335        if (p == ptr || (p > ptr && *(p - 1) != '\\'))
336          {
337            state = in_string;
338            return p + 1;
339          }
340        else
341          { // '"' is escaped
342            beg = p + 1;
343          }
344      }
345    else if (*p == '\'')
346      {
347        if (p == ptr || (p > ptr && *(p - 1) != '\\'))
348          {
349            state = in_char;
350            return p + 1;
351          }
352        else
353          { // '\'' is escaped
354            beg = p + 1;
355          }
356      }
357    else
358      { // we have '/'
359        if (*(p + 1) == '*')
360          {
361            state = in_comment;
362            return p + 2;
363          }
364        else if (*(p + 1) == '/')
365          {
366            state = in_line_comment;
367            return p + 2;
368          }
369        else
370          {
371            beg = p + 1;
372          }
373      }
374  /*
375  char* pos = strchr (ptr, '"');
376  if ((pos != 0) && (pos < pattern) && (pos > ptr) && (*(pos-1) != '\\'))
377    {
378      state = in_string;
379      pattern = pos;
380      length = 1;
381    }
382
383  pos = strchr (ptr, '\'');
384  if ((pos != 0) && (pos < pattern) && (pos > ptr) && (*(pos-1) != '\\'))
385    {
386      state = in_char;
387      pattern = pos;
388      length = 1;
389    }
390
391  pos = strstr (ptr, "/*");
392  if ((pos != 0) && (pos < pattern))
393    {
394      state = in_comment;
395      pattern = pos;
396      length = 2;
397    }
398
399  pos = strstr (ptr, "//");
400  if ((pos != 0) && (pos < pattern))
401    {
402      state = in_line_comment;
403      pattern = pos;
404      length = 2;
405    }
406
407  ptr = pattern + length;
408  return (ptr);
409*/
410  return  ptr + strlen (ptr);
411}
412
413//--------------------------------------------------
414static char* in_string_action (char* ptr, state_def& state)
415{
416  // we exclusively look for a double quote
417
418  char* pos = strchr (ptr, '"');
419  if (pos == 0)
420    {
421      // This string is not finished till the end of the line..
422      // we expect it to continue to the next line...
423      // thus we leave the state as it is
424      ptr += strlen (ptr);
425    }
426  else
427    {
428      if ((pos > ptr) && (*(pos - 1) == '\\'))
429        {
430          ptr = pos + 1;
431        }
432      else
433        {
434          ptr = pos + 1;
435          state = in_line;
436        }
437    }
438
439  return (ptr);
440}
441
442//--------------------------------------------------
443static char* in_char_action (char* ptr, state_def& state)
444{
445  // we exclusively look for a single quote
446
447  char* pos = strchr (ptr, '\'');
448  if (pos == 0)
449    {
450      // This string is not finished till the end of the line..
451      // we expect it continues to the nex line...
452      // thus we leave the state as it is
453      ptr += strlen (ptr);
454    }
455  else
456    {
457      if ((pos > ptr) && (*(pos - 1) == '\\'))
458        {
459          ptr = pos + 1;
460        }
461      else
462        {
463          ptr = pos + 1;
464          state = in_line;
465        }
466    }
467
468  return (ptr);
469}
470
471//--------------------------------------------------
472static char* in_comment_action (char* ptr, state_def& state)
473{
474  char* pattern = ptr + strlen (ptr);
475  int length    = 0;
476  char* pos;
477 
478
479  /*
480    Even if we are inside a comment, we must detect strings since comment markers may
481    be written inside them.
482 
483    pos = strchr (ptr, '"');
484 
485    if ((pos != 0) && (pos < pattern) && (pos > ptr) && (*(pos-1) != '\\'))
486    {
487    state = in_string_comment;
488    pattern = pos;
489    length = 1;
490    }
491
492    pos = strchr (ptr, '\'');
493    if ((pos != 0) && (pos < pattern) && (pos > ptr) && (*(pos-1) != '\\'))
494    {
495    state = in_char_comment;
496    pattern = pos;
497    length = 1;
498    }
499  */
500  pos = strstr (ptr, "*/");
501  if ((pos != 0) && (pos < pattern))
502    {
503      state   = in_line;
504      pattern = pos;
505      length  = 2;
506    }
507
508  ptr = pattern + length;
509
510  return (ptr);
511}
512
513//--------------------------------------------------
514static char* in_string_comment_action (char* ptr, state_def& state)
515{
516  char* pos = strchr (ptr, '"');
517  if (pos == 0)
518    {
519      // This string is not finished till the end of the line..
520      // we expect it continues to the nex line...
521      ptr += strlen (ptr);
522    }
523  else
524    {
525      if ((pos > ptr) && (*(pos - 1) == '\\'))
526        {
527          ptr = pos + 1;
528        }
529      else
530        {
531          ptr = pos + 1;
532          state = in_comment;
533        }
534    }
535
536  return (ptr);
537}
538
539//--------------------------------------------------
540static char* in_char_comment_action (char* ptr, state_def& state)
541{
542  char* pos = strchr (ptr, '\'');
543  if (pos == 0)
544    {
545      // This string is not finished till the end of the line..
546      // we expect it continues to the nex line...
547      ptr += strlen (ptr);
548    }
549  else
550    {
551      if ((pos > ptr) && (*(pos - 1) == '\\'))
552        {
553          ptr = pos + 1;
554        }
555      else
556        {
557          ptr = pos + 1;
558          state = in_comment;
559        }
560      pos--;
561    }
562
563  return (ptr);
564}
565
566//--------------------------------------------------
567static char* in_line_comment_action (char* ptr, state_def& state)
568{
569  //  char * pos = strchr (ptr, '\\'); 
570  /* Extend this part to deal with continuation character */ 
571//   if ( (pos == NULL) || ( (ptr + strlen(ptr)-1)!=pos ))
572//     {
573//       state = in_line;
574//     }
575  /* We already deleted all backslash characters that with newline continue line */
576  state = in_line;
577  ptr    += strlen (ptr);
578 
579  return (ptr);
580}
581
582//--------------------------------------------------
583static void build_deps_text (char* text,
584                             const cmt_string& dir_name,
585                             int current_path_index,
586                             const CmtSystem::cmt_string_vector& include_paths,
587                             const CmtSystem::cmt_string_vector& substitutions,
588                             const DepsBuilder::HeaderFilters& header_filters,
589                             CmtSystem::cmt_string_vector& all_deps,
590                             CmtSystem::cmt_string_vector& deps)
591{
592  Log;
593
594  int line_number = 1;
595
596  log << "|build_deps_text> dir_name="
597      << dir_name << log_endl;
598
599  char* current = text;
600  char* nl;
601  int length;
602  char * ptr;
603  char * begin = current;
604 
605  state_def state = at_start;
606 
607  // nl -> new line
608  while (nl = strchr (begin, '\n'))
609    {
610      length = 0;
611
612      if (begin < nl)
613        {
614          if (*(nl - 1) == '\\')
615            {
616              // erase backslash + newline (continuation character)
617              // shift 2
618              begin = nl - 1;
619              char *d = begin;
620              char *s = nl + 1;
621              while (*d++ = *s++)
622                ;
623            }
624          else if (*(nl - 1) == '\r')
625            {
626              if ((begin < (nl - 1)) && (*(nl - 2) == '\\'))
627                {
628                  // erase backslash + carriage return + newline (continuation character)
629                  // shift 3
630                  begin = nl - 2;
631                  char *d = begin;
632                  char *s = nl + 1;
633                  while (*d++ = *s++)
634                    ;
635                }
636              else
637                {
638                  // process line [current, nl - 1)
639                  length = 2;
640                }
641            }
642          else
643            {
644              // process line [current, nl)
645              length = 1;
646            }
647        }
648      else
649        {
650          // process line [current, nl)
651          length = 1;
652        }
653     
654      if (0 == length) continue;
655
656      if (1 == length)
657        {
658          *nl = 0;
659        }
660      else
661        {
662          *(nl - 1) = 0;
663        }
664     
665      ptr = current;
666      log << "|build_deps_text> line=["
667          << current << "]" << log_endl;
668     
669      while (strlen (ptr) > 0)
670        {
671          switch (state)
672            {
673            case at_start:
674              ptr = at_start_action (ptr,
675                                     state,
676                                     dir_name,
677                                     current_path_index,
678                                     include_paths,
679                                     substitutions,
680                                     header_filters,
681                                     all_deps,
682                                     deps);
683              break;
684            case in_line:
685              ptr = in_line_action (ptr, state);
686              break;
687            case in_string:
688              ptr = in_string_action (ptr, state);
689              break;
690            case in_char:
691              ptr = in_char_action (ptr, state);
692              break;
693            case in_comment:
694              ptr = in_comment_action (ptr, state);
695              break;
696            case in_string_comment:
697              ptr = in_string_comment_action (ptr, state);
698              break;
699            case in_char_comment:
700              ptr = in_char_comment_action (ptr, state);
701              break;
702            case in_line_comment:
703              ptr = in_line_comment_action (ptr, state);
704              break;
705            }
706        } // while (strlen (ptr) > 0)
707     
708      //if (state == in_line) state = at_start;
709      switch (state)
710        {
711        case in_line:
712        case in_line_comment:
713          state = at_start;
714          break;
715        default:
716          break;
717        }
718      line_number++;
719
720      if (1 == length)
721        {
722          *nl = '\n';
723        }
724      else
725        {
726          *(nl - 1) = '\r';
727        }
728      current = nl + 1;
729      begin = current;
730
731    } // while (nl = ...)
732
733      ptr = current;
734      log << "|build_deps_text> line=["
735          << current << "]" << log_endl;
736     
737      while (strlen (ptr) > 0)
738        {
739          switch (state)
740            {
741            case at_start:
742              ptr = at_start_action (ptr,
743                                     state,
744                                     dir_name,
745                                     current_path_index,
746                                     include_paths,
747                                     substitutions,
748                                     header_filters,
749                                     all_deps,
750                                     deps);
751              break;
752            case in_line:
753              ptr = in_line_action (ptr, state);
754              break;
755            case in_string:
756              ptr = in_string_action (ptr, state);
757              break;
758            case in_char:
759              ptr = in_char_action (ptr, state);
760              break;
761            case in_comment:
762              ptr = in_comment_action (ptr, state);
763              break;
764            case in_string_comment:
765              ptr = in_string_comment_action (ptr, state);
766              break;
767            case in_char_comment:
768              ptr = in_char_comment_action (ptr, state);
769              break;
770            case in_line_comment:
771              ptr = in_line_comment_action (ptr, state);
772              break;
773            }
774        }
775 
776}
777
778//--------------------------------------------------
779static int build_deps (const cmt_string& name,
780                       const cmt_string& dir_name,
781                       int current_path_index,
782                       const CmtSystem::cmt_string_vector& include_paths,
783                       const CmtSystem::cmt_string_vector& substitutions,
784                       const DepsBuilder::HeaderFilters& header_filters,
785                       CmtSystem::cmt_string_vector& all_deps,
786                       CmtSystem::cmt_string_vector& deps)
787{
788  Log;
789
790  log << "CMT> build_deps name=" << name << " dir_name=" 
791      << dir_name << log_endl;
792
793  cmt_string full_name;
794  int path_index = locate (name,
795                           dir_name,
796                           include_paths,
797                           substitutions,
798                           full_name);
799
800  if (path_index >= 0)
801    {
802      cmt_string text;
803      if (!text.read (full_name))
804        {
805          CmtError::set (CmtError::file_access_error, full_name);
806          return -2;
807        }
808      char* ptr = &text[0];
809      cmt_string new_dir;
810      CmtSystem::dirname (full_name, new_dir);
811
812      if (path_index == 0 || path_index == 1)
813        build_deps_text (ptr, new_dir,
814                         current_path_index,
815                         include_paths, substitutions,
816                         header_filters,
817                         all_deps, deps);
818      else
819        build_deps_text (ptr, new_dir,
820                         path_index,
821                         include_paths, substitutions,
822                         header_filters,
823                         all_deps, deps);
824    }
825  if (path_index < 0)
826    {
827      log << "CMT> build_deps3" << log_endl;
828      CmtError::set (CmtError::path_not_found, name);
829    }
830  return path_index;
831}
832
833//--------------------------------------------------
834static int locate (const cmt_string& name,
835                   const cmt_string& dir_name,
836                   const CmtSystem::cmt_string_vector& include_paths,
837                   const CmtSystem::cmt_string_vector& substitutions,
838                   cmt_string& full_name)
839{
840  Log;
841
842  log << "CMT> locate name=" << name << " dir_name=" 
843      << dir_name << log_endl;
844
845  //
846  // Return 0 when the file is found in the current directory
847  //
848  if (CmtSystem::test_file (name))
849    {
850      full_name = name;
851      return (0);
852    }
853
854  cmt_string p;
855
856  //
857  // Return 1 when the file is found in the directory of the
858  // upper level source file
859  //
860  p = dir_name;
861  p += CmtSystem::file_separator ();
862  p += name;
863  if (CmtSystem::test_file (p))
864    {
865      full_name = p;
866      return (1);
867    }
868
869  //
870  // Return [path_index + 2] when the include file is found at one of
871  // the include_paths
872  //
873  for (int path_index = 0; path_index < include_paths.size (); path_index++)
874    {
875      p  = include_paths[path_index];
876      p += CmtSystem::file_separator ();
877      p += name;
878
879      log << "CMT> locate2 full_name=" << p << log_endl;
880
881      if (CmtSystem::test_file (p))
882        {
883          full_name = p;
884          return (path_index + 2);
885        }
886    }
887
888  log << "CMT> locate3" << log_endl;
889
890  return (-1);
891}
892
893//--------------------------------------------------------------------------
894DepsBuilder::DepsBuilder ()
895{ }
896
897//--------------------------------------------------------------------------
898DepsBuilder::~DepsBuilder ()
899{
900  clear ();
901}
902
903//--------------------------------------------------------------------------
904void DepsBuilder::clear ()
905{
906  m_include_paths.clear ();
907  m_substitutions.clear ();
908  for (int i = m_header_filters.size () - 1; i >= 0; i--)
909    {
910      m_header_filters[i].clear ();
911    }
912  m_header_filters.clear ();
913  m_deps.clear ();
914  m_all_deps.clear ();
915}
916
917//--------------------------------------------------------------------------
918void DepsBuilder::add (const cmt_string& path, const cmt_string& substitution)
919{
920  if (path.size () == 0)
921    {
922      return;
923    }
924
925  cmt_string p = path;
926  if (path[path.size () - 1] == CmtSystem::file_separator ())
927    {
928      p = path.substr(0, path.size () - 1);
929    }
930  for (int k = m_include_paths.size () - 1; k >= 0; k--)
931    if (m_include_paths[k] == p)
932      {
933        return;
934      }
935 
936  m_include_paths.push_back (p);
937  m_substitutions.push_back (substitution);
938}
939
940//--------------------------------------------------------------------------
941void DepsBuilder::add_includes (const Use& use)
942{
943  Log;
944
945  const Include::IncludeVector& includes = use.includes;
946  int include_number;
947
948  for (include_number = 0;
949       include_number < includes.size ();
950       include_number++)
951    {
952      const Include& include = includes[include_number];
953
954      cmt_string temp = include.name;
955      cmt_string pattern;
956      cmt_string name;
957      char end_pattern;
958
959      int start = 0;
960
961      for (;;)
962        {
963          int begin;
964
965          begin = temp.find (start, "${");
966          if (begin != cmt_string::npos)
967            {
968              end_pattern = '}';
969            }
970          else
971            {
972              begin = temp.find (start, "$(");
973              if (begin != cmt_string::npos)
974                {
975                  end_pattern = ')';
976                }
977              else
978                {
979                  break;
980                }
981            }
982
983          start = begin + 2;
984
985          int end;
986          end = temp.find (start, end_pattern);
987          if (end == cmt_string::npos) break;
988          if (end < begin) break;
989          start = end + 1;
990
991          temp.substr (begin, end - begin + 1, pattern);
992          temp.substr (begin + 2, end - begin - 2, name);
993
994          Symbol* macro = Symbol::find (name);
995          if (macro != 0)
996            {
997              cmt_string value = macro->resolve_macro_value ();
998              value += CmtSystem::file_separator ();
999              temp.replace_all (pattern, value);
1000            }
1001          else
1002            {
1003              cmt_string value = CmtSystem::getenv (name);
1004              value += CmtSystem::file_separator ();
1005              temp.replace_all (pattern, value);
1006            }
1007        }
1008
1009      log << "include = " << temp << log_endl;
1010
1011      add (temp, include.name);
1012    }
1013}
1014
1015//--------------------------------------------------------------------------
1016CmtSystem::cmt_string_vector& DepsBuilder::run (const cmt_string& file_name,
1017                                                const cmt_string& constituent_name)
1018{
1019  Log;
1020
1021  log << "Starting deps builder on " << file_name << log_endl;
1022  CmtMessage::info ("calculating dependencies for " + file_name);
1023
1024  m_deps.clear ();
1025  m_all_deps.clear ();
1026
1027  cmt_string preprocessor;
1028  Symbol* macro = Symbol::find ("preprocessor_command");
1029  if (macro != 0)
1030    {
1031      preprocessor = macro->resolve_macro_value ();
1032    }
1033
1034  if (preprocessor == "")
1035    {
1036      //
1037      //   Since no preprocessor command is defined,
1038      // we use the internal mechanism provided here.
1039      //
1040      cmt_string new_dir;
1041
1042      CmtSystem::dirname (file_name, new_dir);
1043
1044      build_deps (file_name,
1045                  new_dir,
1046                  0,
1047                  m_include_paths,
1048                  m_substitutions,
1049                  m_header_filters,
1050                  m_all_deps,
1051                  m_deps);
1052    }
1053  else
1054    {
1055      //
1056      //  An external preprocessor command is defined. We expect it
1057      // to follow a "standard" syntax for its output, ie:
1058      //   o It starts with:
1059      //       <module>.o: ...
1060      //   o There may be many lines with trailing back-slashes
1061      //   o All entries are space-separated
1062      //   o One of the entries is the source file name itself
1063      //
1064      //  The preprocessor command expects the list of -I options
1065      // (resolved from the "includes" macro) and the list of
1066      // -D/-U options (resolved from the "*_pp_*flags" macros)
1067      //
1068
1069      //
1070      // Building the complete command (still the pp_*flags are
1071      // missing)
1072      //
1073      macro = Symbol::find ("includes");
1074      if (0 != macro)
1075        {
1076          preprocessor += " ";
1077          preprocessor += macro->resolve_macro_value ();
1078        }
1079      macro = Symbol::find ("app_" + constituent_name + "_cppflags");
1080      if (0 != macro)
1081        {
1082          preprocessor += " ";
1083          preprocessor += macro->resolve_macro_value ();
1084        }
1085      macro = Symbol::find ("lib_" + constituent_name + "_cppflags");
1086      if (0 != macro)
1087        {
1088          preprocessor += " ";
1089          preprocessor += macro->resolve_macro_value ();
1090        }
1091     
1092      preprocessor += " ";
1093      preprocessor += file_name;
1094     
1095      cmt_string output;
1096     
1097      int status = CmtSystem::execute (preprocessor, output);
1098      if (0 != status)
1099        {
1100          CmtError::set (CmtError::execution_failed, preprocessor, status);
1101          return m_deps;
1102        }
1103
1104      //
1105      // Make the output as one single big line.
1106      //
1107
1108      output.replace_all ("\n", " ");
1109      output.replace_all ("\\ ", " ");
1110     
1111      CmtSystem::cmt_string_vector files;
1112     
1113      CmtSystem::split (output, " \t", files);
1114
1115      //
1116      // Analyze each entry
1117      //
1118     
1119      for (int i = 1; i < files.size (); i++)
1120        {
1121          const cmt_string& file = files[i];
1122          if (file == file_name) continue;
1123         
1124          cmt_string dir;
1125          cmt_string name;
1126          cmt_string full_name;
1127         
1128          CmtSystem::dirname (file, dir);
1129
1130          //
1131          // Only declared include_paths will be taken into account
1132          // Others are considered as system include paths.
1133          //
1134         
1135          for (int j = 0; j < m_include_paths.size (); j++)
1136            {
1137              const cmt_string& p = m_include_paths[j];
1138              if (dir == p)
1139                {
1140                  CmtSystem::basename (file, name);
1141                  full_name = m_substitutions[j];
1142                  full_name += name;
1143
1144                  //
1145                  // We add in the "m_deps" list the symbolic form
1146                  // of the path rather that the expanded one.
1147                  //
1148                 
1149                  m_deps.push_back (full_name);
1150                 
1151                  break;
1152                }
1153            }
1154        }
1155    }
1156
1157  return (m_deps);
1158}
1159
1160//--------------------------------------------------------------------------
1161void DepsBuilder::add_header_filter (const Use* use, cmt_regexp* filter, const cmt_string& stamp)
1162{
1163  add_header_filter (HeaderFilter (use, filter, stamp));
1164}
1165
1166//--------------------------------------------------------------------------
1167void DepsBuilder::add_header_filter (const HeaderFilter& hf)
1168{
1169  m_header_filters.push_back (hf);
1170}
Note: See TracBrowser for help on using the repository browser.