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.
28 #include <Common/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
!= '/') && (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 fprintf(mGlobals
.OutFptr
, "\t\n"); // file ending flag
290 fclose (mGlobals
.OutFptr
);
293 if (mGlobals
.NeverFail
) {
294 return STATUS_SUCCESS
;
297 // If any errors, then delete our output so that it will get created
298 // again on a rebuild.
300 if ((GetUtilityStatus () == STATUS_ERROR
) && (mGlobals
.OutFileName
!= NULL
)) {
301 remove (mGlobals
.OutFileName
);
304 return GetUtilityStatus ();
310 INT8
*TargetFileName
,
313 STRING_LIST
*ProcessedFiles
319 Given a source file name, open the file and parse all #include lines.
323 TargetFileName - name of the usually .obj target
324 FileName - name of the file to process
325 NestDepth - how deep we're nested in includes
326 ProcessedFiles - list of processed files.
335 INT8 Line
[MAX_LINE_LEN
];
340 INT8 FileNameCopy
[MAX_PATH
];
341 INT8 MacroIncludeFileName
[MAX_LINE_LEN
];
342 INT8 SumDepsFile
[MAX_PATH
];
346 STRING_LIST
*ListPtr
;
348 Status
= STATUS_SUCCESS
;
351 // Print the file being processed. Indent so you can tell the include nesting
354 if (mGlobals
.Verbose
) {
355 fprintf (stdout
, "%*cProcessing file '%s'\n", NestDepth
* 2, ' ', FileName
);
358 // If we're using summary dependency files, and a matching .dep file is
359 // found for this file, then just emit the summary dependency file as
360 // a dependency and return.
362 if (mGlobals
.UseSumDeps
) {
363 strcpy (SumDepsFile
, mGlobals
.SumDepsPath
);
364 strcat (SumDepsFile
, FileName
);
365 for (Cptr
= SumDepsFile
+ strlen (SumDepsFile
) - 1;
366 (*Cptr
!= '\\' && *Cptr
!= '/') && (Cptr
> SumDepsFile
) && (*Cptr
!= '.');
371 strcpy (Cptr
, ".dep");
373 strcat (SumDepsFile
, ".dep");
376 // See if the summary dep file exists. Could use _stat() function, but
377 // it's less portable.
379 if ((Fptr
= fopen (SumDepsFile
, "r")) != NULL
) {
380 PrintDependency (TargetFileName
, SumDepsFile
);
381 return STATUS_SUCCESS
;
385 // If we're not doing duplicates, and we've already seen this filename,
388 if (mGlobals
.NoDupes
) {
389 for (ListPtr
= ProcessedFiles
->Next
; ListPtr
!= NULL
; ListPtr
= ListPtr
->Next
) {
390 if (stricmp (FileName
, ListPtr
->Str
) == 0) {
395 // If we found a match, we're done. If we didn't, create a new element
396 // and add it to the list.
398 if (ListPtr
!= NULL
) {
400 // Print a message if verbose mode
402 if (mGlobals
.Verbose
) {
403 DebugMsg (NULL
, 0, 0, FileName
, "duplicate include -- not processed again");
406 return STATUS_SUCCESS
;
409 ListPtr
= malloc (sizeof (STRING_LIST
));
410 ListPtr
->Str
= malloc (strlen (FileName
) + 1);
411 strcpy (ListPtr
->Str
, FileName
);
412 ListPtr
->Next
= ProcessedFiles
->Next
;
413 ProcessedFiles
->Next
= ListPtr
;
417 // Make sure we didn't exceed our maximum nesting depth
419 if (NestDepth
> MAX_NEST_DEPTH
) {
420 Error (NULL
, 0, 0, FileName
, "max nesting depth exceeded on file");
424 // Make a local copy of the filename. Then we can manipulate it
427 strcpy (FileNameCopy
, FileName
);
429 // Try to open the file locally
431 if ((Fptr
= fopen (FileNameCopy
, "r")) == NULL
) {
433 // Try to find it among the paths.
435 Fptr
= FindFile (FileNameCopy
, sizeof (FileNameCopy
));
438 // If this is not the top-level file, and the command-line argument
439 // said to ignore missing files, then return ok
441 if (NestDepth
!= START_NEST_DEPTH
) {
442 if (mGlobals
.IgnoreNotFound
) {
443 if (!mGlobals
.QuietMode
) {
444 DebugMsg (NULL
, 0, 0, FileNameCopy
, "could not find file");
447 return STATUS_SUCCESS
;
449 Error (NULL
, 0, 0, FileNameCopy
, "could not find file");
454 // Top-level (first) file. Emit an error.
456 Error (NULL
, 0, 0, FileNameCopy
, "could not find file");
462 // Print the dependency, with string substitution
464 PrintDependency (TargetFileName
, FileNameCopy
);
467 // Now read in lines and find all #include lines. Allow them to indent, and
468 // to put spaces between the # and include.
471 while ((fgets (Line
, sizeof (Line
), Fptr
) != NULL
) && (Status
== STATUS_SUCCESS
)) {
475 // Skip preceeding spaces on the line
477 while (*Cptr
&& (isspace (*Cptr
))) {
481 // Check for # character
486 // Check for "include"
488 while (*Cptr
&& (isspace (*Cptr
))) {
492 if (strncmp (Cptr
, "include", 7) == 0) {
494 // Skip over "include" and move on to filename as "file" or <file>
497 while (*Cptr
&& (isspace (*Cptr
))) {
503 } else if (*Cptr
== '"') {
507 // Handle special #include MACRO_NAME(file)
508 // Set EndChar to null so we fall through on processing below.
512 // Look for all the special include macros and convert accordingly.
514 for (Index
= 0; mMacroConversion
[Index
].IncludeMacroName
!= NULL
; Index
++) {
516 // Save the start of the string in case some macros are substrings
522 mMacroConversion
[Index
].IncludeMacroName
,
523 strlen (mMacroConversion
[Index
].IncludeMacroName
)
526 // Skip over the macro name
528 Cptr
+= strlen (mMacroConversion
[Index
].IncludeMacroName
);
530 // Skip over open parenthesis, blank spaces, then find closing
531 // parenthesis or blank space
533 while (*Cptr
&& (isspace (*Cptr
))) {
539 while (*Cptr
&& (isspace (*Cptr
))) {
544 while (*EndPtr
&& !isspace (*EndPtr
) && (*EndPtr
!= ')')) {
552 strcpy (MacroIncludeFileName
, mMacroConversion
[Index
].PathName
);
553 strcat (MacroIncludeFileName
, Cptr
);
554 strcat (MacroIncludeFileName
, "/");
555 strcat (MacroIncludeFileName
, Cptr
);
556 strcat (MacroIncludeFileName
, ".h");
558 // Process immediately, then break out of the outside FOR loop.
560 Status
= ProcessFile (TargetFileName
, MacroIncludeFileName
, NestDepth
+ 1, ProcessedFiles
);
570 // Don't recognize the include line? Ignore it. We assume that the
571 // file compiles anyway.
573 if (mMacroConversion
[Index
].IncludeMacroName
== NULL
) {
575 // Warning (FileNameCopy, LineNum, 0, "could not parse line", NULL);
576 // Status = STATUS_WARNING;
581 // Process "normal" includes. If the endchar is 0, then the
582 // file has already been processed. Otherwise look for the
583 // endchar > or ", and process the include file.
588 while (*EndPtr
&& (*EndPtr
!= EndChar
)) {
592 if (*EndPtr
== EndChar
) {
594 // If we're processing it, do it
596 if ((EndChar
!= '>') || (!mGlobals
.NoSystem
)) {
598 // Null terminate the filename and try to process it.
601 Status
= ProcessFile (TargetFileName
, Cptr
, NestDepth
+ 1, ProcessedFiles
);
604 Warning (FileNameCopy
, LineNum
, 0, "malformed include", "missing closing %c", EndChar
);
605 Status
= STATUS_WARNING
;
615 // Close open files and return status
627 INT8
*TargetFileName
,
634 Given a target (.obj) file name, and a dependent file name, do any string
635 substitutions (per the command line options) on the file names, then
636 print the dependency line of form:
638 TargetFileName : DependentFile
642 TargetFileName - build target file name
643 DependentFile - file on which TargetFileName depends
654 // Go through the symbols and do replacements
656 strcpy (Str
, DependentFile
);
657 ReplaceSymbols (Str
, sizeof (Str
));
658 fprintf (mGlobals
.OutFptr
, "%s\n", Str
);
669 INT8 StrCopy
[MAX_LINE_LEN
];
675 // Go through the entire string to look for replacement strings at
682 // Copy the character
687 // Go through each symbol and try to find a string substitution
689 Sym
= mGlobals
.SymbolTable
;
690 while (Sym
!= NULL
) {
691 if (strnicmp (From
, Sym
->Value
, strlen (Sym
->Value
)) == 0) {
693 // Replace the string, then advance the pointers past the
696 strcpy (To
, Sym
->Name
);
697 To
+= strlen (Sym
->Name
);
698 From
+= strlen (Sym
->Value
);
701 // Break from the while()
715 // Null terminate, and return it
718 if (strlen (StrCopy
) < StrSize
) {
719 strcpy (Str
, StrCopy
);
723 // Given a filename, try to find it along the include paths.
735 INT8 FullFileName
[MAX_PATH
* 2];
738 // Traverse the list of paths and try to find the file
740 List
= mGlobals
.IncludePaths
;
741 while (List
!= NULL
) {
743 // Put the path and filename together
745 if (strlen (List
->Str
) + strlen (FileName
) + 1 > sizeof (FullFileName
)) {
751 "cannot concatenate '%s' + '%s'",
758 // Append the filename to this include path and try to open the file.
760 strcpy (FullFileName
, List
->Str
);
761 strcat (FullFileName
, FileName
);
762 if ((Fptr
= fopen (FullFileName
, "r")) != NULL
) {
764 // Return the file name
766 if (FileNameLen
<= strlen (FullFileName
)) {
767 Error (__FILE__
, __LINE__
, 0, "application error", "internal path name of insufficient length");
769 // fprintf (stdout, "File length > %d: %s\n", FileNameLen, FullFileName);
774 strcpy (FileName
, FullFileName
);
778 // Didn't find it there. Now try this directory with every subdirectory
779 // the user specified on the command line
781 for (SubDir
= mGlobals
.SubDirs
; SubDir
!= NULL
; SubDir
= SubDir
->Next
) {
782 strcpy (FullFileName
, List
->Str
);
783 strcat (FullFileName
, SubDir
->Str
);
784 strcat (FullFileName
, FileName
);
785 if ((Fptr
= fopen (FullFileName
, "r")) != NULL
) {
787 // Return the file name
789 if (FileNameLen
<= strlen (FullFileName
)) {
790 Error (__FILE__
, __LINE__
, 0, "application error", "internal path name of insufficient length");
794 strcpy (FileName
, FullFileName
);
807 // Process the command-line arguments
816 STRING_LIST
*NewList
;
817 STRING_LIST
*LastIncludePath
;
818 STRING_LIST
*LastSourceFile
;
824 memset ((char *) &mGlobals
, 0, sizeof (mGlobals
));
825 mGlobals
.NoDupes
= TRUE
;
834 LastIncludePath
= NULL
;
835 LastSourceFile
= NULL
;
837 // Process until no more args
841 // -i path add include search path
843 if (stricmp (Argv
[0], "-i") == 0) {
845 // check for one more arg
849 // Allocate memory for a new list element, fill it in, and
850 // add it to our list of include paths. Always make sure it
851 // has a "\" on the end of it.
853 NewList
= malloc (sizeof (STRING_LIST
));
854 if (NewList
== NULL
) {
855 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
859 NewList
->Next
= NULL
;
860 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
861 if (NewList
->Str
== NULL
) {
863 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
867 strcpy (NewList
->Str
, Argv
[1]);
868 if (NewList
->Str
[strlen (NewList
->Str
) - 1] != '\\' && NewList
->Str
[strlen (NewList
->Str
) - 1] != '/') {
869 strcat (NewList
->Str
, "/");
872 // Add it to the end of the our list of include paths
874 if (mGlobals
.IncludePaths
== NULL
) {
875 mGlobals
.IncludePaths
= NewList
;
877 LastIncludePath
->Next
= NewList
;
880 LastIncludePath
= NewList
;
882 // fprintf (stdout, "Added path: %s\n", NewList->Str);
885 Error (NULL
, 0, 0, Argv
[0], "option requires an include path");
892 } else if (stricmp (Argv
[0], "-f") == 0) {
894 // Check for one more arg
898 // Allocate memory for a new list element, fill it in, and
899 // add it to our list of source files.
901 NewList
= malloc (sizeof (STRING_LIST
));
902 if (NewList
== NULL
) {
903 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
907 NewList
->Next
= NULL
;
909 // Allocate space to replace ".c" with ".obj", plus null termination
911 NewList
->Str
= malloc (strlen (Argv
[1]) + 5);
912 if (NewList
->Str
== NULL
) {
914 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
918 strcpy (NewList
->Str
, Argv
[1]);
919 if (mGlobals
.SourceFiles
== NULL
) {
920 mGlobals
.SourceFiles
= NewList
;
922 LastSourceFile
->Next
= NewList
;
925 LastSourceFile
= NewList
;
927 Error (NULL
, 0, 0, Argv
[0], "option requires a file name");
932 // The C compiler first looks for #include files in the directory where
933 // the source file came from. Add the file's source directory to the
934 // list of include paths.
936 NewList
= malloc (sizeof (STRING_LIST
));
937 if (NewList
== NULL
) {
938 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
942 NewList
->Next
= NULL
;
943 NewList
->Str
= malloc (strlen (Argv
[1]) + 3);
944 if (NewList
->Str
== NULL
) {
946 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
950 strcpy (NewList
->Str
, Argv
[1]);
952 // Back up in the source file name to the last backslash and terminate after it.
954 for (Index
= strlen (NewList
->Str
) - 1; (Index
> 0) && (NewList
->Str
[Index
] != '\\' && NewList
->Str
[Index
] != '/'); Index
--)
957 strcpy (NewList
->Str
, "./");
959 NewList
->Str
[Index
+ 1] = 0;
962 // Add it to the end of the our list of include paths
964 if (mGlobals
.IncludePaths
== NULL
) {
965 mGlobals
.IncludePaths
= NewList
;
967 LastIncludePath
->Next
= NewList
;
970 if (mGlobals
.Verbose
) {
971 fprintf (stdout
, "Adding include path: %s\n", NewList
->Str
);
974 LastIncludePath
= NewList
;
977 } else if (stricmp (Argv
[0], "-s") == 0) {
979 // -s subdir add subdirectory subdir to list of subdirecties to scan.
980 // Check for one more arg first.
984 // Allocate memory for a new list element, fill it in, and
985 // add it to our list of subdirectory include paths. Always
986 // make sure it has a "\" on the end of it.
988 NewList
= malloc (sizeof (STRING_LIST
));
989 if (NewList
== NULL
) {
990 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
994 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
995 if (NewList
->Str
== NULL
) {
997 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1001 strcpy (NewList
->Str
, Argv
[1]);
1002 if (NewList
->Str
[strlen (NewList
->Str
) - 1] != '\\' && NewList
->Str
[strlen (NewList
->Str
) - 1] != '/') {
1003 strcat (NewList
->Str
, "/");
1006 NewList
->Next
= mGlobals
.SubDirs
;
1007 mGlobals
.SubDirs
= NewList
;
1009 Error (NULL
, 0, 0, Argv
[0], "option requires a subdirectory name");
1011 return STATUS_ERROR
;
1016 } else if (stricmp (Argv
[0], "-sub") == 0) {
1018 // -sub symname symvalue to do string substitution in the output
1022 // Allocate memory for the symbol object
1024 Symbol
= malloc (sizeof (SYMBOL
));
1025 if (Symbol
== NULL
) {
1026 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1027 return STATUS_ERROR
;
1030 // Allocate memory for the symbol name and value, then save copies
1032 Symbol
->Name
= malloc (strlen (Argv
[1]) + 1);
1033 if (Symbol
->Name
== NULL
) {
1035 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1036 return STATUS_ERROR
;
1039 strcpy (Symbol
->Name
, Argv
[1]);
1040 Symbol
->Value
= malloc (strlen (Argv
[2]) + 1);
1041 if (Symbol
->Value
== NULL
) {
1042 free (Symbol
->Name
);
1044 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1045 return STATUS_ERROR
;
1048 strcpy (Symbol
->Value
, Argv
[2]);
1050 // Add it to the list
1052 Symbol
->Next
= mGlobals
.SymbolTable
;
1053 mGlobals
.SymbolTable
= Symbol
;
1055 Error (NULL
, 0, 0, Argv
[0], "option requires a symbol name and value");
1057 return STATUS_ERROR
;
1064 } else if (stricmp (Argv
[0], "-nosystem") == 0) {
1065 mGlobals
.NoSystem
= TRUE
;
1066 } else if (stricmp (Argv
[0], "-nodupes") == 0) {
1067 mGlobals
.NoDupes
= TRUE
;
1068 } else if (stricmp (Argv
[0], "-nodups") == 0) {
1069 mGlobals
.NoDupes
= TRUE
;
1070 } else if (stricmp (Argv
[0], "-target") == 0) {
1072 // -target TargetFileName - Target object file (only one allowed right
1073 // now) is TargetFileName rather than SourceFile.obj
1076 strcpy (mGlobals
.TargetFileName
, Argv
[1]);
1078 Error (NULL
, 0, 0, Argv
[0], "option requires a target file name");
1080 return STATUS_ERROR
;
1085 } else if (stricmp (Argv
[0], "-usesumdeps") == 0) {
1087 // -usesumdeps Path - if we find an included file xxx.h, and file
1088 // Path/xxx.dep exists, list Path/xxx.dep as a dependency rather than
1089 // xxx.h and don't parse xxx.h. This allows you to create a dependency
1090 // file for a commonly included file, and have its dependency file updated
1091 // only if its included files are updated. Then anyone else including this
1092 // common include file can simply have a dependency on that file's .dep file
1093 // rather than on all the files included by it. Confusing enough?
1095 mGlobals
.UseSumDeps
= 1;
1097 strcpy (mGlobals
.SumDepsPath
, Argv
[1]);
1099 // Add slash on end if not there
1101 if (mGlobals
.SumDepsPath
[strlen (mGlobals
.SumDepsPath
) - 1] != '\\' && mGlobals
.SumDepsPath
[strlen (mGlobals
.SumDepsPath
) - 1] != '/') {
1102 strcat (mGlobals
.SumDepsPath
, "/");
1105 Error (NULL
, 0, 0, Argv
[0], "option requires path to summary dependency files");
1107 return STATUS_ERROR
;
1113 } else if (stricmp (Argv
[0], "-o") == 0) {
1115 // -o OutputFileName - specify an output filename for dependency list
1116 // check for one more arg
1120 // Try to open the file
1122 if ((mGlobals
.OutFptr
= fopen (Argv
[1], "w")) == NULL
) {
1123 Error (NULL
, 0, 0, Argv
[1], "could not open file for writing");
1124 return STATUS_ERROR
;
1127 mGlobals
.OutFileName
= Argv
[1];
1129 Error (NULL
, 0, 0, Argv
[0], "option requires output file name");
1131 return STATUS_ERROR
;
1136 } else if (stricmp (Argv
[0], "-v") == 0) {
1137 mGlobals
.Verbose
= TRUE
;
1138 } else if (stricmp (Argv
[0], "-neverfail") == 0) {
1139 mGlobals
.NeverFail
= TRUE
;
1140 } else if (stricmp (Argv
[0], "-q") == 0) {
1141 mGlobals
.QuietMode
= TRUE
;
1142 } else if (stricmp (Argv
[0], "-ignorenotfound") == 0) {
1143 mGlobals
.IgnoreNotFound
= TRUE
;
1144 } else if ((stricmp (Argv
[0], "-h") == 0) || (strcmp (Argv
[0], "-?") == 0)) {
1146 return STATUS_ERROR
;
1148 Error (NULL
, 0, 0, Argv
[0], "unrecognized option");
1150 return STATUS_ERROR
;
1157 // Had to specify at least one source file
1159 if (mGlobals
.SourceFiles
== NULL
) {
1160 Error (NULL
, 0, 0, "must specify one source file name", NULL
);
1162 return STATUS_ERROR
;
1165 // Assume output to stdout if not specified
1167 if (mGlobals
.OutFptr
== NULL
) {
1168 mGlobals
.OutFptr
= stdout
;
1171 return STATUS_SUCCESS
;
1174 // Free the global string lists we allocated memory for
1186 // printf ("Free lists.....");
1188 // Traverse the include paths, freeing each
1189 // printf ("freeing include paths\n");
1191 while (mGlobals
.IncludePaths
!= NULL
) {
1192 Temp
= mGlobals
.IncludePaths
->Next
;
1194 // printf ("Freeing include path string '%s' at 0x%X\n",
1195 // mGlobals.IncludePaths->Str, (int)(mGlobals.IncludePaths->Str));
1197 free (mGlobals
.IncludePaths
->Str
);
1199 // printf ("Freeing include path object at 0x%X\n", (int)(mGlobals.IncludePaths));
1201 free (mGlobals
.IncludePaths
);
1202 mGlobals
.IncludePaths
= Temp
;
1205 // Traverse the source files, freeing each
1207 while (mGlobals
.SourceFiles
!= NULL
) {
1208 Temp
= mGlobals
.SourceFiles
->Next
;
1209 free (mGlobals
.SourceFiles
->Str
);
1210 free (mGlobals
.SourceFiles
);
1211 mGlobals
.SourceFiles
= Temp
;
1214 // Traverse the subdirectory list, freeing each
1216 while (mGlobals
.SubDirs
!= NULL
) {
1217 Temp
= mGlobals
.SubDirs
->Next
;
1218 free (mGlobals
.SubDirs
->Str
);
1219 free (mGlobals
.SubDirs
);
1220 mGlobals
.SubDirs
= Temp
;
1223 // Free the symbol table
1225 while (mGlobals
.SymbolTable
!= NULL
) {
1226 NextSym
= mGlobals
.SymbolTable
->Next
;
1227 free (mGlobals
.SymbolTable
->Name
);
1228 free (mGlobals
.SymbolTable
->Value
);
1229 mGlobals
.SymbolTable
= NextSym
;
1232 // printf ("done\n");
1243 Routine Description:
1245 Print usage information for this utility.
1258 static const char *Str
[] = {
1259 UTILITY_NAME
" -- make dependencies",
1260 " Usage: MakeDeps [options]",
1261 " Options include:",
1262 " -h or -? for this help information",
1263 " -f SourceFile add SourceFile to list of files to scan",
1264 " -i IncludePath add IncludePath to list of search paths",
1265 " -o OutputFile write output dependencies to OutputFile",
1266 " -s SubDir for each IncludePath, also search IncludePath\\SubDir",
1267 " -v for verbose output",
1268 " -ignorenotfound don't warn for files not found",
1269 " -target Target for single SourceFile, target is Target, not SourceFile.obj",
1270 " -q quiet mode to not report files not found if ignored",
1271 " -sub sym str replace all occurrances of 'str' with 'sym' in the output",
1272 " -nosystem not process system <include> files",
1273 " -neverfail always return a success return code",
1275 // " -nodupes keep track of include files, don't rescan duplicates",
1277 " -usesumdeps path use summary dependency files in 'path' directory.",
1281 for (Index
= 0; Str
[Index
] != NULL
; Index
++) {
1282 fprintf (stdout
, "%s\n", Str
[Index
]);