3 Copyright (c) 2004, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Recursively scan source files to find include files and emit them to
19 create dependency lists.
29 #include <UefiBaseTypes.h>
30 #include "EfiUtilityMsgs.h"
31 #include <CommonLib.h>
34 // Structure to maintain a linked list of strings
36 typedef struct _STRING_LIST
{
37 struct _STRING_LIST
*Next
;
41 #define UTILITY_NAME "MakeDeps"
43 #define MAX_LINE_LEN 2048
45 #define START_NEST_DEPTH 1
46 #define MAX_NEST_DEPTH 1000 // just in case we get in an endless loop.
48 // Define the relative paths used by the special #include macros
50 #define PROTOCOL_DIR_PATH "Protocol\\"
51 #define GUID_DIR_PATH "Guid\\"
52 #define ARCH_PROTOCOL_DIR_PATH "ArchProtocol\\"
53 #define PPI_PROTOCOL_DIR_PATH "Ppi\\"
56 // Use this structure to keep track of all the special #include forms
59 INT8
*IncludeMacroName
;
61 } INCLUDE_MACRO_CONVERSION
;
64 // This data is used to convert #include macros like:
65 // #include EFI_PROTOCOL_DEFINITION(xxx)
67 // #include Protocol/xxx/xxx.h
69 static const INCLUDE_MACRO_CONVERSION mMacroConversion
[] = {
70 "EFI_PROTOCOL_DEFINITION",
72 "EFI_GUID_DEFINITION",
74 "EFI_ARCH_PROTOCOL_DEFINITION",
75 ARCH_PROTOCOL_DIR_PATH
,
76 "EFI_PROTOCOL_PRODUCER",
78 "EFI_PROTOCOL_CONSUMER",
80 "EFI_PROTOCOL_DEPENDENCY",
82 "EFI_ARCH_PROTOCOL_PRODUCER",
83 ARCH_PROTOCOL_DIR_PATH
,
84 "EFI_ARCH_PROTOCOL_CONSUMER",
85 ARCH_PROTOCOL_DIR_PATH
,
86 "EFI_ARCH_PROTOCOL_DEPENDENCY",
87 ARCH_PROTOCOL_DIR_PATH
,
89 PPI_PROTOCOL_DIR_PATH
,
91 PPI_PROTOCOL_DIR_PATH
,
93 PPI_PROTOCOL_DIR_PATH
,
95 PPI_PROTOCOL_DIR_PATH
,
100 typedef struct _SYMBOL
{
101 struct _SYMBOL
*Next
;
107 // Here's all our globals. We need a linked list of include paths, a linked
108 // list of source files, a linked list of subdirectories (appended to each
109 // include path when searching), and flags to keep track of command-line options.
112 STRING_LIST
*IncludePaths
; // all include paths to search
113 STRING_LIST
*SourceFiles
; // all source files to parse
114 STRING_LIST
*SubDirs
; // appended to each include path when searching
115 SYMBOL
*SymbolTable
; // for replacement strings
116 FILE *OutFptr
; // output dependencies to this file
117 BOOLEAN Verbose
; // for more detailed output
118 BOOLEAN IgnoreNotFound
; // no warnings if files not found
119 BOOLEAN QuietMode
; // -q - don't print missing file warnings
120 BOOLEAN NoSystem
; // don't process #include <system> files
121 BOOLEAN NeverFail
; // always return success
122 BOOLEAN NoDupes
; // to not list duplicate dependency files (for timing purposes)
123 BOOLEAN UseSumDeps
; // use summary dependency files if found
124 INT8 TargetFileName
[MAX_PATH
]; // target object filename
125 INT8 SumDepsPath
[MAX_PATH
]; // path to summary files
126 INT8
*OutFileName
; // -o option
132 INT8
*TargetFileName
,
135 STRING_LIST
*ProcessedFiles
187 Call the routine to parse the command-line options, then process each file
188 to build dependencies.
192 Argc - Standard C main() argc.
193 Argv - Standard C main() argv.
203 STRING_LIST ProcessedFiles
;
204 STRING_LIST
*TempList
;
207 INT8 TargetFileName
[MAX_PATH
];
209 SetUtilityName (UTILITY_NAME
);
211 // Process the command-line arguments
213 Status
= ProcessArgs (Argc
, Argv
);
214 if (Status
!= STATUS_SUCCESS
) {
218 // Go through the list of source files and process each.
220 memset (&ProcessedFiles
, 0, sizeof (STRING_LIST
));
221 File
= mGlobals
.SourceFiles
;
222 while (File
!= NULL
) {
224 // Clear out our list of processed files
226 TempList
= ProcessedFiles
.Next
;
227 while (ProcessedFiles
.Next
!= NULL
) {
228 TempList
= ProcessedFiles
.Next
->Next
;
229 free (ProcessedFiles
.Next
->Str
);
230 free (ProcessedFiles
.Next
);
231 ProcessedFiles
.Next
= TempList
;
234 // Replace filename extension with ".obj" if they did not
235 // specifically specify the target file
237 if (mGlobals
.TargetFileName
[0] == 0) {
238 strcpy (TargetFileName
, File
->Str
);
240 // Find the .extension
242 for (Cptr
= TargetFileName
+ strlen (TargetFileName
) - 1;
243 (*Cptr
!= '\\') && (Cptr
> TargetFileName
) && (*Cptr
!= '.');
247 if (Cptr
== TargetFileName
) {
248 Error (NULL
, 0, 0, File
->Str
, "could not locate extension in filename");
252 // Tack on the ".obj"
254 strcpy (Cptr
, ".obj");
257 // Copy the target filename they specified
259 strcpy (TargetFileName
, mGlobals
.TargetFileName
);
262 Status
= ProcessFile (TargetFileName
, File
->Str
, START_NEST_DEPTH
, &ProcessedFiles
);
263 if (Status
!= STATUS_SUCCESS
) {
276 // Free up our processed files list
278 TempList
= ProcessedFiles
.Next
;
279 while (ProcessedFiles
.Next
!= NULL
) {
280 TempList
= ProcessedFiles
.Next
->Next
;
281 free (ProcessedFiles
.Next
->Str
);
282 free (ProcessedFiles
.Next
);
283 ProcessedFiles
.Next
= TempList
;
286 // Close our output file
288 if ((mGlobals
.OutFptr
!= stdout
) && (mGlobals
.OutFptr
!= NULL
)) {
289 fclose (mGlobals
.OutFptr
);
292 if (mGlobals
.NeverFail
) {
293 return STATUS_SUCCESS
;
296 // If any errors, then delete our output so that it will get created
297 // again on a rebuild.
299 if ((GetUtilityStatus () == STATUS_ERROR
) && (mGlobals
.OutFileName
!= NULL
)) {
300 remove (mGlobals
.OutFileName
);
303 return GetUtilityStatus ();
309 INT8
*TargetFileName
,
312 STRING_LIST
*ProcessedFiles
318 Given a source file name, open the file and parse all #include lines.
322 TargetFileName - name of the usually .obj target
323 FileName - name of the file to process
324 NestDepth - how deep we're nested in includes
325 ProcessedFiles - list of processed files.
334 INT8 Line
[MAX_LINE_LEN
];
339 INT8 FileNameCopy
[MAX_PATH
];
340 INT8 MacroIncludeFileName
[MAX_LINE_LEN
];
341 INT8 SumDepsFile
[MAX_PATH
];
345 STRING_LIST
*ListPtr
;
347 Status
= STATUS_SUCCESS
;
350 // Print the file being processed. Indent so you can tell the include nesting
353 if (mGlobals
.Verbose
) {
354 fprintf (stdout
, "%*cProcessing file '%s'\n", NestDepth
* 2, ' ', FileName
);
357 // If we're using summary dependency files, and a matching .dep file is
358 // found for this file, then just emit the summary dependency file as
359 // a dependency and return.
361 if (mGlobals
.UseSumDeps
) {
362 strcpy (SumDepsFile
, mGlobals
.SumDepsPath
);
363 strcat (SumDepsFile
, FileName
);
364 for (Cptr
= SumDepsFile
+ strlen (SumDepsFile
) - 1;
365 (*Cptr
!= '\\') && (Cptr
> SumDepsFile
) && (*Cptr
!= '.');
370 strcpy (Cptr
, ".dep");
372 strcat (SumDepsFile
, ".dep");
375 // See if the summary dep file exists. Could use _stat() function, but
376 // it's less portable.
378 if ((Fptr
= fopen (SumDepsFile
, "r")) != NULL
) {
379 PrintDependency (TargetFileName
, SumDepsFile
);
380 return STATUS_SUCCESS
;
384 // If we're not doing duplicates, and we've already seen this filename,
387 if (mGlobals
.NoDupes
) {
388 for (ListPtr
= ProcessedFiles
->Next
; ListPtr
!= NULL
; ListPtr
= ListPtr
->Next
) {
389 if (stricmp (FileName
, ListPtr
->Str
) == 0) {
394 // If we found a match, we're done. If we didn't, create a new element
395 // and add it to the list.
397 if (ListPtr
!= NULL
) {
399 // Print a message if verbose mode
401 if (mGlobals
.Verbose
) {
402 DebugMsg (NULL
, 0, 0, FileName
, "duplicate include -- not processed again");
405 return STATUS_SUCCESS
;
408 ListPtr
= malloc (sizeof (STRING_LIST
));
409 ListPtr
->Str
= malloc (strlen (FileName
) + 1);
410 strcpy (ListPtr
->Str
, FileName
);
411 ListPtr
->Next
= ProcessedFiles
->Next
;
412 ProcessedFiles
->Next
= ListPtr
;
416 // Make sure we didn't exceed our maximum nesting depth
418 if (NestDepth
> MAX_NEST_DEPTH
) {
419 Error (NULL
, 0, 0, FileName
, "max nesting depth exceeded on file");
423 // Make a local copy of the filename. Then we can manipulate it
426 strcpy (FileNameCopy
, FileName
);
428 // Try to open the file locally
430 if ((Fptr
= fopen (FileNameCopy
, "r")) == NULL
) {
432 // Try to find it among the paths.
434 Fptr
= FindFile (FileNameCopy
, sizeof (FileNameCopy
));
437 // If this is not the top-level file, and the command-line argument
438 // said to ignore missing files, then return ok
440 if (NestDepth
!= START_NEST_DEPTH
) {
441 if (mGlobals
.IgnoreNotFound
) {
442 if (!mGlobals
.QuietMode
) {
443 DebugMsg (NULL
, 0, 0, FileNameCopy
, "could not find file");
446 return STATUS_SUCCESS
;
448 Error (NULL
, 0, 0, FileNameCopy
, "could not find file");
453 // Top-level (first) file. Emit an error.
455 Error (NULL
, 0, 0, FileNameCopy
, "could not find file");
461 // Print the dependency, with string substitution
463 PrintDependency (TargetFileName
, FileNameCopy
);
466 // Now read in lines and find all #include lines. Allow them to indent, and
467 // to put spaces between the # and include.
470 while ((fgets (Line
, sizeof (Line
), Fptr
) != NULL
) && (Status
== STATUS_SUCCESS
)) {
474 // Skip preceeding spaces on the line
476 while (*Cptr
&& (isspace (*Cptr
))) {
480 // Check for # character
485 // Check for "include"
487 while (*Cptr
&& (isspace (*Cptr
))) {
491 if (strncmp (Cptr
, "include", 7) == 0) {
493 // Skip over "include" and move on to filename as "file" or <file>
496 while (*Cptr
&& (isspace (*Cptr
))) {
502 } else if (*Cptr
== '"') {
506 // Handle special #include MACRO_NAME(file)
507 // Set EndChar to null so we fall through on processing below.
511 // Look for all the special include macros and convert accordingly.
513 for (Index
= 0; mMacroConversion
[Index
].IncludeMacroName
!= NULL
; Index
++) {
515 // Save the start of the string in case some macros are substrings
521 mMacroConversion
[Index
].IncludeMacroName
,
522 strlen (mMacroConversion
[Index
].IncludeMacroName
)
525 // Skip over the macro name
527 Cptr
+= strlen (mMacroConversion
[Index
].IncludeMacroName
);
529 // Skip over open parenthesis, blank spaces, then find closing
530 // parenthesis or blank space
532 while (*Cptr
&& (isspace (*Cptr
))) {
538 while (*Cptr
&& (isspace (*Cptr
))) {
543 while (*EndPtr
&& !isspace (*EndPtr
) && (*EndPtr
!= ')')) {
551 strcpy (MacroIncludeFileName
, mMacroConversion
[Index
].PathName
);
552 strcat (MacroIncludeFileName
, Cptr
);
553 strcat (MacroIncludeFileName
, "\\");
554 strcat (MacroIncludeFileName
, Cptr
);
555 strcat (MacroIncludeFileName
, ".h");
557 // Process immediately, then break out of the outside FOR loop.
559 Status
= ProcessFile (TargetFileName
, MacroIncludeFileName
, NestDepth
+ 1, ProcessedFiles
);
569 // Don't recognize the include line? Ignore it. We assume that the
570 // file compiles anyway.
572 if (mMacroConversion
[Index
].IncludeMacroName
== NULL
) {
574 // Warning (FileNameCopy, LineNum, 0, "could not parse line", NULL);
575 // Status = STATUS_WARNING;
580 // Process "normal" includes. If the endchar is 0, then the
581 // file has already been processed. Otherwise look for the
582 // endchar > or ", and process the include file.
587 while (*EndPtr
&& (*EndPtr
!= EndChar
)) {
591 if (*EndPtr
== EndChar
) {
593 // If we're processing it, do it
595 if ((EndChar
!= '>') || (!mGlobals
.NoSystem
)) {
597 // Null terminate the filename and try to process it.
600 Status
= ProcessFile (TargetFileName
, Cptr
, NestDepth
+ 1, ProcessedFiles
);
603 Warning (FileNameCopy
, LineNum
, 0, "malformed include", "missing closing %c", EndChar
);
604 Status
= STATUS_WARNING
;
614 // Close open files and return status
626 INT8
*TargetFileName
,
633 Given a target (.obj) file name, and a dependent file name, do any string
634 substitutions (per the command line options) on the file names, then
635 print the dependency line of form:
637 TargetFileName : DependentFile
641 TargetFileName - build target file name
642 DependentFile - file on which TargetFileName depends
653 // Go through the symbols and do replacements
655 strcpy (Str
, TargetFileName
);
656 ReplaceSymbols (Str
, sizeof (Str
));
657 fprintf (mGlobals
.OutFptr
, "%s : ", Str
);
658 strcpy (Str
, DependentFile
);
659 ReplaceSymbols (Str
, sizeof (Str
));
660 fprintf (mGlobals
.OutFptr
, "%s\n", Str
);
671 INT8 StrCopy
[MAX_LINE_LEN
];
677 // Go through the entire string to look for replacement strings at
684 // Copy the character
689 // Go through each symbol and try to find a string substitution
691 Sym
= mGlobals
.SymbolTable
;
692 while (Sym
!= NULL
) {
693 if (strnicmp (From
, Sym
->Value
, strlen (Sym
->Value
)) == 0) {
695 // Replace the string, then advance the pointers past the
698 strcpy (To
, Sym
->Name
);
699 To
+= strlen (Sym
->Name
);
700 From
+= strlen (Sym
->Value
);
703 // Break from the while()
717 // Null terminate, and return it
720 if (strlen (StrCopy
) < StrSize
) {
721 strcpy (Str
, StrCopy
);
725 // Given a filename, try to find it along the include paths.
737 INT8 FullFileName
[MAX_PATH
* 2];
740 // Traverse the list of paths and try to find the file
742 List
= mGlobals
.IncludePaths
;
743 while (List
!= NULL
) {
745 // Put the path and filename together
747 if (strlen (List
->Str
) + strlen (FileName
) + 1 > sizeof (FullFileName
)) {
753 "cannot concatenate '%s' + '%s'",
760 // Append the filename to this include path and try to open the file.
762 strcpy (FullFileName
, List
->Str
);
763 strcat (FullFileName
, FileName
);
764 if ((Fptr
= fopen (FullFileName
, "r")) != NULL
) {
766 // Return the file name
768 if (FileNameLen
<= strlen (FullFileName
)) {
769 Error (__FILE__
, __LINE__
, 0, "application error", "internal path name of insufficient length");
771 // fprintf (stdout, "File length > %d: %s\n", FileNameLen, FullFileName);
776 strcpy (FileName
, FullFileName
);
780 // Didn't find it there. Now try this directory with every subdirectory
781 // the user specified on the command line
783 for (SubDir
= mGlobals
.SubDirs
; SubDir
!= NULL
; SubDir
= SubDir
->Next
) {
784 strcpy (FullFileName
, List
->Str
);
785 strcat (FullFileName
, SubDir
->Str
);
786 strcat (FullFileName
, FileName
);
787 if ((Fptr
= fopen (FullFileName
, "r")) != NULL
) {
789 // Return the file name
791 if (FileNameLen
<= strlen (FullFileName
)) {
792 Error (__FILE__
, __LINE__
, 0, "application error", "internal path name of insufficient length");
796 strcpy (FileName
, FullFileName
);
809 // Process the command-line arguments
818 STRING_LIST
*NewList
;
819 STRING_LIST
*LastIncludePath
;
820 STRING_LIST
*LastSourceFile
;
826 memset ((char *) &mGlobals
, 0, sizeof (mGlobals
));
827 mGlobals
.NoDupes
= TRUE
;
836 LastIncludePath
= NULL
;
837 LastSourceFile
= NULL
;
839 // Process until no more args
843 // -i path add include search path
845 if (stricmp (Argv
[0], "-i") == 0) {
847 // check for one more arg
851 // Allocate memory for a new list element, fill it in, and
852 // add it to our list of include paths. Always make sure it
853 // has a "\" on the end of it.
855 NewList
= malloc (sizeof (STRING_LIST
));
856 if (NewList
== NULL
) {
857 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
861 NewList
->Next
= NULL
;
862 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
863 if (NewList
->Str
== NULL
) {
865 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
869 strcpy (NewList
->Str
, Argv
[1]);
870 if (NewList
->Str
[strlen (NewList
->Str
) - 1] != '\\') {
871 strcat (NewList
->Str
, "\\");
874 // Add it to the end of the our list of include paths
876 if (mGlobals
.IncludePaths
== NULL
) {
877 mGlobals
.IncludePaths
= NewList
;
879 LastIncludePath
->Next
= NewList
;
882 LastIncludePath
= NewList
;
884 // fprintf (stdout, "Added path: %s\n", NewList->Str);
887 Error (NULL
, 0, 0, Argv
[0], "option requires an include path");
894 } else if (stricmp (Argv
[0], "-f") == 0) {
896 // Check for one more arg
900 // Allocate memory for a new list element, fill it in, and
901 // add it to our list of source files.
903 NewList
= malloc (sizeof (STRING_LIST
));
904 if (NewList
== NULL
) {
905 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
909 NewList
->Next
= NULL
;
911 // Allocate space to replace ".c" with ".obj", plus null termination
913 NewList
->Str
= malloc (strlen (Argv
[1]) + 5);
914 if (NewList
->Str
== NULL
) {
916 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
920 strcpy (NewList
->Str
, Argv
[1]);
921 if (mGlobals
.SourceFiles
== NULL
) {
922 mGlobals
.SourceFiles
= NewList
;
924 LastSourceFile
->Next
= NewList
;
927 LastSourceFile
= NewList
;
929 Error (NULL
, 0, 0, Argv
[0], "option requires a file name");
934 // The C compiler first looks for #include files in the directory where
935 // the source file came from. Add the file's source directory to the
936 // list of include paths.
938 NewList
= malloc (sizeof (STRING_LIST
));
939 if (NewList
== NULL
) {
940 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
944 NewList
->Next
= NULL
;
945 NewList
->Str
= malloc (strlen (Argv
[1]) + 3);
946 if (NewList
->Str
== NULL
) {
948 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
952 strcpy (NewList
->Str
, Argv
[1]);
954 // Back up in the source file name to the last backslash and terminate after it.
956 for (Index
= strlen (NewList
->Str
) - 1; (Index
> 0) && (NewList
->Str
[Index
] != '\\'); Index
--)
959 strcpy (NewList
->Str
, ".\\");
961 NewList
->Str
[Index
+ 1] = 0;
964 // Add it to the end of the our list of include paths
966 if (mGlobals
.IncludePaths
== NULL
) {
967 mGlobals
.IncludePaths
= NewList
;
969 LastIncludePath
->Next
= NewList
;
972 if (mGlobals
.Verbose
) {
973 fprintf (stdout
, "Adding include path: %s\n", NewList
->Str
);
976 LastIncludePath
= NewList
;
979 } else if (stricmp (Argv
[0], "-s") == 0) {
981 // -s subdir add subdirectory subdir to list of subdirecties to scan.
982 // Check for one more arg first.
986 // Allocate memory for a new list element, fill it in, and
987 // add it to our list of subdirectory include paths. Always
988 // make sure it has a "\" on the end of it.
990 NewList
= malloc (sizeof (STRING_LIST
));
991 if (NewList
== NULL
) {
992 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
996 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
997 if (NewList
->Str
== NULL
) {
999 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1000 return STATUS_ERROR
;
1003 strcpy (NewList
->Str
, Argv
[1]);
1004 if (NewList
->Str
[strlen (NewList
->Str
) - 1] != '\\') {
1005 strcat (NewList
->Str
, "\\");
1008 NewList
->Next
= mGlobals
.SubDirs
;
1009 mGlobals
.SubDirs
= NewList
;
1011 Error (NULL
, 0, 0, Argv
[0], "option requires a subdirectory name");
1013 return STATUS_ERROR
;
1018 } else if (stricmp (Argv
[0], "-sub") == 0) {
1020 // -sub symname symvalue to do string substitution in the output
1024 // Allocate memory for the symbol object
1026 Symbol
= malloc (sizeof (SYMBOL
));
1027 if (Symbol
== NULL
) {
1028 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1029 return STATUS_ERROR
;
1032 // Allocate memory for the symbol name and value, then save copies
1034 Symbol
->Name
= malloc (strlen (Argv
[1]) + 1);
1035 if (Symbol
->Name
== NULL
) {
1037 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1038 return STATUS_ERROR
;
1041 strcpy (Symbol
->Name
, Argv
[1]);
1042 Symbol
->Value
= malloc (strlen (Argv
[2]) + 1);
1043 if (Symbol
->Value
== NULL
) {
1044 free (Symbol
->Name
);
1046 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1047 return STATUS_ERROR
;
1050 strcpy (Symbol
->Value
, Argv
[2]);
1052 // Add it to the list
1054 Symbol
->Next
= mGlobals
.SymbolTable
;
1055 mGlobals
.SymbolTable
= Symbol
;
1057 Error (NULL
, 0, 0, Argv
[0], "option requires a symbol name and value");
1059 return STATUS_ERROR
;
1066 } else if (stricmp (Argv
[0], "-nosystem") == 0) {
1067 mGlobals
.NoSystem
= TRUE
;
1068 } else if (stricmp (Argv
[0], "-nodupes") == 0) {
1069 mGlobals
.NoDupes
= TRUE
;
1070 } else if (stricmp (Argv
[0], "-nodups") == 0) {
1071 mGlobals
.NoDupes
= TRUE
;
1072 } else if (stricmp (Argv
[0], "-target") == 0) {
1074 // -target TargetFileName - Target object file (only one allowed right
1075 // now) is TargetFileName rather than SourceFile.obj
1078 strcpy (mGlobals
.TargetFileName
, Argv
[1]);
1080 Error (NULL
, 0, 0, Argv
[0], "option requires a target file name");
1082 return STATUS_ERROR
;
1087 } else if (stricmp (Argv
[0], "-usesumdeps") == 0) {
1089 // -usesumdeps Path - if we find an included file xxx.h, and file
1090 // Path/xxx.dep exists, list Path/xxx.dep as a dependency rather than
1091 // xxx.h and don't parse xxx.h. This allows you to create a dependency
1092 // file for a commonly included file, and have its dependency file updated
1093 // only if its included files are updated. Then anyone else including this
1094 // common include file can simply have a dependency on that file's .dep file
1095 // rather than on all the files included by it. Confusing enough?
1097 mGlobals
.UseSumDeps
= 1;
1099 strcpy (mGlobals
.SumDepsPath
, Argv
[1]);
1101 // Add slash on end if not there
1103 if (mGlobals
.SumDepsPath
[strlen (mGlobals
.SumDepsPath
) - 1] != '\\') {
1104 strcat (mGlobals
.SumDepsPath
, "\\");
1107 Error (NULL
, 0, 0, Argv
[0], "option requires path to summary dependency files");
1109 return STATUS_ERROR
;
1115 } else if (stricmp (Argv
[0], "-o") == 0) {
1117 // -o OutputFileName - specify an output filename for dependency list
1118 // check for one more arg
1122 // Try to open the file
1124 if ((mGlobals
.OutFptr
= fopen (Argv
[1], "w")) == NULL
) {
1125 Error (NULL
, 0, 0, Argv
[1], "could not open file for writing");
1126 return STATUS_ERROR
;
1129 mGlobals
.OutFileName
= Argv
[1];
1131 Error (NULL
, 0, 0, Argv
[0], "option requires output file name");
1133 return STATUS_ERROR
;
1138 } else if (stricmp (Argv
[0], "-v") == 0) {
1139 mGlobals
.Verbose
= TRUE
;
1140 } else if (stricmp (Argv
[0], "-neverfail") == 0) {
1141 mGlobals
.NeverFail
= TRUE
;
1142 } else if (stricmp (Argv
[0], "-q") == 0) {
1143 mGlobals
.QuietMode
= TRUE
;
1144 } else if (stricmp (Argv
[0], "-ignorenotfound") == 0) {
1145 mGlobals
.IgnoreNotFound
= TRUE
;
1146 } else if ((stricmp (Argv
[0], "-h") == 0) || (strcmp (Argv
[0], "-?") == 0)) {
1148 return STATUS_ERROR
;
1150 Error (NULL
, 0, 0, Argv
[0], "unrecognized option");
1152 return STATUS_ERROR
;
1159 // Had to specify at least one source file
1161 if (mGlobals
.SourceFiles
== NULL
) {
1162 Error (NULL
, 0, 0, "must specify one source file name", NULL
);
1164 return STATUS_ERROR
;
1167 // Assume output to stdout if not specified
1169 if (mGlobals
.OutFptr
== NULL
) {
1170 mGlobals
.OutFptr
= stdout
;
1173 return STATUS_SUCCESS
;
1176 // Free the global string lists we allocated memory for
1188 // printf ("Free lists.....");
1190 // Traverse the include paths, freeing each
1191 // printf ("freeing include paths\n");
1193 while (mGlobals
.IncludePaths
!= NULL
) {
1194 Temp
= mGlobals
.IncludePaths
->Next
;
1196 // printf ("Freeing include path string '%s' at 0x%X\n",
1197 // mGlobals.IncludePaths->Str, (int)(mGlobals.IncludePaths->Str));
1199 free (mGlobals
.IncludePaths
->Str
);
1201 // printf ("Freeing include path object at 0x%X\n", (int)(mGlobals.IncludePaths));
1203 free (mGlobals
.IncludePaths
);
1204 mGlobals
.IncludePaths
= Temp
;
1207 // Traverse the source files, freeing each
1209 while (mGlobals
.SourceFiles
!= NULL
) {
1210 Temp
= mGlobals
.SourceFiles
->Next
;
1211 free (mGlobals
.SourceFiles
->Str
);
1212 free (mGlobals
.SourceFiles
);
1213 mGlobals
.SourceFiles
= Temp
;
1216 // Traverse the subdirectory list, freeing each
1218 while (mGlobals
.SubDirs
!= NULL
) {
1219 Temp
= mGlobals
.SubDirs
->Next
;
1220 free (mGlobals
.SubDirs
->Str
);
1221 free (mGlobals
.SubDirs
);
1222 mGlobals
.SubDirs
= Temp
;
1225 // Free the symbol table
1227 while (mGlobals
.SymbolTable
!= NULL
) {
1228 NextSym
= mGlobals
.SymbolTable
->Next
;
1229 free (mGlobals
.SymbolTable
->Name
);
1230 free (mGlobals
.SymbolTable
->Value
);
1231 mGlobals
.SymbolTable
= NextSym
;
1234 // printf ("done\n");
1245 Routine Description:
1247 Print usage information for this utility.
1260 static const char *Str
[] = {
1261 UTILITY_NAME
" -- make dependencies",
1262 " Usage: MakeDeps [options]",
1263 " Options include:",
1264 " -h or -? for this help information",
1265 " -f SourceFile add SourceFile to list of files to scan",
1266 " -i IncludePath add IncludePath to list of search paths",
1267 " -o OutputFile write output dependencies to OutputFile",
1268 " -s SubDir for each IncludePath, also search IncludePath\\SubDir",
1269 " -v for verbose output",
1270 " -ignorenotfound don't warn for files not found",
1271 " -target Target for single SourceFile, target is Target, not SourceFile.obj",
1272 " -q quiet mode to not report files not found if ignored",
1273 " -sub sym str replace all occurrances of 'str' with 'sym' in the output",
1274 " -nosystem not process system <include> files",
1275 " -neverfail always return a success return code",
1277 // " -nodupes keep track of include files, don't rescan duplicates",
1279 " -usesumdeps path use summary dependency files in 'path' directory.",
1283 for (Index
= 0; Str
[Index
] != NULL
; Index
++) {
1284 fprintf (stdout
, "%s\n", Str
[Index
]);