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

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

See C.L. 522

  • Property svn:eol-style set to native
File size: 28.2 KB
RevLine 
[2]1//-----------------------------------------------------------
2// Copyright Christian Arnault LAL-Orsay CNRS
3// arnault@lal.in2p3.fr
[663]4// Modified by Grigory Rybkin
[2]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"
[588]14#include "cmt_error.h"
[2]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
[400]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  };
[2]32
33//--------------------------------------------------
[427]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);
[2]39
[427]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);
[2]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,
[427]56                                const DepsBuilder::HeaderFilters& header_filters,
[2]57                                CmtSystem::cmt_string_vector& all_deps,
58                                CmtSystem::cmt_string_vector& deps)
59{
[78]60  Log;
61
[2]62  for (int i = 0; i < all_deps.size (); i++)
63    {
[78]64      const cmt_string& n = all_deps[i];
65
66      log << "CMT> check old header file name=" << n << " against " << header_file << log_endl;
67
[427]68      if (n == header_file) return;
[2]69    }
[427]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)
[2]84    {
[427]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--)
[2]94        {
[427]95          cmt_string stamp_file;
[588]96          log << "|header_file_action> header " << header_file_path << " against stamp " << stamp_file << log_endl;
[427]97          if (header_filters[i].use_stamp (header_file_path, stamp_file))
[2]98            {
[427]99              bool included = false;
100              for (int i = deps.size () - 1; i >= 0; i--)
[2]101                {
[427]102                  if (deps[i] == stamp_file)
103                    {
104                      included = true;
105                      break;
106                    }
[2]107                }
[427]108              if (!included) deps.push_back (stamp_file);
109              return;
[2]110            }
111        }
112    }
[427]113
114  log << "CMT> parsing new header file name=" << header_file << log_endl;
115
116///////////////////////////////////////////////////////////////////////////////////////////////////////
117  cmt_string text;
[588]118  if (!text.read (header_file_path))
119    {
120      CmtError::set (CmtError::file_access_error, header_file_path);
121      return;
122    }
[427]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);
[2]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,
[427]175                              const DepsBuilder::HeaderFilters& header_filters,
[2]176                              CmtSystem::cmt_string_vector& all_deps,
177                              CmtSystem::cmt_string_vector& deps)
178{
[360]179
[2]180  char term = 0;
[360]181  // To ignore leading spaces and tabs
[399]182  while ( (*ptr == ' ') || (*ptr == '\t'))
[400]183    {
184      ptr++;
185    }
[2]186
187  if (*ptr == '#')
188    {
189      ptr++;
[78]190
191      // skip spaces
[399]192      while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
[78]193
[2]194      if (!strncmp (ptr, "include", 7))
195        {
[78]196          // We have a #include statement
197
[2]198          ptr += 7;
199
[399]200          while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
[360]201         
[2]202          if (*ptr == '<')
203            {
204              term = '>';
205              ptr++;
206            }
207          else if (*ptr == '"')
208            {
209              term = '"';
210              ptr++;
211            }
212          else
213            {
[78]214              // empty #include statement??
[2]215              state = in_line;
216              ptr += strlen (ptr);
217              return (ptr);
218            }
219        }
220      else
221        {
[78]222          // ignore other pre-processor statements
223
[2]224          state = in_line;
225          ptr += strlen (ptr);
226          return (ptr);
227        }
228    }
[657]229  else if (!strncmp (ptr, "include", 7) ||
230           !strncmp (ptr, "INCLUDE", 7))
231  //  else if (!strncmp (ptr, "      include", 13))
[2]232    {
[78]233      // fortran include statement
234
[657]235      ptr += 7;
236      //ptr += 13;
[2]237
[399]238      while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
[78]239
[399]240      if (*ptr == '\'')
[2]241        {
[399]242          term = '\'';
[2]243          ptr++;
244        }
[657]245      else if (*ptr == '(')
246        {
247          term = ')';
248          ptr++;
249        }
[2]250      else
251        {
252          state = in_line;
253          return (ptr);
254        }
255    }
[657]256  /*
[399]257  else if (!strncmp (ptr, "\tinclude", 8))
[2]258    {
[78]259      // fortran include statement
260
[2]261      ptr += 8;
262
[399]263      while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
[78]264
[399]265      if (*ptr == '\'')
[2]266        {
[399]267          term = '\'';
[2]268          ptr++;
269        }
270      else
271        {
272          state = in_line;
273          return (ptr);
274        }
275    }
[657]276  */
[2]277  else
278    {
279      state = in_line;
280      return (ptr);
281    }
282
[78]283  // At this point we do have to include a header file.
284
[2]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,
[427]300                      header_filters,
[2]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
[78]315/**
316   Any line with no header inclusion
317   step through comments and strings
[400]318*/
[2]319static char* in_line_action (char* ptr, state_def& state)
320{
[657]321  //  char* pattern = ptr + strlen (ptr);\
322  //  int length = 0;
[2]323
[78]324  /*
325    search for the first occurrence of
326    {single-quote double-quote open-comment open-line-comment}
327
[399]328    Must exclude escaped quotes \' and \"
[78]329  */
330
[657]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
[658]342            beg = p + 1;
[657]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
[658]354            beg = p + 1;
[657]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          {
[658]371            beg = p + 1;
[657]372          }
373      }
374  /*
[2]375  char* pos = strchr (ptr, '"');
[399]376  if ((pos != 0) && (pos < pattern) && (pos > ptr) && (*(pos-1) != '\\'))
[2]377    {
[78]378      state = in_string;
379      pattern = pos;
380      length = 1;
[2]381    }
382
[399]383  pos = strchr (ptr, '\'');
384  if ((pos != 0) && (pos < pattern) && (pos > ptr) && (*(pos-1) != '\\'))
[2]385    {
[78]386      state = in_char;
387      pattern = pos;
388      length = 1;
[2]389    }
390
[657]391  pos = strstr (ptr, "/*");
[78]392  if ((pos != 0) && (pos < pattern))
[2]393    {
[78]394      state = in_comment;
395      pattern = pos;
396      length = 2;
[2]397    }
398
399  pos = strstr (ptr, "//");
[78]400  if ((pos != 0) && (pos < pattern))
[2]401    {
[78]402      state = in_line_comment;
403      pattern = pos;
404      length = 2;
[2]405    }
406
[78]407  ptr = pattern + length;
[2]408  return (ptr);
[657]409*/
410  return  ptr + strlen (ptr);
[2]411}
412
413//--------------------------------------------------
414static char* in_string_action (char* ptr, state_def& state)
415{
[78]416  // we exclusively look for a double quote
417
[2]418  char* pos = strchr (ptr, '"');
419  if (pos == 0)
420    {
[400]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
[2]424      ptr += strlen (ptr);
425    }
426  else
427    {
[399]428      if ((pos > ptr) && (*(pos - 1) == '\\'))
[2]429        {
[78]430          ptr = pos + 1;
[2]431        }
432      else
433        {
[78]434          ptr = pos + 1;
[2]435          state = in_line;
436        }
437    }
438
439  return (ptr);
440}
441
442//--------------------------------------------------
443static char* in_char_action (char* ptr, state_def& state)
444{
[78]445  // we exclusively look for a single quote
446
[399]447  char* pos = strchr (ptr, '\'');
[2]448  if (pos == 0)
449    {
[400]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
[2]453      ptr += strlen (ptr);
454    }
455  else
456    {
[399]457      if ((pos > ptr) && (*(pos - 1) == '\\'))
[2]458        {
[78]459          ptr = pos + 1;
[2]460        }
461      else
462        {
[78]463          ptr = pos + 1;
[2]464          state = in_line;
465        }
466    }
467
468  return (ptr);
469}
470
471//--------------------------------------------------
472static char* in_comment_action (char* ptr, state_def& state)
473{
[78]474  char* pattern = ptr + strlen (ptr);
[360]475  int length    = 0;
476  char* pos;
477 
[78]478
[400]479  /*
[78]480    Even if we are inside a comment, we must detect strings since comment markers may
481    be written inside them.
[360]482 
[400]483    pos = strchr (ptr, '"');
[360]484 
[400]485    if ((pos != 0) && (pos < pattern) && (pos > ptr) && (*(pos-1) != '\\'))
[2]486    {
[400]487    state = in_string_comment;
488    pattern = pos;
489    length = 1;
[2]490    }
[78]491
[400]492    pos = strchr (ptr, '\'');
493    if ((pos != 0) && (pos < pattern) && (pos > ptr) && (*(pos-1) != '\\'))
[2]494    {
[400]495    state = in_char_comment;
496    pattern = pos;
497    length = 1;
[2]498    }
[400]499  */
[2]500  pos = strstr (ptr, "*/");
[78]501  if ((pos != 0) && (pos < pattern))
[2]502    {
[360]503      state   = in_line;
[78]504      pattern = pos;
[360]505      length  = 2;
[2]506    }
507
[78]508  ptr = pattern + length;
[2]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    {
[400]519      // This string is not finished till the end of the line..
520      // we expect it continues to the nex line...
[2]521      ptr += strlen (ptr);
522    }
523  else
524    {
[399]525      if ((pos > ptr) && (*(pos - 1) == '\\'))
[2]526        {
[78]527          ptr = pos + 1;
[2]528        }
529      else
530        {
[78]531          ptr = pos + 1;
[2]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{
[399]542  char* pos = strchr (ptr, '\'');
[2]543  if (pos == 0)
544    {
[400]545      // This string is not finished till the end of the line..
546      // we expect it continues to the nex line...
[2]547      ptr += strlen (ptr);
548    }
549  else
550    {
[399]551      if ((pos > ptr) && (*(pos - 1) == '\\'))
[2]552        {
[78]553          ptr = pos + 1;
[2]554        }
555      else
556        {
[78]557          ptr = pos + 1;
[2]558          state = in_comment;
559        }
[78]560      pos--;
[2]561    }
562
563  return (ptr);
564}
565
566//--------------------------------------------------
567static char* in_line_comment_action (char* ptr, state_def& state)
568{
[606]569  //  char * pos = strchr (ptr, '\\'); 
[400]570  /* Extend this part to deal with continuation character */ 
[606]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;
[360]577  ptr    += strlen (ptr);
578 
[2]579  return (ptr);
580}
581
582//--------------------------------------------------
[78]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,
[427]588                             const DepsBuilder::HeaderFilters& header_filters,
[78]589                             CmtSystem::cmt_string_vector& all_deps,
590                             CmtSystem::cmt_string_vector& deps)
[2]591{
592  Log;
593
[78]594  int line_number = 1;
595
[606]596  log << "|build_deps_text> dir_name="
[78]597      << dir_name << log_endl;
598
599  char* current = text;
[606]600  char* nl;
601  int length;
602  char * ptr;
603  char * begin = current;
[360]604 
[78]605  state_def state = at_start;
[360]606 
[606]607  // nl -> new line
608  while (nl = strchr (begin, '\n'))
[2]609    {
[606]610      length = 0;
[2]611
[606]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        }
[78]648      else
649        {
[606]650          // process line [current, nl)
[78]651          length = 1;
652        }
[606]653     
654      if (0 == length) continue;
[78]655
[606]656      if (1 == length)
657        {
658          *nl = 0;
659        }
660      else
661        {
662          *(nl - 1) = 0;
663        }
664     
[78]665      ptr = current;
[606]666      log << "|build_deps_text> line=["
[78]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,
[606]680                                     header_filters,
[78]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:
[79]703              ptr = in_line_comment_action (ptr, state);
[78]704              break;
705            }
[606]706        } // while (strlen (ptr) > 0)
707     
[657]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        }
[78]716      line_number++;
717
[606]718      if (1 == length)
[78]719        {
[606]720          *nl = '\n';
[78]721        }
722      else
723        {
[606]724          *(nl - 1) = '\r';
[78]725        }
[606]726      current = nl + 1;
727      begin = current;
728
729    } // while (nl = ...)
730
731      ptr = current;
732      log << "|build_deps_text> line=["
733          << current << "]" << log_endl;
734     
735      while (strlen (ptr) > 0)
736        {
737          switch (state)
738            {
739            case at_start:
740              ptr = at_start_action (ptr,
741                                     state,
742                                     dir_name,
743                                     current_path_index,
744                                     include_paths,
745                                     substitutions,
746                                     header_filters,
747                                     all_deps,
748                                     deps);
749              break;
750            case in_line:
751              ptr = in_line_action (ptr, state);
752              break;
753            case in_string:
754              ptr = in_string_action (ptr, state);
755              break;
756            case in_char:
757              ptr = in_char_action (ptr, state);
758              break;
759            case in_comment:
760              ptr = in_comment_action (ptr, state);
761              break;
762            case in_string_comment:
763              ptr = in_string_comment_action (ptr, state);
764              break;
765            case in_char_comment:
766              ptr = in_char_comment_action (ptr, state);
767              break;
768            case in_line_comment:
769              ptr = in_line_comment_action (ptr, state);
770              break;
771            }
772        }
773 
[2]774}
775
776//--------------------------------------------------
777static int build_deps (const cmt_string& name,
778                       const cmt_string& dir_name,
779                       int current_path_index,
780                       const CmtSystem::cmt_string_vector& include_paths,
781                       const CmtSystem::cmt_string_vector& substitutions,
[427]782                       const DepsBuilder::HeaderFilters& header_filters,
[2]783                       CmtSystem::cmt_string_vector& all_deps,
784                       CmtSystem::cmt_string_vector& deps)
785{
786  Log;
787
788  log << "CMT> build_deps name=" << name << " dir_name=" 
789      << dir_name << log_endl;
790
[427]791  cmt_string full_name;
792  int path_index = locate (name,
793                           dir_name,
794                           include_paths,
795                           substitutions,
796                           full_name);
797
798  if (path_index >= 0)
799    {
800      cmt_string text;
[588]801      if (!text.read (full_name))
802        {
803          CmtError::set (CmtError::file_access_error, full_name);
804          return -2;
805        }
[427]806      char* ptr = &text[0];
807      cmt_string new_dir;
808      CmtSystem::dirname (full_name, new_dir);
809
810      if (path_index == 0 || path_index == 1)
811        build_deps_text (ptr, new_dir,
812                         current_path_index,
813                         include_paths, substitutions,
814                         header_filters,
815                         all_deps, deps);
816      else
817        build_deps_text (ptr, new_dir,
818                         path_index,
819                         include_paths, substitutions,
820                         header_filters,
821                         all_deps, deps);
822    }
823  if (path_index < 0)
824    {
825      log << "CMT> build_deps3" << log_endl;
[588]826      CmtError::set (CmtError::path_not_found, name);
[427]827    }
828  return path_index;
829}
830
831//--------------------------------------------------
832static int locate (const cmt_string& name,
833                   const cmt_string& dir_name,
834                   const CmtSystem::cmt_string_vector& include_paths,
835                   const CmtSystem::cmt_string_vector& substitutions,
836                   cmt_string& full_name)
837{
838  Log;
839
840  log << "CMT> locate name=" << name << " dir_name=" 
841      << dir_name << log_endl;
842
[400]843  //
844  // Return 0 when the file is found in the current directory
845  //
[2]846  if (CmtSystem::test_file (name))
847    {
[427]848      full_name = name;
[78]849      return (0);
[2]850    }
851
[427]852  cmt_string p;
[2]853
[400]854  //
855  // Return 1 when the file is found in the directory of the
856  // upper level source file
857  //
[427]858  p = dir_name;
859  p += CmtSystem::file_separator ();
860  p += name;
861  if (CmtSystem::test_file (p))
[2]862    {
[427]863      full_name = p;
[78]864      return (1);
[2]865    }
866
[400]867  //
868  // Return [path_index + 2] when the include file is found at one of
869  // the include_paths
870  //
[427]871  for (int path_index = 0; path_index < include_paths.size (); path_index++)
[2]872    {
[427]873      p  = include_paths[path_index];
874      p += CmtSystem::file_separator ();
875      p += name;
[2]876
[427]877      log << "CMT> locate2 full_name=" << p << log_endl;
[2]878
[427]879      if (CmtSystem::test_file (p))
[2]880        {
[427]881          full_name = p;
[78]882          return (path_index + 2);
[2]883        }
884    }
885
[427]886  log << "CMT> locate3" << log_endl;
[2]887
888  return (-1);
889}
890
891//--------------------------------------------------------------------------
[588]892DepsBuilder::DepsBuilder ()
893{ }
894
895//--------------------------------------------------------------------------
896DepsBuilder::~DepsBuilder ()
897{
898  clear ();
899}
900
901//--------------------------------------------------------------------------
[2]902void DepsBuilder::clear ()
903{
904  m_include_paths.clear ();
905  m_substitutions.clear ();
[427]906  for (int i = m_header_filters.size () - 1; i >= 0; i--)
907    {
908      m_header_filters[i].clear ();
909    }
910  m_header_filters.clear ();
[588]911  m_deps.clear ();
912  m_all_deps.clear ();
[2]913}
914
915//--------------------------------------------------------------------------
916void DepsBuilder::add (const cmt_string& path, const cmt_string& substitution)
917{
[427]918  if (path.size () == 0)
919    {
920      return;
921    }
[588]922
923  cmt_string p = path;
[2]924  if (path[path.size () - 1] == CmtSystem::file_separator ())
925    {
[588]926      p = path.substr(0, path.size () - 1);
[2]927    }
[588]928  for (int k = m_include_paths.size () - 1; k >= 0; k--)
929    if (m_include_paths[k] == p)
930      {
931        return;
932      }
933 
934  m_include_paths.push_back (p);
[2]935  m_substitutions.push_back (substitution);
936}
937
938//--------------------------------------------------------------------------
939void DepsBuilder::add_includes (const Use& use)
940{
941  Log;
942
943  const Include::IncludeVector& includes = use.includes;
944  int include_number;
945
946  for (include_number = 0;
947       include_number < includes.size ();
948       include_number++)
949    {
950      const Include& include = includes[include_number];
951
952      cmt_string temp = include.name;
953      cmt_string pattern;
954      cmt_string name;
955      char end_pattern;
956
957      int start = 0;
958
959      for (;;)
960        {
961          int begin;
962
963          begin = temp.find (start, "${");
964          if (begin != cmt_string::npos)
965            {
966              end_pattern = '}';
967            }
968          else
969            {
970              begin = temp.find (start, "$(");
971              if (begin != cmt_string::npos)
972                {
973                  end_pattern = ')';
974                }
975              else
976                {
977                  break;
978                }
979            }
980
981          start = begin + 2;
982
983          int end;
984          end = temp.find (start, end_pattern);
985          if (end == cmt_string::npos) break;
986          if (end < begin) break;
987          start = end + 1;
988
989          temp.substr (begin, end - begin + 1, pattern);
990          temp.substr (begin + 2, end - begin - 2, name);
991
992          Symbol* macro = Symbol::find (name);
993          if (macro != 0)
994            {
995              cmt_string value = macro->resolve_macro_value ();
996              value += CmtSystem::file_separator ();
997              temp.replace_all (pattern, value);
998            }
999          else
1000            {
1001              cmt_string value = CmtSystem::getenv (name);
1002              value += CmtSystem::file_separator ();
1003              temp.replace_all (pattern, value);
1004            }
1005        }
1006
1007      log << "include = " << temp << log_endl;
1008
1009      add (temp, include.name);
1010    }
1011}
1012
1013//--------------------------------------------------------------------------
[588]1014CmtSystem::cmt_string_vector& DepsBuilder::run (const cmt_string& file_name,
1015                                                const cmt_string& constituent_name)
[2]1016{
[78]1017  Log;
1018
1019  log << "Starting deps builder on " << file_name << log_endl;
[588]1020  CmtMessage::info ("calculating dependencies for " + file_name);
[78]1021
[2]1022  m_deps.clear ();
1023  m_all_deps.clear ();
1024
1025  cmt_string preprocessor;
1026  Symbol* macro = Symbol::find ("preprocessor_command");
1027  if (macro != 0)
1028    {
1029      preprocessor = macro->resolve_macro_value ();
1030    }
1031
1032  if (preprocessor == "")
1033    {
[400]1034      //
1035      //   Since no preprocessor command is defined,
1036      // we use the internal mechanism provided here.
1037      //
[2]1038      cmt_string new_dir;
1039
1040      CmtSystem::dirname (file_name, new_dir);
1041
1042      build_deps (file_name,
1043                  new_dir,
1044                  0,
1045                  m_include_paths,
1046                  m_substitutions,
[427]1047                  m_header_filters,
[2]1048                  m_all_deps,
1049                  m_deps);
1050    }
1051  else
1052    {
[400]1053      //
1054      //  An external preprocessor command is defined. We expect it
1055      // to follow a "standard" syntax for its output, ie:
1056      //   o It starts with:
1057      //       <module>.o: ...
1058      //   o There may be many lines with trailing back-slashes
1059      //   o All entries are space-separated
1060      //   o One of the entries is the source file name itself
1061      //
1062      //  The preprocessor command expects the list of -I options
1063      // (resolved from the "includes" macro) and the list of
1064      // -D/-U options (resolved from the "*_pp_*flags" macros)
1065      //
[2]1066
[400]1067      //
1068      // Building the complete command (still the pp_*flags are
1069      // missing)
1070      //
[2]1071      macro = Symbol::find ("includes");
[588]1072      if (0 != macro)
1073        {
1074          preprocessor += " ";
1075          preprocessor += macro->resolve_macro_value ();
1076        }
1077      macro = Symbol::find ("app_" + constituent_name + "_cppflags");
1078      if (0 != macro)
1079        {
1080          preprocessor += " ";
1081          preprocessor += macro->resolve_macro_value ();
1082        }
1083      macro = Symbol::find ("lib_" + constituent_name + "_cppflags");
1084      if (0 != macro)
1085        {
1086          preprocessor += " ";
1087          preprocessor += macro->resolve_macro_value ();
1088        }
1089     
[2]1090      preprocessor += " ";
1091      preprocessor += file_name;
1092     
1093      cmt_string output;
1094     
[588]1095      int status = CmtSystem::execute (preprocessor, output);
1096      if (0 != status)
1097        {
1098          CmtError::set (CmtError::execution_failed, preprocessor, status);
1099          return m_deps;
1100        }
[2]1101
[400]1102      //
1103      // Make the output as one single big line.
1104      //
[2]1105
[399]1106      output.replace_all ("\n", " ");
1107      output.replace_all ("\\ ", " ");
[2]1108     
1109      CmtSystem::cmt_string_vector files;
1110     
[399]1111      CmtSystem::split (output, " \t", files);
[2]1112
[400]1113      //
1114      // Analyze each entry
1115      //
[2]1116     
1117      for (int i = 1; i < files.size (); i++)
1118        {
1119          const cmt_string& file = files[i];
1120          if (file == file_name) continue;
1121         
1122          cmt_string dir;
1123          cmt_string name;
1124          cmt_string full_name;
1125         
1126          CmtSystem::dirname (file, dir);
1127
[400]1128          //
1129          // Only declared include_paths will be taken into account
1130          // Others are considered as system include paths.
1131          //
[2]1132         
1133          for (int j = 0; j < m_include_paths.size (); j++)
1134            {
1135              const cmt_string& p = m_include_paths[j];
1136              if (dir == p)
1137                {
1138                  CmtSystem::basename (file, name);
1139                  full_name = m_substitutions[j];
1140                  full_name += name;
1141
[400]1142                  //
1143                  // We add in the "m_deps" list the symbolic form
1144                  // of the path rather that the expanded one.
1145                  //
[2]1146                 
1147                  m_deps.push_back (full_name);
1148                 
1149                  break;
1150                }
1151            }
1152        }
1153    }
1154
1155  return (m_deps);
1156}
1157
[427]1158//--------------------------------------------------------------------------
[588]1159void DepsBuilder::add_header_filter (const Use* use, cmt_regexp* filter, const cmt_string& stamp)
[427]1160{
1161  add_header_filter (HeaderFilter (use, filter, stamp));
1162}
1163
1164//--------------------------------------------------------------------------
1165void DepsBuilder::add_header_filter (const HeaderFilter& hf)
1166{
1167  m_header_filters.push_back (hf);
1168}
Note: See TracBrowser for help on using the repository browser.