3 Copyright (c) 2004 - 2006, 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 "EfiUtilityMsgs.h"
32 // Structure to maintain a linked list of strings
34 typedef struct _STRING_LIST
{
35 struct _STRING_LIST
*Next
;
39 #define UTILITY_NAME "MakeDeps"
41 #define MAX_LINE_LEN 2048
43 #define START_NEST_DEPTH 1
44 #define MAX_NEST_DEPTH 1000 // just in case we get in an endless loop.
46 // Define the relative paths used by the special #include macros
48 #define PROTOCOL_DIR_PATH "Protocol\\"
49 #define GUID_DIR_PATH "Guid\\"
50 #define ARCH_PROTOCOL_DIR_PATH "ArchProtocol\\"
51 #define PPI_PROTOCOL_DIR_PATH "Ppi\\"
54 // Use this structure to keep track of all the special #include forms
57 INT8
*IncludeMacroName
;
59 } INCLUDE_MACRO_CONVERSION
;
62 // This data is used to convert #include macros like:
63 // #include EFI_PROTOCOL_DEFINITION(xxx)
65 // #include Protocol/xxx/xxx.h
67 static const INCLUDE_MACRO_CONVERSION mMacroConversion
[] = {
68 "EFI_PROTOCOL_DEFINITION",
70 "EFI_GUID_DEFINITION",
72 "EFI_ARCH_PROTOCOL_DEFINITION",
73 ARCH_PROTOCOL_DIR_PATH
,
74 "EFI_PROTOCOL_PRODUCER",
76 "EFI_PROTOCOL_CONSUMER",
78 "EFI_PROTOCOL_DEPENDENCY",
80 "EFI_ARCH_PROTOCOL_PRODUCER",
81 ARCH_PROTOCOL_DIR_PATH
,
82 "EFI_ARCH_PROTOCOL_CONSUMER",
83 ARCH_PROTOCOL_DIR_PATH
,
84 "EFI_ARCH_PROTOCOL_DEPENDENCY",
85 ARCH_PROTOCOL_DIR_PATH
,
87 PPI_PROTOCOL_DIR_PATH
,
89 PPI_PROTOCOL_DIR_PATH
,
91 PPI_PROTOCOL_DIR_PATH
,
93 PPI_PROTOCOL_DIR_PATH
,
98 typedef struct _SYMBOL
{
105 // Here's all our globals. We need a linked list of include paths, a linked
106 // list of source files, a linked list of subdirectories (appended to each
107 // include path when searching), and flags to keep track of command-line options.
110 STRING_LIST
*IncludePaths
; // all include paths to search
111 STRING_LIST
*SourceFiles
; // all source files to parse
112 STRING_LIST
*SubDirs
; // appended to each include path when searching
113 SYMBOL
*SymbolTable
; // for replacement strings
114 FILE *OutFptr
; // output dependencies to this file
115 BOOLEAN Verbose
; // for more detailed output
116 BOOLEAN IgnoreNotFound
; // no warnings if files not found
117 BOOLEAN QuietMode
; // -q - don't print missing file warnings
118 BOOLEAN NoSystem
; // don't process #include <system> files
119 BOOLEAN NeverFail
; // always return success
120 BOOLEAN NoDupes
; // to not list duplicate dependency files (for timing purposes)
121 BOOLEAN UseSumDeps
; // use summary dependency files if found
122 BOOLEAN IsAsm
; // The SourceFiles are assembler files
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
);
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, there is no # for asm
482 if ((*Cptr
== '#') || (mGlobals
.IsAsm
)) {
488 // Check for "include", case insensitive for asm
490 while (*Cptr
&& (isspace (*Cptr
))) {
493 if (((!mGlobals
.IsAsm
) && (strncmp (Cptr
, "include", 7) == 0)) ||
494 (mGlobals
.IsAsm
&& (_strnicmp (Cptr
, "include", 7) == 0))) {
496 // Skip over "include" and move on to filename as "file" or <file> or file for asm
499 while (*Cptr
&& (isspace (*Cptr
))) {
505 } else if (*Cptr
== '"') {
507 } else if (mGlobals
.IsAsm
) {
509 // Handle include file for asm
510 // Set EndChar to null so we fall through on processing below.
515 // Look for the end of include file name
518 while (*EndPtr
&& (!isspace (*EndPtr
))) {
523 // Null terminate the filename and try to process it.
526 Status
= ProcessFile (TargetFileName
, Cptr
, NestDepth
+ 1, ProcessedFiles
);
529 // Handle special #include MACRO_NAME(file)
530 // Set EndChar to null so we fall through on processing below.
534 // Look for all the special include macros and convert accordingly.
536 for (Index
= 0; mMacroConversion
[Index
].IncludeMacroName
!= NULL
; Index
++) {
538 // Save the start of the string in case some macros are substrings
544 mMacroConversion
[Index
].IncludeMacroName
,
545 strlen (mMacroConversion
[Index
].IncludeMacroName
)
548 // Skip over the macro name
550 Cptr
+= strlen (mMacroConversion
[Index
].IncludeMacroName
);
552 // Skip over open parenthesis, blank spaces, then find closing
553 // parenthesis or blank space
555 while (*Cptr
&& (isspace (*Cptr
))) {
561 while (*Cptr
&& (isspace (*Cptr
))) {
566 while (*EndPtr
&& !isspace (*EndPtr
) && (*EndPtr
!= ')')) {
574 strcpy (MacroIncludeFileName
, mMacroConversion
[Index
].PathName
);
575 strcat (MacroIncludeFileName
, Cptr
);
576 strcat (MacroIncludeFileName
, "\\");
577 strcat (MacroIncludeFileName
, Cptr
);
578 strcat (MacroIncludeFileName
, ".h");
580 // Process immediately, then break out of the outside FOR loop.
582 Status
= ProcessFile (TargetFileName
, MacroIncludeFileName
, NestDepth
+ 1, ProcessedFiles
);
592 // Don't recognize the include line? Ignore it. We assume that the
593 // file compiles anyway.
595 if (mMacroConversion
[Index
].IncludeMacroName
== NULL
) {
597 // Warning (FileNameCopy, LineNum, 0, "could not parse line", NULL);
598 // Status = STATUS_WARNING;
603 // Process "normal" includes. If the endchar is 0, then the
604 // file has already been processed. Otherwise look for the
605 // endchar > or ", and process the include file.
610 while (*EndPtr
&& (*EndPtr
!= EndChar
)) {
614 if (*EndPtr
== EndChar
) {
616 // If we're processing it, do it
618 if ((EndChar
!= '>') || (!mGlobals
.NoSystem
)) {
620 // Null terminate the filename and try to process it.
623 Status
= ProcessFile (TargetFileName
, Cptr
, NestDepth
+ 1, ProcessedFiles
);
626 Warning (FileNameCopy
, LineNum
, 0, "malformed include", "missing closing %c", EndChar
);
627 Status
= STATUS_WARNING
;
637 // Close open files and return status
649 INT8
*TargetFileName
,
656 Given a target (.obj) file name, and a dependent file name, do any string
657 substitutions (per the command line options) on the file names, then
658 print the dependency line of form:
660 TargetFileName : DependentFile
664 TargetFileName - build target file name
665 DependentFile - file on which TargetFileName depends
676 // Go through the symbols and do replacements
678 strcpy (Str
, TargetFileName
);
679 ReplaceSymbols (Str
, sizeof (Str
));
680 fprintf (mGlobals
.OutFptr
, "%s : ", Str
);
681 strcpy (Str
, DependentFile
);
682 ReplaceSymbols (Str
, sizeof (Str
));
683 fprintf (mGlobals
.OutFptr
, "%s\n", Str
);
685 // Add pseudo target to avoid incremental build failure when the file is deleted
687 fprintf (mGlobals
.OutFptr
, "%s : \n", Str
);
698 INT8 StrCopy
[MAX_LINE_LEN
];
704 // Go through the entire string to look for replacement strings at
711 // Copy the character
716 // Go through each symbol and try to find a string substitution
718 Sym
= mGlobals
.SymbolTable
;
719 while (Sym
!= NULL
) {
720 if (_strnicmp (From
, Sym
->Value
, strlen (Sym
->Value
)) == 0) {
722 // Replace the string, then advance the pointers past the
725 strcpy (To
, Sym
->Name
);
726 To
+= strlen (Sym
->Name
);
727 From
+= strlen (Sym
->Value
);
730 // Break from the while()
744 // Null terminate, and return it
747 if (strlen (StrCopy
) < StrSize
) {
748 strcpy (Str
, StrCopy
);
752 // Given a filename, try to find it along the include paths.
764 INT8 FullFileName
[MAX_PATH
* 2];
767 // Traverse the list of paths and try to find the file
769 List
= mGlobals
.IncludePaths
;
770 while (List
!= NULL
) {
772 // Put the path and filename together
774 if (strlen (List
->Str
) + strlen (FileName
) + 1 > sizeof (FullFileName
)) {
780 "cannot concatenate '%s' + '%s'",
787 // Append the filename to this include path and try to open the file.
789 strcpy (FullFileName
, List
->Str
);
790 strcat (FullFileName
, FileName
);
791 if ((Fptr
= fopen (FullFileName
, "r")) != NULL
) {
793 // Return the file name
795 if (FileNameLen
<= strlen (FullFileName
)) {
796 Error (__FILE__
, __LINE__
, 0, "application error", "internal path name of insufficient length");
798 // fprintf (stdout, "File length > %d: %s\n", FileNameLen, FullFileName);
803 strcpy (FileName
, FullFileName
);
807 // Didn't find it there. Now try this directory with every subdirectory
808 // the user specified on the command line
810 for (SubDir
= mGlobals
.SubDirs
; SubDir
!= NULL
; SubDir
= SubDir
->Next
) {
811 strcpy (FullFileName
, List
->Str
);
812 strcat (FullFileName
, SubDir
->Str
);
813 strcat (FullFileName
, FileName
);
814 if ((Fptr
= fopen (FullFileName
, "r")) != NULL
) {
816 // Return the file name
818 if (FileNameLen
<= strlen (FullFileName
)) {
819 Error (__FILE__
, __LINE__
, 0, "application error", "internal path name of insufficient length");
823 strcpy (FileName
, FullFileName
);
836 // Process the command-line arguments
845 STRING_LIST
*NewList
;
846 STRING_LIST
*LastIncludePath
;
847 STRING_LIST
*LastSourceFile
;
853 memset ((char *) &mGlobals
, 0, sizeof (mGlobals
));
854 mGlobals
.NoDupes
= TRUE
;
863 LastIncludePath
= NULL
;
864 LastSourceFile
= NULL
;
866 // Process until no more args
870 // -i path add include search path
872 if (_stricmp (Argv
[0], "-i") == 0) {
874 // check for one more arg
878 // Allocate memory for a new list element, fill it in, and
879 // add it to our list of include paths. Always make sure it
880 // has a "\" on the end of it.
882 NewList
= malloc (sizeof (STRING_LIST
));
883 if (NewList
== NULL
) {
884 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
888 NewList
->Next
= NULL
;
889 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
890 if (NewList
->Str
== NULL
) {
892 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
896 strcpy (NewList
->Str
, Argv
[1]);
897 if (NewList
->Str
[strlen (NewList
->Str
) - 1] != '\\') {
898 strcat (NewList
->Str
, "\\");
901 // Add it to the end of the our list of include paths
903 if (mGlobals
.IncludePaths
== NULL
) {
904 mGlobals
.IncludePaths
= NewList
;
906 LastIncludePath
->Next
= NewList
;
909 LastIncludePath
= NewList
;
911 // fprintf (stdout, "Added path: %s\n", NewList->Str);
914 Error (NULL
, 0, 0, Argv
[0], "option requires an include path");
921 } else if (_stricmp (Argv
[0], "-f") == 0) {
923 // Check for one more arg
927 // Allocate memory for a new list element, fill it in, and
928 // add it to our list of source files.
930 NewList
= malloc (sizeof (STRING_LIST
));
931 if (NewList
== NULL
) {
932 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
936 NewList
->Next
= NULL
;
938 // Allocate space to replace ".c" with ".obj", plus null termination
940 NewList
->Str
= malloc (strlen (Argv
[1]) + 5);
941 if (NewList
->Str
== NULL
) {
943 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
947 strcpy (NewList
->Str
, Argv
[1]);
948 if (mGlobals
.SourceFiles
== NULL
) {
949 mGlobals
.SourceFiles
= NewList
;
951 LastSourceFile
->Next
= NewList
;
954 LastSourceFile
= NewList
;
956 Error (NULL
, 0, 0, Argv
[0], "option requires a file name");
961 // The C compiler first looks for #include files in the directory where
962 // the source file came from. Add the file's source directory to the
963 // list of include paths.
965 NewList
= malloc (sizeof (STRING_LIST
));
966 if (NewList
== NULL
) {
967 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
971 NewList
->Next
= NULL
;
972 NewList
->Str
= malloc (strlen (Argv
[1]) + 3);
973 if (NewList
->Str
== NULL
) {
975 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
979 strcpy (NewList
->Str
, Argv
[1]);
981 // Back up in the source file name to the last backslash and terminate after it.
983 for (Index
= strlen (NewList
->Str
) - 1; (Index
> 0) && (NewList
->Str
[Index
] != '\\'); Index
--)
986 strcpy (NewList
->Str
, ".\\");
988 NewList
->Str
[Index
+ 1] = 0;
991 // Add it to the end of the our list of include paths
993 if (mGlobals
.IncludePaths
== NULL
) {
994 mGlobals
.IncludePaths
= NewList
;
996 LastIncludePath
->Next
= NewList
;
999 if (mGlobals
.Verbose
) {
1000 fprintf (stdout
, "Adding include path: %s\n", NewList
->Str
);
1003 LastIncludePath
= NewList
;
1006 } else if (_stricmp (Argv
[0], "-s") == 0) {
1008 // -s subdir add subdirectory subdir to list of subdirecties to scan.
1009 // Check for one more arg first.
1013 // Allocate memory for a new list element, fill it in, and
1014 // add it to our list of subdirectory include paths. Always
1015 // make sure it has a "\" on the end of it.
1017 NewList
= malloc (sizeof (STRING_LIST
));
1018 if (NewList
== NULL
) {
1019 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1020 return STATUS_ERROR
;
1023 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
1024 if (NewList
->Str
== NULL
) {
1026 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1027 return STATUS_ERROR
;
1030 strcpy (NewList
->Str
, Argv
[1]);
1031 if (NewList
->Str
[strlen (NewList
->Str
) - 1] != '\\') {
1032 strcat (NewList
->Str
, "\\");
1035 NewList
->Next
= mGlobals
.SubDirs
;
1036 mGlobals
.SubDirs
= NewList
;
1038 Error (NULL
, 0, 0, Argv
[0], "option requires a subdirectory name");
1040 return STATUS_ERROR
;
1045 } else if (_stricmp (Argv
[0], "-sub") == 0) {
1047 // -sub symname symvalue to do string substitution in the output
1051 // Allocate memory for the symbol object
1053 Symbol
= malloc (sizeof (SYMBOL
));
1054 if (Symbol
== NULL
) {
1055 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1056 return STATUS_ERROR
;
1059 // Allocate memory for the symbol name and value, then save copies
1061 Symbol
->Name
= malloc (strlen (Argv
[1]) + 1);
1062 if (Symbol
->Name
== NULL
) {
1064 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1065 return STATUS_ERROR
;
1068 strcpy (Symbol
->Name
, Argv
[1]);
1069 Symbol
->Value
= malloc (strlen (Argv
[2]) + 1);
1070 if (Symbol
->Value
== NULL
) {
1071 free (Symbol
->Name
);
1073 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1074 return STATUS_ERROR
;
1077 strcpy (Symbol
->Value
, Argv
[2]);
1079 // Add it to the list
1081 Symbol
->Next
= mGlobals
.SymbolTable
;
1082 mGlobals
.SymbolTable
= Symbol
;
1084 Error (NULL
, 0, 0, Argv
[0], "option requires a symbol name and value");
1086 return STATUS_ERROR
;
1093 } else if (_stricmp (Argv
[0], "-nosystem") == 0) {
1094 mGlobals
.NoSystem
= TRUE
;
1095 } else if (_stricmp (Argv
[0], "-nodupes") == 0) {
1096 mGlobals
.NoDupes
= TRUE
;
1097 } else if (_stricmp (Argv
[0], "-nodups") == 0) {
1098 mGlobals
.NoDupes
= TRUE
;
1099 } else if (_stricmp (Argv
[0], "-target") == 0) {
1101 // -target TargetFileName - Target object file (only one allowed right
1102 // now) is TargetFileName rather than SourceFile.obj
1105 strcpy (mGlobals
.TargetFileName
, Argv
[1]);
1107 Error (NULL
, 0, 0, Argv
[0], "option requires a target file name");
1109 return STATUS_ERROR
;
1114 } else if (_stricmp (Argv
[0], "-usesumdeps") == 0) {
1116 // -usesumdeps Path - if we find an included file xxx.h, and file
1117 // Path/xxx.dep exists, list Path/xxx.dep as a dependency rather than
1118 // xxx.h and don't parse xxx.h. This allows you to create a dependency
1119 // file for a commonly included file, and have its dependency file updated
1120 // only if its included files are updated. Then anyone else including this
1121 // common include file can simply have a dependency on that file's .dep file
1122 // rather than on all the files included by it. Confusing enough?
1124 mGlobals
.UseSumDeps
= 1;
1126 strcpy (mGlobals
.SumDepsPath
, Argv
[1]);
1128 // Add slash on end if not there
1130 if (mGlobals
.SumDepsPath
[strlen (mGlobals
.SumDepsPath
) - 1] != '\\') {
1131 strcat (mGlobals
.SumDepsPath
, "\\");
1134 Error (NULL
, 0, 0, Argv
[0], "option requires path to summary dependency files");
1136 return STATUS_ERROR
;
1142 } else if (_stricmp (Argv
[0], "-o") == 0) {
1144 // -o OutputFileName - specify an output filename for dependency list
1145 // check for one more arg
1149 // Try to open the file
1151 if ((mGlobals
.OutFptr
= fopen (Argv
[1], "w")) == NULL
) {
1152 Error (NULL
, 0, 0, Argv
[1], "could not open file for writing");
1153 return STATUS_ERROR
;
1156 mGlobals
.OutFileName
= Argv
[1];
1158 Error (NULL
, 0, 0, Argv
[0], "option requires output file name");
1160 return STATUS_ERROR
;
1165 } else if (_stricmp (Argv
[0], "-v") == 0) {
1166 mGlobals
.Verbose
= TRUE
;
1167 } else if (_stricmp (Argv
[0], "-neverfail") == 0) {
1168 mGlobals
.NeverFail
= TRUE
;
1169 } else if (_stricmp (Argv
[0], "-q") == 0) {
1170 mGlobals
.QuietMode
= TRUE
;
1171 } else if (_stricmp (Argv
[0], "-ignorenotfound") == 0) {
1172 mGlobals
.IgnoreNotFound
= TRUE
;
1173 } else if (_stricmp (Argv
[0], "-asm") == 0) {
1174 mGlobals
.IsAsm
= TRUE
;
1175 } else if ((_stricmp (Argv
[0], "-h") == 0) || (strcmp (Argv
[0], "-?") == 0)) {
1177 return STATUS_ERROR
;
1179 Error (NULL
, 0, 0, Argv
[0], "unrecognized option");
1181 return STATUS_ERROR
;
1188 // Had to specify at least one source file
1190 if (mGlobals
.SourceFiles
== NULL
) {
1191 Error (NULL
, 0, 0, "must specify one source file name", NULL
);
1193 return STATUS_ERROR
;
1196 // Assume output to stdout if not specified
1198 if (mGlobals
.OutFptr
== NULL
) {
1199 mGlobals
.OutFptr
= stdout
;
1202 return STATUS_SUCCESS
;
1205 // Free the global string lists we allocated memory for
1217 // printf ("Free lists.....");
1219 // Traverse the include paths, freeing each
1220 // printf ("freeing include paths\n");
1222 while (mGlobals
.IncludePaths
!= NULL
) {
1223 Temp
= mGlobals
.IncludePaths
->Next
;
1225 // printf ("Freeing include path string '%s' at 0x%X\n",
1226 // mGlobals.IncludePaths->Str, (int)(mGlobals.IncludePaths->Str));
1228 free (mGlobals
.IncludePaths
->Str
);
1230 // printf ("Freeing include path object at 0x%X\n", (int)(mGlobals.IncludePaths));
1232 free (mGlobals
.IncludePaths
);
1233 mGlobals
.IncludePaths
= Temp
;
1236 // Traverse the source files, freeing each
1238 while (mGlobals
.SourceFiles
!= NULL
) {
1239 Temp
= mGlobals
.SourceFiles
->Next
;
1240 free (mGlobals
.SourceFiles
->Str
);
1241 free (mGlobals
.SourceFiles
);
1242 mGlobals
.SourceFiles
= Temp
;
1245 // Traverse the subdirectory list, freeing each
1247 while (mGlobals
.SubDirs
!= NULL
) {
1248 Temp
= mGlobals
.SubDirs
->Next
;
1249 free (mGlobals
.SubDirs
->Str
);
1250 free (mGlobals
.SubDirs
);
1251 mGlobals
.SubDirs
= Temp
;
1254 // Free the symbol table
1256 while (mGlobals
.SymbolTable
!= NULL
) {
1257 NextSym
= mGlobals
.SymbolTable
->Next
;
1258 free (mGlobals
.SymbolTable
->Name
);
1259 free (mGlobals
.SymbolTable
->Value
);
1260 mGlobals
.SymbolTable
= NextSym
;
1263 // printf ("done\n");
1274 Routine Description:
1276 Print usage information for this utility.
1289 static const char *Str
[] = {
1290 UTILITY_NAME
" -- make dependencies",
1291 " Usage: MakeDeps [options]",
1292 " Options include:",
1293 " -h or -? for this help information",
1294 " -f SourceFile add SourceFile to list of files to scan",
1295 " -i IncludePath add IncludePath to list of search paths",
1296 " -o OutputFile write output dependencies to OutputFile",
1297 " -s SubDir for each IncludePath, also search IncludePath\\SubDir",
1298 " -v for verbose output",
1299 " -ignorenotfound don't warn for files not found",
1300 " -target Target for single SourceFile, target is Target, not SourceFile.obj",
1301 " -q quiet mode to not report files not found if ignored",
1302 " -sub sym str replace all occurrances of 'str' with 'sym' in the output",
1303 " -nosystem not process system <include> files",
1304 " -neverfail always return a success return code",
1306 // " -nodupes keep track of include files, don't rescan duplicates",
1308 " -usesumdeps path use summary dependency files in 'path' directory.",
1309 " -asm The SourceFile is assembler file",
1313 for (Index
= 0; Str
[Index
] != NULL
; Index
++) {
1314 fprintf (stdout
, "%s\n", Str
[Index
]);