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

Last change on this file since 588 was 588, checked in by rybkin, 13 years ago

See C.L. 465

  • Property svn:eol-style set to native
File size: 27.1 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", 13))
229    {
230      // fortran include statement
231
232      ptr += 13;
233
234      while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
235
236      if (*ptr == '\'')
237        {
238          term = '\'';
239          ptr++;
240        }
241      else
242        {
243          state = in_line;
244          return (ptr);
245        }
246    }
247  else if (!strncmp (ptr, "\tinclude", 8))
248    {
249      // fortran include statement
250
251      ptr += 8;
252
253      while ((*ptr == ' ') || (*ptr == '\t')) ptr++;
254
255      if (*ptr == '\'')
256        {
257          term = '\'';
258          ptr++;
259        }
260      else
261        {
262          state = in_line;
263          return (ptr);
264        }
265    }
266  else
267    {
268      state = in_line;
269      return (ptr);
270    }
271
272  // At this point we do have to include a header file.
273
274  char* end;
275
276  end = strchr (ptr, term);
277  if (end != 0)
278    {
279      *end = 0;
280    }
281 
282  const char* header_file = ptr;
283 
284  header_file_action (header_file,
285                      dir_name,
286                      current_path_index,
287                      include_paths,
288                      substitutions,
289                      header_filters,
290                      all_deps,
291                      deps);
292 
293  if (end != 0)
294    {
295      *end = term;
296    }
297
298  state = in_line;
299  ptr += strlen (ptr);
300 
301  return (ptr);
302}
303
304/**
305   Any line with no header inclusion
306   step through comments and strings
307*/
308static char* in_line_action (char* ptr, state_def& state)
309{
310  char* pattern = ptr + strlen (ptr);
311  int length = 0;
312
313  /*
314    search for the first occurrence of
315    {single-quote double-quote open-comment open-line-comment}
316
317    Must exclude escaped quotes \' and \"
318  */
319
320  char* pos = strchr (ptr, '"');
321  if ((pos != 0) && (pos < pattern) && (pos > ptr) && (*(pos-1) != '\\'))
322    {
323      state = in_string;
324      pattern = pos;
325      length = 1;
326    }
327
328  pos = strchr (ptr, '\'');
329  if ((pos != 0) && (pos < pattern) && (pos > ptr) && (*(pos-1) != '\\'))
330    {
331      state = in_char;
332      pattern = pos;
333      length = 1;
334    }
335
336  pos = strstr (ptr, "/*");   //*/
337  if ((pos != 0) && (pos < pattern))
338    {
339      state = in_comment;
340      pattern = pos;
341      length = 2;
342    }
343
344  pos = strstr (ptr, "//");
345  if ((pos != 0) && (pos < pattern))
346    {
347      state = in_line_comment;
348      pattern = pos;
349      length = 2;
350    }
351
352  ptr = pattern + length;
353
354  return (ptr);
355}
356
357//--------------------------------------------------
358static char* in_string_action (char* ptr, state_def& state)
359{
360  // we exclusively look for a double quote
361
362  char* pos = strchr (ptr, '"');
363  if (pos == 0)
364    {
365      // This string is not finished till the end of the line..
366      // we expect it to continue to the next line...
367      // thus we leave the state as it is
368      ptr += strlen (ptr);
369    }
370  else
371    {
372      if ((pos > ptr) && (*(pos - 1) == '\\'))
373        {
374          ptr = pos + 1;
375        }
376      else
377        {
378          ptr = pos + 1;
379          state = in_line;
380        }
381    }
382
383  return (ptr);
384}
385
386//--------------------------------------------------
387static char* in_char_action (char* ptr, state_def& state)
388{
389  // we exclusively look for a single quote
390
391  char* pos = strchr (ptr, '\'');
392  if (pos == 0)
393    {
394      // This string is not finished till the end of the line..
395      // we expect it continues to the nex line...
396      // thus we leave the state as it is
397      ptr += strlen (ptr);
398    }
399  else
400    {
401      if ((pos > ptr) && (*(pos - 1) == '\\'))
402        {
403          ptr = pos + 1;
404        }
405      else
406        {
407          ptr = pos + 1;
408          state = in_line;
409        }
410    }
411
412  return (ptr);
413}
414
415//--------------------------------------------------
416static char* in_comment_action (char* ptr, state_def& state)
417{
418  char* pattern = ptr + strlen (ptr);
419  int length    = 0;
420  char* pos;
421 
422
423  /*
424    Even if we are inside a comment, we must detect strings since comment markers may
425    be written inside them.
426 
427    pos = strchr (ptr, '"');
428 
429    if ((pos != 0) && (pos < pattern) && (pos > ptr) && (*(pos-1) != '\\'))
430    {
431    state = in_string_comment;
432    pattern = pos;
433    length = 1;
434    }
435
436    pos = strchr (ptr, '\'');
437    if ((pos != 0) && (pos < pattern) && (pos > ptr) && (*(pos-1) != '\\'))
438    {
439    state = in_char_comment;
440    pattern = pos;
441    length = 1;
442    }
443  */
444  pos = strstr (ptr, "*/");
445  if ((pos != 0) && (pos < pattern))
446    {
447      state   = in_line;
448      pattern = pos;
449      length  = 2;
450    }
451
452  ptr = pattern + length;
453
454  return (ptr);
455}
456
457//--------------------------------------------------
458static char* in_string_comment_action (char* ptr, state_def& state)
459{
460  char* pos = strchr (ptr, '"');
461  if (pos == 0)
462    {
463      // This string is not finished till the end of the line..
464      // we expect it continues to the nex line...
465      ptr += strlen (ptr);
466    }
467  else
468    {
469      if ((pos > ptr) && (*(pos - 1) == '\\'))
470        {
471          ptr = pos + 1;
472        }
473      else
474        {
475          ptr = pos + 1;
476          state = in_comment;
477        }
478    }
479
480  return (ptr);
481}
482
483//--------------------------------------------------
484static char* in_char_comment_action (char* ptr, state_def& state)
485{
486  char* pos = strchr (ptr, '\'');
487  if (pos == 0)
488    {
489      // This string is not finished till the end of the line..
490      // we expect it continues to the nex line...
491      ptr += strlen (ptr);
492    }
493  else
494    {
495      if ((pos > ptr) && (*(pos - 1) == '\\'))
496        {
497          ptr = pos + 1;
498        }
499      else
500        {
501          ptr = pos + 1;
502          state = in_comment;
503        }
504      pos--;
505    }
506
507  return (ptr);
508}
509
510//--------------------------------------------------
511static char* in_line_comment_action (char* ptr, state_def& state)
512{
513  char * pos = strchr (ptr, '\\'); 
514  /* Extend this part to deal with continuation character */ 
515  if ( (pos == NULL) || ( (ptr + strlen(ptr)-1)!=pos ))
516    {
517      state = in_line;
518    }
519 
520  ptr    += strlen (ptr);
521 
522  return (ptr);
523}
524
525//--------------------------------------------------
526static void build_deps_text (char* text,
527                             const cmt_string& dir_name,
528                             int current_path_index,
529                             const CmtSystem::cmt_string_vector& include_paths,
530                             const CmtSystem::cmt_string_vector& substitutions,
531                             const DepsBuilder::HeaderFilters& header_filters,
532                             CmtSystem::cmt_string_vector& all_deps,
533                             CmtSystem::cmt_string_vector& deps)
534{
535  Log;
536
537  int pos;
538  int max_pos;
539  int line_number = 1;
540
541  log << "CMT> build_deps_text dir_name="
542      << dir_name << log_endl;
543
544  // erase of continuation character
545  pos = 0;
546  max_pos = strlen (text);
547  char* current = text;
548
549  char* last = text + max_pos;
550  while (current < last)
551    {
552   
553      //  bscrnl -> BackSlash Carriage Return New Line
554      //  bsnl -> BackSlash New Line
555      char* bscrnl = strstr (current, "\\\r\n");
556      char* bsnl   = strstr (current, "\\\n");
557     
558      if ( (bscrnl==0) && (bsnl ==0)) break;
559     
560      int length = 0;
561           
562      char * ptr = 0;
563      if (bsnl==0)  //bscrnl > 0
564        {
565          length = 3;
566          ptr    = bscrnl; 
567        }     
568      else if (bscrnl==0) //bsnl > 0
569        {
570          length = 2;                       
571          ptr    = bsnl; 
572        }     
573      else if (bscrnl < bsnl)
574        {
575          length = 3;
576          ptr    = bscrnl;                 
577        }
578      else // (bscrnl > bsnl)
579        {
580          length = 2;                       
581          ptr    = bsnl;         
582        }
583      strcpy (ptr, ptr+length);
584      current = ptr;
585      last -= length;
586    } 
587 
588  pos = 0;
589  max_pos = strlen (text);
590  current = text;
591  last = text + max_pos;
592
593  state_def state = at_start;
594 
595
596  while (current < last)
597    {
598             
599      char marker;
600      char* marker_pos = 0;
601
602      //  crnl -> Carriage Return New Line
603      //  nl -> New Line
604      char* crnl = strstr (current, "\r\n");
605      char* nl = strchr (current, '\n');
606
607      char* first = nl;
608      int length = 1;
609
610      char* ptr = 0;
611
612      if (crnl != 0)
613        {
614          // cr+nl has been found
615
616          if (nl == 0)
617            {
618              // cr but no nl ??
619              first = crnl;
620              length = 2;
621            }
622          else
623            {
624              // both cr+nl and nl found
625              first = (nl < crnl) ? nl : crnl;
626              length = (nl < crnl) ? 1 : 2;
627            }
628        }
629      else
630        {
631          // no cr+nl but nl alone found
632          first = nl;
633          length = 1;
634        }
635
636      ptr = current;
637
638      if (first == 0)
639        {
640          // neither nl nor cr+nl found => this is the last line
641          marker_pos = 0;
642        }
643      else
644        {
645          marker_pos = first;
646          marker = *marker_pos;
647          *marker_pos = 0;
648        }
649
650      log << "CMT> build_deps_text2 line=[" 
651          << current << "]" << log_endl;
652     
653      while (strlen (ptr) > 0)
654        {
655          switch (state)
656            {
657            case at_start:
658              ptr = at_start_action (ptr,
659                                     state,
660                                     dir_name,
661                                     current_path_index,
662                                     include_paths,
663                                     substitutions,
664                                     header_filters,
665                                     all_deps,
666                                     deps);
667              break;
668            case in_line:
669              ptr = in_line_action (ptr, state);
670              break;
671            case in_string:
672              ptr = in_string_action (ptr, state);
673              break;
674            case in_char:
675              ptr = in_char_action (ptr, state);
676              break;
677            case in_comment:
678              ptr = in_comment_action (ptr, state);
679              break;
680            case in_string_comment:
681              ptr = in_string_comment_action (ptr, state);
682              break;
683            case in_char_comment:
684              ptr = in_char_comment_action (ptr, state);
685              break;
686            case in_line_comment:
687              ptr = in_line_comment_action (ptr, state);
688              break;
689            }
690        }
691
692      if (state == in_line) state = at_start;
693      line_number++;
694
695      if (marker_pos != 0)
696        {
697          *marker_pos = marker;
698          current = marker_pos + length;
699        }
700      else
701        {
702          break;
703        }
704    }
705           
706}
707
708//--------------------------------------------------
709static int build_deps (const cmt_string& name,
710                       const cmt_string& dir_name,
711                       int current_path_index,
712                       const CmtSystem::cmt_string_vector& include_paths,
713                       const CmtSystem::cmt_string_vector& substitutions,
714                       const DepsBuilder::HeaderFilters& header_filters,
715                       CmtSystem::cmt_string_vector& all_deps,
716                       CmtSystem::cmt_string_vector& deps)
717{
718  Log;
719
720  log << "CMT> build_deps name=" << name << " dir_name=" 
721      << dir_name << log_endl;
722
723  cmt_string full_name;
724  int path_index = locate (name,
725                           dir_name,
726                           include_paths,
727                           substitutions,
728                           full_name);
729
730  if (path_index >= 0)
731    {
732      cmt_string text;
733      if (!text.read (full_name))
734        {
735          CmtError::set (CmtError::file_access_error, full_name);
736          return -2;
737        }
738      char* ptr = &text[0];
739      cmt_string new_dir;
740      CmtSystem::dirname (full_name, new_dir);
741
742      if (path_index == 0 || path_index == 1)
743        build_deps_text (ptr, new_dir,
744                         current_path_index,
745                         include_paths, substitutions,
746                         header_filters,
747                         all_deps, deps);
748      else
749        build_deps_text (ptr, new_dir,
750                         path_index,
751                         include_paths, substitutions,
752                         header_filters,
753                         all_deps, deps);
754    }
755  if (path_index < 0)
756    {
757      log << "CMT> build_deps3" << log_endl;
758      CmtError::set (CmtError::path_not_found, name);
759    }
760  return path_index;
761}
762
763//--------------------------------------------------
764static int locate (const cmt_string& name,
765                   const cmt_string& dir_name,
766                   const CmtSystem::cmt_string_vector& include_paths,
767                   const CmtSystem::cmt_string_vector& substitutions,
768                   cmt_string& full_name)
769{
770  Log;
771
772  log << "CMT> locate name=" << name << " dir_name=" 
773      << dir_name << log_endl;
774
775  //
776  // Return 0 when the file is found in the current directory
777  //
778  if (CmtSystem::test_file (name))
779    {
780      full_name = name;
781      return (0);
782    }
783
784  cmt_string p;
785
786  //
787  // Return 1 when the file is found in the directory of the
788  // upper level source file
789  //
790  p = dir_name;
791  p += CmtSystem::file_separator ();
792  p += name;
793  if (CmtSystem::test_file (p))
794    {
795      full_name = p;
796      return (1);
797    }
798
799  //
800  // Return [path_index + 2] when the include file is found at one of
801  // the include_paths
802  //
803  for (int path_index = 0; path_index < include_paths.size (); path_index++)
804    {
805      p  = include_paths[path_index];
806      p += CmtSystem::file_separator ();
807      p += name;
808
809      log << "CMT> locate2 full_name=" << p << log_endl;
810
811      if (CmtSystem::test_file (p))
812        {
813          full_name = p;
814          return (path_index + 2);
815        }
816    }
817
818  log << "CMT> locate3" << log_endl;
819
820  return (-1);
821}
822
823//--------------------------------------------------------------------------
824DepsBuilder::DepsBuilder ()
825{ }
826
827//--------------------------------------------------------------------------
828DepsBuilder::~DepsBuilder ()
829{
830  clear ();
831}
832
833//--------------------------------------------------------------------------
834void DepsBuilder::clear ()
835{
836  m_include_paths.clear ();
837  m_substitutions.clear ();
838  for (int i = m_header_filters.size () - 1; i >= 0; i--)
839    {
840      m_header_filters[i].clear ();
841    }
842  m_header_filters.clear ();
843  m_deps.clear ();
844  m_all_deps.clear ();
845}
846
847//--------------------------------------------------------------------------
848void DepsBuilder::add (const cmt_string& path, const cmt_string& substitution)
849{
850  if (path.size () == 0)
851    {
852      return;
853    }
854
855  cmt_string p = path;
856  if (path[path.size () - 1] == CmtSystem::file_separator ())
857    {
858      p = path.substr(0, path.size () - 1);
859    }
860  for (int k = m_include_paths.size () - 1; k >= 0; k--)
861    if (m_include_paths[k] == p)
862      {
863        return;
864      }
865 
866  m_include_paths.push_back (p);
867  m_substitutions.push_back (substitution);
868}
869
870//--------------------------------------------------------------------------
871void DepsBuilder::add_includes (const Use& use)
872{
873  Log;
874
875  const Include::IncludeVector& includes = use.includes;
876  int include_number;
877
878  for (include_number = 0;
879       include_number < includes.size ();
880       include_number++)
881    {
882      const Include& include = includes[include_number];
883
884      cmt_string temp = include.name;
885      cmt_string pattern;
886      cmt_string name;
887      char end_pattern;
888
889      int start = 0;
890
891      for (;;)
892        {
893          int begin;
894
895          begin = temp.find (start, "${");
896          if (begin != cmt_string::npos)
897            {
898              end_pattern = '}';
899            }
900          else
901            {
902              begin = temp.find (start, "$(");
903              if (begin != cmt_string::npos)
904                {
905                  end_pattern = ')';
906                }
907              else
908                {
909                  break;
910                }
911            }
912
913          start = begin + 2;
914
915          int end;
916          end = temp.find (start, end_pattern);
917          if (end == cmt_string::npos) break;
918          if (end < begin) break;
919          start = end + 1;
920
921          temp.substr (begin, end - begin + 1, pattern);
922          temp.substr (begin + 2, end - begin - 2, name);
923
924          Symbol* macro = Symbol::find (name);
925          if (macro != 0)
926            {
927              cmt_string value = macro->resolve_macro_value ();
928              value += CmtSystem::file_separator ();
929              temp.replace_all (pattern, value);
930            }
931          else
932            {
933              cmt_string value = CmtSystem::getenv (name);
934              value += CmtSystem::file_separator ();
935              temp.replace_all (pattern, value);
936            }
937        }
938
939      log << "include = " << temp << log_endl;
940
941      add (temp, include.name);
942    }
943}
944
945//--------------------------------------------------------------------------
946CmtSystem::cmt_string_vector& DepsBuilder::run (const cmt_string& file_name,
947                                                const cmt_string& constituent_name)
948{
949  Log;
950
951  log << "Starting deps builder on " << file_name << log_endl;
952  CmtMessage::info ("calculating dependencies for " + file_name);
953
954  m_deps.clear ();
955  m_all_deps.clear ();
956
957  cmt_string preprocessor;
958  Symbol* macro = Symbol::find ("preprocessor_command");
959  if (macro != 0)
960    {
961      preprocessor = macro->resolve_macro_value ();
962    }
963
964  if (preprocessor == "")
965    {
966      //
967      //   Since no preprocessor command is defined,
968      // we use the internal mechanism provided here.
969      //
970      cmt_string new_dir;
971
972      CmtSystem::dirname (file_name, new_dir);
973
974      build_deps (file_name,
975                  new_dir,
976                  0,
977                  m_include_paths,
978                  m_substitutions,
979                  m_header_filters,
980                  m_all_deps,
981                  m_deps);
982    }
983  else
984    {
985      //
986      //  An external preprocessor command is defined. We expect it
987      // to follow a "standard" syntax for its output, ie:
988      //   o It starts with:
989      //       <module>.o: ...
990      //   o There may be many lines with trailing back-slashes
991      //   o All entries are space-separated
992      //   o One of the entries is the source file name itself
993      //
994      //  The preprocessor command expects the list of -I options
995      // (resolved from the "includes" macro) and the list of
996      // -D/-U options (resolved from the "*_pp_*flags" macros)
997      //
998
999      //
1000      // Building the complete command (still the pp_*flags are
1001      // missing)
1002      //
1003      macro = Symbol::find ("includes");
1004      if (0 != macro)
1005        {
1006          preprocessor += " ";
1007          preprocessor += macro->resolve_macro_value ();
1008        }
1009      macro = Symbol::find ("app_" + constituent_name + "_cppflags");
1010      if (0 != macro)
1011        {
1012          preprocessor += " ";
1013          preprocessor += macro->resolve_macro_value ();
1014        }
1015      macro = Symbol::find ("lib_" + constituent_name + "_cppflags");
1016      if (0 != macro)
1017        {
1018          preprocessor += " ";
1019          preprocessor += macro->resolve_macro_value ();
1020        }
1021     
1022      preprocessor += " ";
1023      preprocessor += file_name;
1024     
1025      cmt_string output;
1026     
1027      int status = CmtSystem::execute (preprocessor, output);
1028      if (0 != status)
1029        {
1030          CmtError::set (CmtError::execution_failed, preprocessor, status);
1031          return m_deps;
1032        }
1033
1034      //
1035      // Make the output as one single big line.
1036      //
1037
1038      output.replace_all ("\n", " ");
1039      output.replace_all ("\\ ", " ");
1040     
1041      CmtSystem::cmt_string_vector files;
1042     
1043      CmtSystem::split (output, " \t", files);
1044
1045      //
1046      // Analyze each entry
1047      //
1048     
1049      for (int i = 1; i < files.size (); i++)
1050        {
1051          const cmt_string& file = files[i];
1052          if (file == file_name) continue;
1053         
1054          cmt_string dir;
1055          cmt_string name;
1056          cmt_string full_name;
1057         
1058          CmtSystem::dirname (file, dir);
1059
1060          //
1061          // Only declared include_paths will be taken into account
1062          // Others are considered as system include paths.
1063          //
1064         
1065          for (int j = 0; j < m_include_paths.size (); j++)
1066            {
1067              const cmt_string& p = m_include_paths[j];
1068              if (dir == p)
1069                {
1070                  CmtSystem::basename (file, name);
1071                  full_name = m_substitutions[j];
1072                  full_name += name;
1073
1074                  //
1075                  // We add in the "m_deps" list the symbolic form
1076                  // of the path rather that the expanded one.
1077                  //
1078                 
1079                  m_deps.push_back (full_name);
1080                 
1081                  break;
1082                }
1083            }
1084        }
1085    }
1086
1087  return (m_deps);
1088}
1089
1090//--------------------------------------------------------------------------
1091void DepsBuilder::add_header_filter (const Use* use, cmt_regexp* filter, const cmt_string& stamp)
1092{
1093  add_header_filter (HeaderFilter (use, filter, stamp));
1094}
1095
1096//--------------------------------------------------------------------------
1097void DepsBuilder::add_header_filter (const HeaderFilter& hf)
1098{
1099  m_header_filters.push_back (hf);
1100}
Note: See TracBrowser for help on using the repository browser.