source: CMT/HEAD/source/cmt_deps_builder.cxx @ 658

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

See C.L. 517

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