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"
33 // Structure to maintain a linked list of strings
35 typedef struct _STRING_LIST
{
36 struct _STRING_LIST
*Next
;
40 #define UTILITY_NAME "MakeDeps"
42 #define MAX_LINE_LEN 2048
44 #define START_NEST_DEPTH 1
45 #define MAX_NEST_DEPTH 1000 // just in case we get in an endless loop.
47 // Define the relative paths used by the special #include macros
49 #define PROTOCOL_DIR_PATH "Protocol\\"
50 #define GUID_DIR_PATH "Guid\\"
51 #define ARCH_PROTOCOL_DIR_PATH "ArchProtocol\\"
52 #define PPI_PROTOCOL_DIR_PATH "Ppi\\"
55 // Use this structure to keep track of all the special #include forms
58 INT8
*IncludeMacroName
;
60 } INCLUDE_MACRO_CONVERSION
;
63 // This data is used to convert #include macros like:
64 // #include EFI_PROTOCOL_DEFINITION(xxx)
66 // #include Protocol/xxx/xxx.h
68 static const INCLUDE_MACRO_CONVERSION mMacroConversion
[] = {
69 "EFI_PROTOCOL_DEFINITION",
71 "EFI_GUID_DEFINITION",
73 "EFI_ARCH_PROTOCOL_DEFINITION",
74 ARCH_PROTOCOL_DIR_PATH
,
75 "EFI_PROTOCOL_PRODUCER",
77 "EFI_PROTOCOL_CONSUMER",
79 "EFI_PROTOCOL_DEPENDENCY",
81 "EFI_ARCH_PROTOCOL_PRODUCER",
82 ARCH_PROTOCOL_DIR_PATH
,
83 "EFI_ARCH_PROTOCOL_CONSUMER",
84 ARCH_PROTOCOL_DIR_PATH
,
85 "EFI_ARCH_PROTOCOL_DEPENDENCY",
86 ARCH_PROTOCOL_DIR_PATH
,
88 PPI_PROTOCOL_DIR_PATH
,
90 PPI_PROTOCOL_DIR_PATH
,
92 PPI_PROTOCOL_DIR_PATH
,
94 PPI_PROTOCOL_DIR_PATH
,
99 typedef struct _SYMBOL
{
100 struct _SYMBOL
*Next
;
106 // Here's all our globals. We need a linked list of include paths, a linked
107 // list of source files, a linked list of subdirectories (appended to each
108 // include path when searching), and flags to keep track of command-line options.
111 STRING_LIST
*IncludePaths
; // all include paths to search
112 STRING_LIST
*SourceFiles
; // all source files to parse
113 STRING_LIST
*SubDirs
; // appended to each include path when searching
114 SYMBOL
*SymbolTable
; // for replacement strings
115 FILE *OutFptr
; // output dependencies to this file
116 BOOLEAN Verbose
; // for more detailed output
117 BOOLEAN IgnoreNotFound
; // no warnings if files not found
118 BOOLEAN QuietMode
; // -q - don't print missing file warnings
119 BOOLEAN NoSystem
; // don't process #include <system> files
120 BOOLEAN NeverFail
; // always return success
121 BOOLEAN NoDupes
; // to not list duplicate dependency files (for timing purposes)
122 BOOLEAN UseSumDeps
; // use summary dependency files if found
123 INT8 TargetFileName
[MAX_PATH
]; // target object filename
124 INT8 SumDepsPath
[MAX_PATH
]; // path to summary files
125 INT8
*OutFileName
; // -o option
131 INT8
*TargetFileName
,
134 STRING_LIST
*ProcessedFiles
186 Call the routine to parse the command-line options, then process each file
187 to build dependencies.
191 Argc - Standard C main() argc.
192 Argv - Standard C main() argv.
202 STRING_LIST ProcessedFiles
;
203 STRING_LIST
*TempList
;
206 INT8 TargetFileName
[MAX_PATH
];
208 SetUtilityName (UTILITY_NAME
);
210 // Process the command-line arguments
212 Status
= ProcessArgs (Argc
, Argv
);
213 if (Status
!= STATUS_SUCCESS
) {
217 // Go through the list of source files and process each.
219 memset (&ProcessedFiles
, 0, sizeof (STRING_LIST
));
220 File
= mGlobals
.SourceFiles
;
221 while (File
!= NULL
) {
223 // Clear out our list of processed files
225 TempList
= ProcessedFiles
.Next
;
226 while (ProcessedFiles
.Next
!= NULL
) {
227 TempList
= ProcessedFiles
.Next
->Next
;
228 free (ProcessedFiles
.Next
->Str
);
229 free (ProcessedFiles
.Next
);
230 ProcessedFiles
.Next
= TempList
;
233 // Replace filename extension with ".obj" if they did not
234 // specifically specify the target file
236 if (mGlobals
.TargetFileName
[0] == 0) {
237 strcpy (TargetFileName
, File
->Str
);
239 // Find the .extension
241 for (Cptr
= TargetFileName
+ strlen (TargetFileName
) - 1;
242 (*Cptr
!= '\\') && (Cptr
> TargetFileName
) && (*Cptr
!= '.');
246 if (Cptr
== TargetFileName
) {
247 Error (NULL
, 0, 0, File
->Str
, "could not locate extension in filename");
251 // Tack on the ".obj"
253 strcpy (Cptr
, ".obj");
256 // Copy the target filename they specified
258 strcpy (TargetFileName
, mGlobals
.TargetFileName
);
261 Status
= ProcessFile (TargetFileName
, File
->Str
, START_NEST_DEPTH
, &ProcessedFiles
);
262 if (Status
!= STATUS_SUCCESS
) {
275 // Free up our processed files list
277 TempList
= ProcessedFiles
.Next
;
278 while (ProcessedFiles
.Next
!= NULL
) {
279 TempList
= ProcessedFiles
.Next
->Next
;
280 free (ProcessedFiles
.Next
->Str
);
281 free (ProcessedFiles
.Next
);
282 ProcessedFiles
.Next
= TempList
;
285 // Close our output file
287 if ((mGlobals
.OutFptr
!= stdout
) && (mGlobals
.OutFptr
!= NULL
)) {
288 fclose (mGlobals
.OutFptr
);
291 if (mGlobals
.NeverFail
) {
292 return STATUS_SUCCESS
;
295 // If any errors, then delete our output so that it will get created
296 // again on a rebuild.
298 if ((GetUtilityStatus () == STATUS_ERROR
) && (mGlobals
.OutFileName
!= NULL
)) {
299 remove (mGlobals
.OutFileName
);
302 return GetUtilityStatus ();
308 INT8
*TargetFileName
,
311 STRING_LIST
*ProcessedFiles
317 Given a source file name, open the file and parse all #include lines.
321 TargetFileName - name of the usually .obj target
322 FileName - name of the file to process
323 NestDepth - how deep we're nested in includes
324 ProcessedFiles - list of processed files.
333 INT8 Line
[MAX_LINE_LEN
];
338 INT8 FileNameCopy
[MAX_PATH
];
339 INT8 MacroIncludeFileName
[MAX_LINE_LEN
];
340 INT8 SumDepsFile
[MAX_PATH
];
344 STRING_LIST
*ListPtr
;
346 Status
= STATUS_SUCCESS
;
349 // Print the file being processed. Indent so you can tell the include nesting
352 if (mGlobals
.Verbose
) {
353 fprintf (stdout
, "%*cProcessing file '%s'\n", NestDepth
* 2, ' ', FileName
);
356 // If we're using summary dependency files, and a matching .dep file is
357 // found for this file, then just emit the summary dependency file as
358 // a dependency and return.
360 if (mGlobals
.UseSumDeps
) {
361 strcpy (SumDepsFile
, mGlobals
.SumDepsPath
);
362 strcat (SumDepsFile
, FileName
);
363 for (Cptr
= SumDepsFile
+ strlen (SumDepsFile
) - 1;
364 (*Cptr
!= '\\') && (Cptr
> SumDepsFile
) && (*Cptr
!= '.');
369 strcpy (Cptr
, ".dep");
371 strcat (SumDepsFile
, ".dep");
374 // See if the summary dep file exists. Could use _stat() function, but
375 // it's less portable.
377 if ((Fptr
= fopen (SumDepsFile
, "r")) != NULL
) {
378 PrintDependency (TargetFileName
, SumDepsFile
);
379 return STATUS_SUCCESS
;
383 // If we're not doing duplicates, and we've already seen this filename,
386 if (mGlobals
.NoDupes
) {
387 for (ListPtr
= ProcessedFiles
->Next
; ListPtr
!= NULL
; ListPtr
= ListPtr
->Next
) {
388 if (stricmp (FileName
, ListPtr
->Str
) == 0) {
393 // If we found a match, we're done. If we didn't, create a new element
394 // and add it to the list.
396 if (ListPtr
!= NULL
) {
398 // Print a message if verbose mode
400 if (mGlobals
.Verbose
) {
401 DebugMsg (NULL
, 0, 0, FileName
, "duplicate include -- not processed again");
404 return STATUS_SUCCESS
;
407 ListPtr
= malloc (sizeof (STRING_LIST
));
408 ListPtr
->Str
= malloc (strlen (FileName
) + 1);
409 strcpy (ListPtr
->Str
, FileName
);
410 ListPtr
->Next
= ProcessedFiles
->Next
;
411 ProcessedFiles
->Next
= ListPtr
;
415 // Make sure we didn't exceed our maximum nesting depth
417 if (NestDepth
> MAX_NEST_DEPTH
) {
418 Error (NULL
, 0, 0, FileName
, "max nesting depth exceeded on file");
422 // Make a local copy of the filename. Then we can manipulate it
425 strcpy (FileNameCopy
, FileName
);
427 // Try to open the file locally
429 if ((Fptr
= fopen (FileNameCopy
, "r")) == NULL
) {
431 // Try to find it among the paths.
433 Fptr
= FindFile (FileNameCopy
, sizeof (FileNameCopy
));
436 // If this is not the top-level file, and the command-line argument
437 // said to ignore missing files, then return ok
439 if (NestDepth
!= START_NEST_DEPTH
) {
440 if (mGlobals
.IgnoreNotFound
) {
441 if (!mGlobals
.QuietMode
) {
442 DebugMsg (NULL
, 0, 0, FileNameCopy
, "could not find file");
445 return STATUS_SUCCESS
;
447 Error (NULL
, 0, 0, FileNameCopy
, "could not find file");
452 // Top-level (first) file. Emit an error.
454 Error (NULL
, 0, 0, FileNameCopy
, "could not find file");
460 // Print the dependency, with string substitution
462 PrintDependency (TargetFileName
, FileNameCopy
);
465 // Now read in lines and find all #include lines. Allow them to indent, and
466 // to put spaces between the # and include.
469 while ((fgets (Line
, sizeof (Line
), Fptr
) != NULL
) && (Status
== STATUS_SUCCESS
)) {
473 // Skip preceeding spaces on the line
475 while (*Cptr
&& (isspace (*Cptr
))) {
479 // Check for # character
484 // Check for "include"
486 while (*Cptr
&& (isspace (*Cptr
))) {
490 if (strncmp (Cptr
, "include", 7) == 0) {
492 // Skip over "include" and move on to filename as "file" or <file>
495 while (*Cptr
&& (isspace (*Cptr
))) {
501 } else if (*Cptr
== '"') {
505 // Handle special #include MACRO_NAME(file)
506 // Set EndChar to null so we fall through on processing below.
510 // Look for all the special include macros and convert accordingly.
512 for (Index
= 0; mMacroConversion
[Index
].IncludeMacroName
!= NULL
; Index
++) {
514 // Save the start of the string in case some macros are substrings
520 mMacroConversion
[Index
].IncludeMacroName
,
521 strlen (mMacroConversion
[Index
].IncludeMacroName
)
524 // Skip over the macro name
526 Cptr
+= strlen (mMacroConversion
[Index
].IncludeMacroName
);
528 // Skip over open parenthesis, blank spaces, then find closing
529 // parenthesis or blank space
531 while (*Cptr
&& (isspace (*Cptr
))) {
537 while (*Cptr
&& (isspace (*Cptr
))) {
542 while (*EndPtr
&& !isspace (*EndPtr
) && (*EndPtr
!= ')')) {
550 strcpy (MacroIncludeFileName
, mMacroConversion
[Index
].PathName
);
551 strcat (MacroIncludeFileName
, Cptr
);
552 strcat (MacroIncludeFileName
, "\\");
553 strcat (MacroIncludeFileName
, Cptr
);
554 strcat (MacroIncludeFileName
, ".h");
556 // Process immediately, then break out of the outside FOR loop.
558 Status
= ProcessFile (TargetFileName
, MacroIncludeFileName
, NestDepth
+ 1, ProcessedFiles
);
568 // Don't recognize the include line? Ignore it. We assume that the
569 // file compiles anyway.
571 if (mMacroConversion
[Index
].IncludeMacroName
== NULL
) {
573 // Warning (FileNameCopy, LineNum, 0, "could not parse line", NULL);
574 // Status = STATUS_WARNING;
579 // Process "normal" includes. If the endchar is 0, then the
580 // file has already been processed. Otherwise look for the
581 // endchar > or ", and process the include file.
586 while (*EndPtr
&& (*EndPtr
!= EndChar
)) {
590 if (*EndPtr
== EndChar
) {
592 // If we're processing it, do it
594 if ((EndChar
!= '>') || (!mGlobals
.NoSystem
)) {
596 // Null terminate the filename and try to process it.
599 Status
= ProcessFile (TargetFileName
, Cptr
, NestDepth
+ 1, ProcessedFiles
);
602 Warning (FileNameCopy
, LineNum
, 0, "malformed include", "missing closing %c", EndChar
);
603 Status
= STATUS_WARNING
;
613 // Close open files and return status
625 INT8
*TargetFileName
,
632 Given a target (.obj) file name, and a dependent file name, do any string
633 substitutions (per the command line options) on the file names, then
634 print the dependency line of form:
636 TargetFileName : DependentFile
640 TargetFileName - build target file name
641 DependentFile - file on which TargetFileName depends
652 // Go through the symbols and do replacements
654 strcpy (Str
, TargetFileName
);
655 ReplaceSymbols (Str
, sizeof (Str
));
656 fprintf (mGlobals
.OutFptr
, "%s : ", Str
);
657 strcpy (Str
, DependentFile
);
658 ReplaceSymbols (Str
, sizeof (Str
));
659 fprintf (mGlobals
.OutFptr
, "%s\n", Str
);
670 INT8 StrCopy
[MAX_LINE_LEN
];
676 // Go through the entire string to look for replacement strings at
683 // Copy the character
688 // Go through each symbol and try to find a string substitution
690 Sym
= mGlobals
.SymbolTable
;
691 while (Sym
!= NULL
) {
692 if (strnicmp (From
, Sym
->Value
, strlen (Sym
->Value
)) == 0) {
694 // Replace the string, then advance the pointers past the
697 strcpy (To
, Sym
->Name
);
698 To
+= strlen (Sym
->Name
);
699 From
+= strlen (Sym
->Value
);
702 // Break from the while()
716 // Null terminate, and return it
719 if (strlen (StrCopy
) < StrSize
) {
720 strcpy (Str
, StrCopy
);
724 // Given a filename, try to find it along the include paths.
736 INT8 FullFileName
[MAX_PATH
* 2];
739 // Traverse the list of paths and try to find the file
741 List
= mGlobals
.IncludePaths
;
742 while (List
!= NULL
) {
744 // Put the path and filename together
746 if (strlen (List
->Str
) + strlen (FileName
) + 1 > sizeof (FullFileName
)) {
752 "cannot concatenate '%s' + '%s'",
759 // Append the filename to this include path and try to open the file.
761 strcpy (FullFileName
, List
->Str
);
762 strcat (FullFileName
, FileName
);
763 if ((Fptr
= fopen (FullFileName
, "r")) != NULL
) {
765 // Return the file name
767 if (FileNameLen
<= strlen (FullFileName
)) {
768 Error (__FILE__
, __LINE__
, 0, "application error", "internal path name of insufficient length");
770 // fprintf (stdout, "File length > %d: %s\n", FileNameLen, FullFileName);
775 strcpy (FileName
, FullFileName
);
779 // Didn't find it there. Now try this directory with every subdirectory
780 // the user specified on the command line
782 for (SubDir
= mGlobals
.SubDirs
; SubDir
!= NULL
; SubDir
= SubDir
->Next
) {
783 strcpy (FullFileName
, List
->Str
);
784 strcat (FullFileName
, SubDir
->Str
);
785 strcat (FullFileName
, FileName
);
786 if ((Fptr
= fopen (FullFileName
, "r")) != NULL
) {
788 // Return the file name
790 if (FileNameLen
<= strlen (FullFileName
)) {
791 Error (__FILE__
, __LINE__
, 0, "application error", "internal path name of insufficient length");
795 strcpy (FileName
, FullFileName
);
808 // Process the command-line arguments
817 STRING_LIST
*NewList
;
818 STRING_LIST
*LastIncludePath
;
819 STRING_LIST
*LastSourceFile
;
825 memset ((char *) &mGlobals
, 0, sizeof (mGlobals
));
826 mGlobals
.NoDupes
= TRUE
;
835 LastIncludePath
= NULL
;
836 LastSourceFile
= NULL
;
838 // Process until no more args
842 // -i path add include search path
844 if (stricmp (Argv
[0], "-i") == 0) {
846 // check for one more arg
850 // Allocate memory for a new list element, fill it in, and
851 // add it to our list of include paths. Always make sure it
852 // has a "\" on the end of it.
854 NewList
= malloc (sizeof (STRING_LIST
));
855 if (NewList
== NULL
) {
856 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
860 NewList
->Next
= NULL
;
861 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
862 if (NewList
->Str
== NULL
) {
864 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
868 strcpy (NewList
->Str
, Argv
[1]);
869 if (NewList
->Str
[strlen (NewList
->Str
) - 1] != '\\') {
870 strcat (NewList
->Str
, "\\");
873 // Add it to the end of the our list of include paths
875 if (mGlobals
.IncludePaths
== NULL
) {
876 mGlobals
.IncludePaths
= NewList
;
878 LastIncludePath
->Next
= NewList
;
881 LastIncludePath
= NewList
;
883 // fprintf (stdout, "Added path: %s\n", NewList->Str);
886 Error (NULL
, 0, 0, Argv
[0], "option requires an include path");
893 } else if (stricmp (Argv
[0], "-f") == 0) {
895 // Check for one more arg
899 // Allocate memory for a new list element, fill it in, and
900 // add it to our list of source files.
902 NewList
= malloc (sizeof (STRING_LIST
));
903 if (NewList
== NULL
) {
904 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
908 NewList
->Next
= NULL
;
910 // Allocate space to replace ".c" with ".obj", plus null termination
912 NewList
->Str
= malloc (strlen (Argv
[1]) + 5);
913 if (NewList
->Str
== NULL
) {
915 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
919 strcpy (NewList
->Str
, Argv
[1]);
920 if (mGlobals
.SourceFiles
== NULL
) {
921 mGlobals
.SourceFiles
= NewList
;
923 LastSourceFile
->Next
= NewList
;
926 LastSourceFile
= NewList
;
928 Error (NULL
, 0, 0, Argv
[0], "option requires a file name");
933 // The C compiler first looks for #include files in the directory where
934 // the source file came from. Add the file's source directory to the
935 // list of include paths.
937 NewList
= malloc (sizeof (STRING_LIST
));
938 if (NewList
== NULL
) {
939 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
943 NewList
->Next
= NULL
;
944 NewList
->Str
= malloc (strlen (Argv
[1]) + 3);
945 if (NewList
->Str
== NULL
) {
947 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
951 strcpy (NewList
->Str
, Argv
[1]);
953 // Back up in the source file name to the last backslash and terminate after it.
955 for (Index
= strlen (NewList
->Str
) - 1; (Index
> 0) && (NewList
->Str
[Index
] != '\\'); Index
--)
958 strcpy (NewList
->Str
, ".\\");
960 NewList
->Str
[Index
+ 1] = 0;
963 // Add it to the end of the our list of include paths
965 if (mGlobals
.IncludePaths
== NULL
) {
966 mGlobals
.IncludePaths
= NewList
;
968 LastIncludePath
->Next
= NewList
;
971 if (mGlobals
.Verbose
) {
972 fprintf (stdout
, "Adding include path: %s\n", NewList
->Str
);
975 LastIncludePath
= NewList
;
978 } else if (stricmp (Argv
[0], "-s") == 0) {
980 // -s subdir add subdirectory subdir to list of subdirecties to scan.
981 // Check for one more arg first.
985 // Allocate memory for a new list element, fill it in, and
986 // add it to our list of subdirectory include paths. Always
987 // make sure it has a "\" on the end of it.
989 NewList
= malloc (sizeof (STRING_LIST
));
990 if (NewList
== NULL
) {
991 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
995 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
996 if (NewList
->Str
== NULL
) {
998 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1002 strcpy (NewList
->Str
, Argv
[1]);
1003 if (NewList
->Str
[strlen (NewList
->Str
) - 1] != '\\') {
1004 strcat (NewList
->Str
, "\\");
1007 NewList
->Next
= mGlobals
.SubDirs
;
1008 mGlobals
.SubDirs
= NewList
;
1010 Error (NULL
, 0, 0, Argv
[0], "option requires a subdirectory name");
1012 return STATUS_ERROR
;
1017 } else if (stricmp (Argv
[0], "-sub") == 0) {
1019 // -sub symname symvalue to do string substitution in the output
1023 // Allocate memory for the symbol object
1025 Symbol
= malloc (sizeof (SYMBOL
));
1026 if (Symbol
== NULL
) {
1027 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1028 return STATUS_ERROR
;
1031 // Allocate memory for the symbol name and value, then save copies
1033 Symbol
->Name
= malloc (strlen (Argv
[1]) + 1);
1034 if (Symbol
->Name
== NULL
) {
1036 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1037 return STATUS_ERROR
;
1040 strcpy (Symbol
->Name
, Argv
[1]);
1041 Symbol
->Value
= malloc (strlen (Argv
[2]) + 1);
1042 if (Symbol
->Value
== NULL
) {
1043 free (Symbol
->Name
);
1045 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1046 return STATUS_ERROR
;
1049 strcpy (Symbol
->Value
, Argv
[2]);
1051 // Add it to the list
1053 Symbol
->Next
= mGlobals
.SymbolTable
;
1054 mGlobals
.SymbolTable
= Symbol
;
1056 Error (NULL
, 0, 0, Argv
[0], "option requires a symbol name and value");
1058 return STATUS_ERROR
;
1065 } else if (stricmp (Argv
[0], "-nosystem") == 0) {
1066 mGlobals
.NoSystem
= TRUE
;
1067 } else if (stricmp (Argv
[0], "-nodupes") == 0) {
1068 mGlobals
.NoDupes
= TRUE
;
1069 } else if (stricmp (Argv
[0], "-nodups") == 0) {
1070 mGlobals
.NoDupes
= TRUE
;
1071 } else if (stricmp (Argv
[0], "-target") == 0) {
1073 // -target TargetFileName - Target object file (only one allowed right
1074 // now) is TargetFileName rather than SourceFile.obj
1077 strcpy (mGlobals
.TargetFileName
, Argv
[1]);
1079 Error (NULL
, 0, 0, Argv
[0], "option requires a target file name");
1081 return STATUS_ERROR
;
1086 } else if (stricmp (Argv
[0], "-usesumdeps") == 0) {
1088 // -usesumdeps Path - if we find an included file xxx.h, and file
1089 // Path/xxx.dep exists, list Path/xxx.dep as a dependency rather than
1090 // xxx.h and don't parse xxx.h. This allows you to create a dependency
1091 // file for a commonly included file, and have its dependency file updated
1092 // only if its included files are updated. Then anyone else including this
1093 // common include file can simply have a dependency on that file's .dep file
1094 // rather than on all the files included by it. Confusing enough?
1096 mGlobals
.UseSumDeps
= 1;
1098 strcpy (mGlobals
.SumDepsPath
, Argv
[1]);
1100 // Add slash on end if not there
1102 if (mGlobals
.SumDepsPath
[strlen (mGlobals
.SumDepsPath
) - 1] != '\\') {
1103 strcat (mGlobals
.SumDepsPath
, "\\");
1106 Error (NULL
, 0, 0, Argv
[0], "option requires path to summary dependency files");
1108 return STATUS_ERROR
;
1114 } else if (stricmp (Argv
[0], "-o") == 0) {
1116 // -o OutputFileName - specify an output filename for dependency list
1117 // check for one more arg
1121 // Try to open the file
1123 if ((mGlobals
.OutFptr
= fopen (Argv
[1], "w")) == NULL
) {
1124 Error (NULL
, 0, 0, Argv
[1], "could not open file for writing");
1125 return STATUS_ERROR
;
1128 mGlobals
.OutFileName
= Argv
[1];
1130 Error (NULL
, 0, 0, Argv
[0], "option requires output file name");
1132 return STATUS_ERROR
;
1137 } else if (stricmp (Argv
[0], "-v") == 0) {
1138 mGlobals
.Verbose
= TRUE
;
1139 } else if (stricmp (Argv
[0], "-neverfail") == 0) {
1140 mGlobals
.NeverFail
= TRUE
;
1141 } else if (stricmp (Argv
[0], "-q") == 0) {
1142 mGlobals
.QuietMode
= TRUE
;
1143 } else if (stricmp (Argv
[0], "-ignorenotfound") == 0) {
1144 mGlobals
.IgnoreNotFound
= TRUE
;
1145 } else if ((stricmp (Argv
[0], "-h") == 0) || (strcmp (Argv
[0], "-?") == 0)) {
1147 return STATUS_ERROR
;
1149 Error (NULL
, 0, 0, Argv
[0], "unrecognized option");
1151 return STATUS_ERROR
;
1158 // Had to specify at least one source file
1160 if (mGlobals
.SourceFiles
== NULL
) {
1161 Error (NULL
, 0, 0, "must specify one source file name", NULL
);
1163 return STATUS_ERROR
;
1166 // Assume output to stdout if not specified
1168 if (mGlobals
.OutFptr
== NULL
) {
1169 mGlobals
.OutFptr
= stdout
;
1172 return STATUS_SUCCESS
;
1175 // Free the global string lists we allocated memory for
1187 // printf ("Free lists.....");
1189 // Traverse the include paths, freeing each
1190 // printf ("freeing include paths\n");
1192 while (mGlobals
.IncludePaths
!= NULL
) {
1193 Temp
= mGlobals
.IncludePaths
->Next
;
1195 // printf ("Freeing include path string '%s' at 0x%X\n",
1196 // mGlobals.IncludePaths->Str, (int)(mGlobals.IncludePaths->Str));
1198 free (mGlobals
.IncludePaths
->Str
);
1200 // printf ("Freeing include path object at 0x%X\n", (int)(mGlobals.IncludePaths));
1202 free (mGlobals
.IncludePaths
);
1203 mGlobals
.IncludePaths
= Temp
;
1206 // Traverse the source files, freeing each
1208 while (mGlobals
.SourceFiles
!= NULL
) {
1209 Temp
= mGlobals
.SourceFiles
->Next
;
1210 free (mGlobals
.SourceFiles
->Str
);
1211 free (mGlobals
.SourceFiles
);
1212 mGlobals
.SourceFiles
= Temp
;
1215 // Traverse the subdirectory list, freeing each
1217 while (mGlobals
.SubDirs
!= NULL
) {
1218 Temp
= mGlobals
.SubDirs
->Next
;
1219 free (mGlobals
.SubDirs
->Str
);
1220 free (mGlobals
.SubDirs
);
1221 mGlobals
.SubDirs
= Temp
;
1224 // Free the symbol table
1226 while (mGlobals
.SymbolTable
!= NULL
) {
1227 NextSym
= mGlobals
.SymbolTable
->Next
;
1228 free (mGlobals
.SymbolTable
->Name
);
1229 free (mGlobals
.SymbolTable
->Value
);
1230 mGlobals
.SymbolTable
= NextSym
;
1233 // printf ("done\n");
1244 Routine Description:
1246 Print usage information for this utility.
1259 static const char *Str
[] = {
1260 UTILITY_NAME
" -- make dependencies",
1261 " Usage: MakeDeps [options]",
1262 " Options include:",
1263 " -h or -? for this help information",
1264 " -f SourceFile add SourceFile to list of files to scan",
1265 " -i IncludePath add IncludePath to list of search paths",
1266 " -o OutputFile write output dependencies to OutputFile",
1267 " -s SubDir for each IncludePath, also search IncludePath\\SubDir",
1268 " -v for verbose output",
1269 " -ignorenotfound don't warn for files not found",
1270 " -target Target for single SourceFile, target is Target, not SourceFile.obj",
1271 " -q quiet mode to not report files not found if ignored",
1272 " -sub sym str replace all occurrances of 'str' with 'sym' in the output",
1273 " -nosystem not process system <include> files",
1274 " -neverfail always return a success return code",
1276 // " -nodupes keep track of include files, don't rescan duplicates",
1278 " -usesumdeps path use summary dependency files in 'path' directory.",
1282 for (Index
= 0; Str
[Index
] != NULL
; Index
++) {
1283 fprintf (stdout
, "%s\n", Str
[Index
]);