3 Copyright (c) 2004 - 2007, Intel Corporation. All rights reserved.<BR>
4 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
{
111 // Here's all our globals. We need a linked list of include paths, a linked
112 // list of source files, a linked list of subdirectories (appended to each
113 // include path when searching), and flags to keep track of command-line options.
116 STRING_LIST
*IncludePaths
; // all include paths to search
117 STRING_LIST
*ParentPaths
; // all parent paths to search
118 STRING_LIST
*SourceFiles
; // all source files to parse
119 STRING_LIST
*SubDirs
; // appended to each include path when searching
120 SYMBOL
*SymbolTable
; // for replacement strings
121 FILE *OutFptr
; // output dependencies to this file
122 BOOLEAN Verbose
; // for more detailed output
123 BOOLEAN IgnoreNotFound
; // no warnings if files not found
124 BOOLEAN QuietMode
; // -q - don't print missing file warnings
125 BOOLEAN NoSystem
; // don't process #include <system> files
126 BOOLEAN NeverFail
; // always return success
127 BOOLEAN NoDupes
; // to not list duplicate dependency files (for timing purposes)
128 BOOLEAN UseSumDeps
; // use summary dependency files if found
129 BOOLEAN IsAsm
; // The SourceFiles are assembler files
130 BOOLEAN IsCl
; // The SourceFiles are the output of cl with /showIncludes
131 INT8 TargetFileName
[MAX_PATH
]; // target object filename
132 INT8 SumDepsPath
[MAX_PATH
]; // path to summary files
133 INT8 TmpFileName
[MAX_PATH
]; // temp file name for output file
134 INT8
*OutFileName
; // -o option
140 INT8
*TargetFileName
,
143 STRING_LIST
*ProcessedFiles
,
144 FILE_SEARCH_TYPE FileSearchType
150 INT8
*TargetFileName
,
152 STRING_LIST
*ProcessedFiles
160 FILE_SEARCH_TYPE FileSearchType
205 Call the routine to parse the command-line options, then process each file
206 to build dependencies.
210 Argc - Standard C main() argc.
211 Argv - Standard C main() argv.
221 STRING_LIST ProcessedFiles
;
222 STRING_LIST
*TempList
;
225 INT8 TargetFileName
[MAX_PATH
];
227 SetUtilityName (UTILITY_NAME
);
229 // Process the command-line arguments
231 Status
= ProcessArgs (Argc
, Argv
);
232 if (Status
!= STATUS_SUCCESS
) {
236 // Go through the list of source files and process each.
238 memset (&ProcessedFiles
, 0, sizeof (STRING_LIST
));
239 File
= mGlobals
.SourceFiles
;
240 while (File
!= NULL
) {
242 // Clear out our list of processed files
244 TempList
= ProcessedFiles
.Next
;
245 while (ProcessedFiles
.Next
!= NULL
) {
246 TempList
= ProcessedFiles
.Next
->Next
;
247 free (ProcessedFiles
.Next
->Str
);
248 free (ProcessedFiles
.Next
);
249 ProcessedFiles
.Next
= TempList
;
252 // Replace filename extension with ".obj" if they did not
253 // specifically specify the target file
255 if (mGlobals
.TargetFileName
[0] == 0) {
256 strcpy (TargetFileName
, File
->Str
);
258 // Find the .extension
260 for (Cptr
= TargetFileName
+ strlen (TargetFileName
) - 1;
261 (*Cptr
!= '\\') && (Cptr
> TargetFileName
) && (*Cptr
!= '.');
265 if (Cptr
== TargetFileName
) {
266 Error (NULL
, 0, 0, File
->Str
, "could not locate extension in filename");
270 // Tack on the ".obj"
272 strcpy (Cptr
, ".obj");
275 // Copy the target filename they specified
277 strcpy (TargetFileName
, mGlobals
.TargetFileName
);
281 Status
= ProcessClOutput (TargetFileName
, File
->Str
, &ProcessedFiles
);
283 Status
= ProcessFile (TargetFileName
, File
->Str
, START_NEST_DEPTH
,
284 &ProcessedFiles
, SearchCurrentDir
);
286 if (Status
!= STATUS_SUCCESS
) {
299 // Free up our processed files list
301 TempList
= ProcessedFiles
.Next
;
302 while (ProcessedFiles
.Next
!= NULL
) {
303 TempList
= ProcessedFiles
.Next
->Next
;
304 free (ProcessedFiles
.Next
->Str
);
305 free (ProcessedFiles
.Next
);
306 ProcessedFiles
.Next
= TempList
;
309 // Close our temp output file
311 if ((mGlobals
.OutFptr
!= stdout
) && (mGlobals
.OutFptr
!= NULL
)) {
312 fclose (mGlobals
.OutFptr
);
315 if (mGlobals
.NeverFail
) {
316 return STATUS_SUCCESS
;
319 if (mGlobals
.OutFileName
!= NULL
) {
320 if (GetUtilityStatus () == STATUS_ERROR
) {
322 // If any errors, then delete our temp output
323 // Also try to delete target file to improve the incremental build
325 remove (mGlobals
.TmpFileName
);
326 remove (TargetFileName
);
329 // Otherwise, rename temp file to output file
331 remove (mGlobals
.OutFileName
);
332 rename (mGlobals
.TmpFileName
, mGlobals
.OutFileName
);
336 return GetUtilityStatus ();
342 INT8
*TargetFileName
,
345 STRING_LIST
*ProcessedFiles
,
346 FILE_SEARCH_TYPE FileSearchType
352 Given a source file name, open the file and parse all #include lines.
356 TargetFileName - name of the usually .obj target
357 FileName - name of the file to process
358 NestDepth - how deep we're nested in includes
359 ProcessedFiles - list of processed files.
360 FileSearchType - search type for FileName
369 INT8 Line
[MAX_LINE_LEN
];
374 INT8 FileNameCopy
[MAX_PATH
];
375 INT8 MacroIncludeFileName
[MAX_LINE_LEN
];
376 INT8 SumDepsFile
[MAX_PATH
];
380 STRING_LIST
*ListPtr
;
381 STRING_LIST ParentPath
;
383 Status
= STATUS_SUCCESS
;
386 // Print the file being processed. Indent so you can tell the include nesting
389 if (mGlobals
.Verbose
) {
390 fprintf (stdout
, "%*cProcessing file '%s'\n", NestDepth
* 2, ' ', FileName
);
393 // If we're using summary dependency files, and a matching .dep file is
394 // found for this file, then just emit the summary dependency file as
395 // a dependency and return.
397 if (mGlobals
.UseSumDeps
) {
398 strcpy (SumDepsFile
, mGlobals
.SumDepsPath
);
399 strcat (SumDepsFile
, FileName
);
400 for (Cptr
= SumDepsFile
+ strlen (SumDepsFile
) - 1;
401 (*Cptr
!= '\\') && (Cptr
> SumDepsFile
) && (*Cptr
!= '.');
406 strcpy (Cptr
, ".dep");
408 strcat (SumDepsFile
, ".dep");
411 // See if the summary dep file exists. Could use _stat() function, but
412 // it's less portable.
414 if ((Fptr
= fopen (SumDepsFile
, "r")) != NULL
) {
415 PrintDependency (TargetFileName
, SumDepsFile
);
417 return STATUS_SUCCESS
;
422 // Make sure we didn't exceed our maximum nesting depth
424 if (NestDepth
> MAX_NEST_DEPTH
) {
425 Error (NULL
, 0, 0, FileName
, "max nesting depth exceeded on file");
429 // Make a local copy of the filename. Then we can manipulate it
432 strcpy (FileNameCopy
, FileName
);
434 if (FileSearchType
== SearchCurrentDir
) {
436 // Try to open the source file locally
438 if ((Fptr
= fopen (FileNameCopy
, "r")) == NULL
) {
439 Error (NULL
, 0, 0, FileNameCopy
, "could not open source file");
444 // Try to find it among the paths.
446 Fptr
= FindFile (FileNameCopy
, sizeof (FileNameCopy
), FileSearchType
);
449 // If this is not the top-level file, and the command-line argument
450 // said to ignore missing files, then return ok
452 if (NestDepth
!= START_NEST_DEPTH
) {
453 if (mGlobals
.IgnoreNotFound
) {
454 if (!mGlobals
.QuietMode
) {
455 DebugMsg (NULL
, 0, 0, FileNameCopy
, "could not find file");
458 return STATUS_SUCCESS
;
460 Error (NULL
, 0, 0, FileNameCopy
, "could not find file");
465 // Top-level (first) file. Emit an error.
467 Error (NULL
, 0, 0, FileNameCopy
, "could not find file");
474 // If we're not doing duplicates, and we've already seen this filename,
477 if (mGlobals
.NoDupes
) {
478 for (ListPtr
= ProcessedFiles
->Next
; ListPtr
!= NULL
; ListPtr
= ListPtr
->Next
) {
479 if (_stricmp (FileNameCopy
, ListPtr
->Str
) == 0) {
484 // If we found a match, we're done. If we didn't, create a new element
485 // and add it to the list.
487 if (ListPtr
!= NULL
) {
489 // Print a message if verbose mode
491 if (mGlobals
.Verbose
) {
492 DebugMsg (NULL
, 0, 0, FileNameCopy
, "duplicate include -- not processed again");
495 return STATUS_SUCCESS
;
498 ListPtr
= malloc (sizeof (STRING_LIST
));
499 ListPtr
->Str
= malloc (strlen (FileNameCopy
) + 1);
500 strcpy (ListPtr
->Str
, FileNameCopy
);
501 ListPtr
->Next
= ProcessedFiles
->Next
;
502 ProcessedFiles
->Next
= ListPtr
;
506 // Print the dependency, with string substitution
508 PrintDependency (TargetFileName
, FileNameCopy
);
511 // Get the file path and push to ParentPaths
513 Cptr
= FileNameCopy
+ strlen (FileNameCopy
) - 1;
514 for (; (Cptr
> FileNameCopy
) && (*Cptr
!= '\\') && (*Cptr
!= '/'); Cptr
--);
515 if ((*Cptr
== '\\') || (*Cptr
== '/')) {
518 strcpy (FileNameCopy
, ".\\");
520 ParentPath
.Next
= mGlobals
.ParentPaths
;
521 ParentPath
.Str
= FileNameCopy
;
522 mGlobals
.ParentPaths
= &ParentPath
;
525 // Now read in lines and find all #include lines. Allow them to indent, and
526 // to put spaces between the # and include.
529 while ((fgets (Line
, sizeof (Line
), Fptr
) != NULL
) && (Status
== STATUS_SUCCESS
)) {
533 // Skip preceeding spaces on the line
535 while (*Cptr
&& (isspace (*Cptr
))) {
539 // Check for # character, there is no # for asm
541 if ((*Cptr
== '#') || (mGlobals
.IsAsm
)) {
547 // Check for "include", case insensitive for asm
549 while (*Cptr
&& (isspace (*Cptr
))) {
552 if (((!mGlobals
.IsAsm
) && (strncmp (Cptr
, "include", 7) == 0)) ||
553 (mGlobals
.IsAsm
&& (_strnicmp (Cptr
, "include", 7) == 0))) {
555 // Skip over "include" and move on to filename as "file" or <file> or file for asm
558 while (*Cptr
&& (isspace (*Cptr
))) {
564 } else if (*Cptr
== '"') {
566 } else if (mGlobals
.IsAsm
) {
568 // Handle include file for asm
569 // Set EndChar to null so we fall through on processing below.
574 // Look for the end of include file name
577 while (*EndPtr
&& (!isspace (*EndPtr
))) {
582 // Null terminate the filename and try to process it.
585 Status
= ProcessFile (TargetFileName
, Cptr
, NestDepth
+ 1,
586 ProcessedFiles
, SearchAllPaths
);
589 // Handle special #include MACRO_NAME(file)
590 // Set EndChar to null so we fall through on processing below.
594 // Look for all the special include macros and convert accordingly.
596 for (Index
= 0; mMacroConversion
[Index
].IncludeMacroName
!= NULL
; Index
++) {
598 // Save the start of the string in case some macros are substrings
604 mMacroConversion
[Index
].IncludeMacroName
,
605 strlen (mMacroConversion
[Index
].IncludeMacroName
)
608 // Skip over the macro name
610 Cptr
+= strlen (mMacroConversion
[Index
].IncludeMacroName
);
612 // Skip over open parenthesis, blank spaces, then find closing
613 // parenthesis or blank space
615 while (*Cptr
&& (isspace (*Cptr
))) {
621 while (*Cptr
&& (isspace (*Cptr
))) {
626 while (*EndPtr
&& !isspace (*EndPtr
) && (*EndPtr
!= ')')) {
634 strcpy (MacroIncludeFileName
, mMacroConversion
[Index
].PathName
);
635 strcat (MacroIncludeFileName
, Cptr
);
636 strcat (MacroIncludeFileName
, "\\");
637 strcat (MacroIncludeFileName
, Cptr
);
638 strcat (MacroIncludeFileName
, ".h");
640 // Process immediately, then break out of the outside FOR loop.
642 Status
= ProcessFile (TargetFileName
, MacroIncludeFileName
, NestDepth
+ 1,
643 ProcessedFiles
, SearchAllPaths
);
653 // Don't recognize the include line? Ignore it. We assume that the
654 // file compiles anyway.
656 if (mMacroConversion
[Index
].IncludeMacroName
== NULL
) {
658 // Warning (FileNameCopy, LineNum, 0, "could not parse line", NULL);
659 // Status = STATUS_WARNING;
664 // Process "normal" includes. If the endchar is 0, then the
665 // file has already been processed. Otherwise look for the
666 // endchar > or ", and process the include file.
671 while (*EndPtr
&& (*EndPtr
!= EndChar
)) {
675 if (*EndPtr
== EndChar
) {
677 // If we're processing it, do it
679 if (EndChar
!= '>') {
681 // Null terminate the filename and try to process it.
684 Status
= ProcessFile (TargetFileName
, Cptr
, NestDepth
+ 1,
685 ProcessedFiles
, SearchAllPaths
);
686 } else if (!mGlobals
.NoSystem
) {
688 // Null terminate the filename and try to process it.
691 Status
= ProcessFile (TargetFileName
, Cptr
, NestDepth
+ 1,
692 ProcessedFiles
, SearchIncludePaths
);
695 Warning (FileNameCopy
, LineNum
, 0, "malformed include", "missing closing %c", EndChar
);
696 Status
= STATUS_WARNING
;
704 // Pop the file path from ParentPaths
706 mGlobals
.ParentPaths
= ParentPath
.Next
;
710 // Close open files and return status
722 INT8
*TargetFileName
,
724 STRING_LIST
*ProcessedFiles
730 Given a source file name, open the file and parse all "Note: including file: xxx.h" lines.
734 TargetFileName - name of the usually .obj target
735 FileName - name of the file to process
736 ProcessedFiles - list of processed files.
745 INT8 Line
[MAX_LINE_LEN
];
746 INT8 IncludeFileName
[MAX_LINE_LEN
];
747 STRING_LIST
*ListPtr
;
752 if ((Fptr
= fopen (FileName
, "r")) == NULL
) {
753 Error (NULL
, 0, 0, FileName
, "could not open file for reading");
756 if (fgets (Line
, sizeof (Line
), Fptr
) != NULL
) {
758 // First line is the source file name, print it
766 Error (NULL
, 0, 0, NULL
, "incorrect cl tool path may be used ");
771 while (fgets (Line
, sizeof (Line
), Fptr
) != NULL
) {
772 Ret
= sscanf (Line
, "Note: including file: %s %c", IncludeFileName
, &Char
);
775 // There is space in include file name. It's VS header file. Ignore it.
778 } else if ( Ret
!= 1) {
780 // Cl error info, print it
781 // the tool will return error code to stop the nmake
789 // If we're not doing duplicates, and we've already seen this filename,
792 if (mGlobals
.NoDupes
) {
793 for (ListPtr
= ProcessedFiles
->Next
; ListPtr
!= NULL
; ListPtr
= ListPtr
->Next
) {
794 if (_stricmp (IncludeFileName
, ListPtr
->Str
) == 0) {
799 // If we found a match, we're done. If we didn't, create a new element
800 // and add it to the list.
802 if (ListPtr
!= NULL
) {
804 // Print a message if verbose mode
806 if (mGlobals
.Verbose
) {
807 DebugMsg (NULL
, 0, 0, IncludeFileName
, "duplicate include -- not processed again");
813 ListPtr
= malloc (sizeof (STRING_LIST
));
814 ListPtr
->Str
= malloc (strlen (IncludeFileName
) + 1);
815 strcpy (ListPtr
->Str
, IncludeFileName
);
816 ListPtr
->Next
= ProcessedFiles
->Next
;
817 ProcessedFiles
->Next
= ListPtr
;
820 PrintDependency (TargetFileName
, IncludeFileName
);
826 Error (NULL
, 0, 0, NULL
, "cl error");
829 return STATUS_SUCCESS
;
836 INT8
*TargetFileName
,
843 Given a target (.obj) file name, and a dependent file name, do any string
844 substitutions (per the command line options) on the file names, then
845 print the dependency line of form:
847 TargetFileName : DependentFile
851 TargetFileName - build target file name
852 DependentFile - file on which TargetFileName depends
863 // Go through the symbols and do replacements
865 strcpy (Str
, TargetFileName
);
866 ReplaceSymbols (Str
, sizeof (Str
));
867 fprintf (mGlobals
.OutFptr
, "%s : ", Str
);
868 strcpy (Str
, DependentFile
);
869 ReplaceSymbols (Str
, sizeof (Str
));
870 fprintf (mGlobals
.OutFptr
, "%s\n", Str
);
872 // Add pseudo target to avoid incremental build failure when the file is deleted
874 fprintf (mGlobals
.OutFptr
, "%s : \n", Str
);
885 INT8 StrCopy
[MAX_LINE_LEN
];
891 // Go through the entire string to look for replacement strings at
898 // Copy the character
903 // Go through each symbol and try to find a string substitution
905 Sym
= mGlobals
.SymbolTable
;
906 while (Sym
!= NULL
) {
907 if (_strnicmp (From
, Sym
->Value
, strlen (Sym
->Value
)) == 0) {
909 // Replace the string, then advance the pointers past the
912 strcpy (To
, Sym
->Name
);
913 To
+= strlen (Sym
->Name
);
914 From
+= strlen (Sym
->Value
);
917 // Break from the while()
931 // Null terminate, and return it
934 if (strlen (StrCopy
) < StrSize
) {
935 strcpy (Str
, StrCopy
);
939 // Given a filename, try to find it along the include paths.
946 FILE_SEARCH_TYPE FileSearchType
952 INT8 FullFileName
[MAX_PATH
* 2];
955 // Traverse the list of paths and try to find the file
957 if (FileSearchType
== SearchAllPaths
) {
958 List
= mGlobals
.ParentPaths
;
959 while (List
!= NULL
) {
961 // Put the path and filename together
963 if (strlen (List
->Str
) + strlen (FileName
) + 1 > sizeof (FullFileName
)) {
969 "cannot concatenate '%s' + '%s'",
976 // Append the filename to this include path and try to open the file.
978 strcpy (FullFileName
, List
->Str
);
979 strcat (FullFileName
, FileName
);
980 if ((Fptr
= fopen (FullFileName
, "r")) != NULL
) {
982 // Return the file name
984 if (FileNameLen
<= strlen (FullFileName
)) {
985 Error (__FILE__
, __LINE__
, 0, "application error", "internal path name of insufficient length");
987 // fprintf (stdout, "File length > %d: %s\n", FileNameLen, FullFileName);
992 strcpy (FileName
, FullFileName
);
1000 List
= mGlobals
.IncludePaths
;
1001 while (List
!= NULL
) {
1003 // Put the path and filename together
1005 if (strlen (List
->Str
) + strlen (FileName
) + 1 > sizeof (FullFileName
)) {
1010 "application error",
1011 "cannot concatenate '%s' + '%s'",
1018 // Append the filename to this include path and try to open the file.
1020 strcpy (FullFileName
, List
->Str
);
1021 strcat (FullFileName
, FileName
);
1022 if ((Fptr
= fopen (FullFileName
, "r")) != NULL
) {
1024 // Return the file name
1026 if (FileNameLen
<= strlen (FullFileName
)) {
1027 Error (__FILE__
, __LINE__
, 0, "application error", "internal path name of insufficient length");
1029 // fprintf (stdout, "File length > %d: %s\n", FileNameLen, FullFileName);
1034 strcpy (FileName
, FullFileName
);
1038 // Didn't find it there. Now try this directory with every subdirectory
1039 // the user specified on the command line
1041 for (SubDir
= mGlobals
.SubDirs
; SubDir
!= NULL
; SubDir
= SubDir
->Next
) {
1042 strcpy (FullFileName
, List
->Str
);
1043 strcat (FullFileName
, SubDir
->Str
);
1044 strcat (FullFileName
, FileName
);
1045 if ((Fptr
= fopen (FullFileName
, "r")) != NULL
) {
1047 // Return the file name
1049 if (FileNameLen
<= strlen (FullFileName
)) {
1050 Error (__FILE__
, __LINE__
, 0, "application error", "internal path name of insufficient length");
1054 strcpy (FileName
, FullFileName
);
1067 // Process the command-line arguments
1076 STRING_LIST
*NewList
;
1077 STRING_LIST
*LastIncludePath
;
1078 STRING_LIST
*LastSourceFile
;
1082 // Clear our globals
1084 memset ((char *) &mGlobals
, 0, sizeof (mGlobals
));
1085 mGlobals
.NoDupes
= TRUE
;
1087 // Skip program name
1092 // Initialize locals
1094 LastIncludePath
= NULL
;
1095 LastSourceFile
= NULL
;
1097 // Process until no more args
1101 // -i path add include search path
1103 if (_stricmp (Argv
[0], "-i") == 0) {
1105 // check for one more arg
1109 // Allocate memory for a new list element, fill it in, and
1110 // add it to our list of include paths. Always make sure it
1111 // has a "\" on the end of it.
1113 NewList
= malloc (sizeof (STRING_LIST
));
1114 if (NewList
== NULL
) {
1115 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1116 return STATUS_ERROR
;
1119 NewList
->Next
= NULL
;
1120 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
1121 if (NewList
->Str
== NULL
) {
1123 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1124 return STATUS_ERROR
;
1127 strcpy (NewList
->Str
, Argv
[1]);
1128 if (NewList
->Str
[strlen (NewList
->Str
) - 1] != '\\') {
1129 strcat (NewList
->Str
, "\\");
1132 // Add it to the end of the our list of include paths
1134 if (mGlobals
.IncludePaths
== NULL
) {
1135 mGlobals
.IncludePaths
= NewList
;
1137 LastIncludePath
->Next
= NewList
;
1140 LastIncludePath
= NewList
;
1142 // fprintf (stdout, "Added path: %s\n", NewList->Str);
1145 Error (NULL
, 0, 0, Argv
[0], "option requires an include path");
1147 return STATUS_ERROR
;
1152 } else if (_stricmp (Argv
[0], "-f") == 0) {
1154 // Check for one more arg
1158 // Allocate memory for a new list element, fill it in, and
1159 // add it to our list of source files.
1161 NewList
= malloc (sizeof (STRING_LIST
));
1162 if (NewList
== NULL
) {
1163 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1164 return STATUS_ERROR
;
1167 NewList
->Next
= NULL
;
1169 // Allocate space to replace ".c" with ".obj", plus null termination
1171 NewList
->Str
= malloc (strlen (Argv
[1]) + 5);
1172 if (NewList
->Str
== NULL
) {
1174 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1175 return STATUS_ERROR
;
1178 strcpy (NewList
->Str
, Argv
[1]);
1179 if (mGlobals
.SourceFiles
== NULL
) {
1180 mGlobals
.SourceFiles
= NewList
;
1182 LastSourceFile
->Next
= NewList
;
1185 LastSourceFile
= NewList
;
1187 Error (NULL
, 0, 0, Argv
[0], "option requires a file name");
1189 return STATUS_ERROR
;
1194 } else if (_stricmp (Argv
[0], "-s") == 0) {
1196 // -s subdir add subdirectory subdir to list of subdirecties to scan.
1197 // Check for one more arg first.
1201 // Allocate memory for a new list element, fill it in, and
1202 // add it to our list of subdirectory include paths. Always
1203 // make sure it has a "\" on the end of it.
1205 NewList
= malloc (sizeof (STRING_LIST
));
1206 if (NewList
== NULL
) {
1207 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1208 return STATUS_ERROR
;
1211 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
1212 if (NewList
->Str
== NULL
) {
1214 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1215 return STATUS_ERROR
;
1218 strcpy (NewList
->Str
, Argv
[1]);
1219 if (NewList
->Str
[strlen (NewList
->Str
) - 1] != '\\') {
1220 strcat (NewList
->Str
, "\\");
1223 NewList
->Next
= mGlobals
.SubDirs
;
1224 mGlobals
.SubDirs
= NewList
;
1226 Error (NULL
, 0, 0, Argv
[0], "option requires a subdirectory name");
1228 return STATUS_ERROR
;
1233 } else if (_stricmp (Argv
[0], "-sub") == 0) {
1235 // -sub symname symvalue to do string substitution in the output
1239 // Allocate memory for the symbol object
1241 Symbol
= malloc (sizeof (SYMBOL
));
1242 if (Symbol
== NULL
) {
1243 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1244 return STATUS_ERROR
;
1247 // Allocate memory for the symbol name and value, then save copies
1249 Symbol
->Name
= malloc (strlen (Argv
[1]) + 1);
1250 if (Symbol
->Name
== NULL
) {
1252 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1253 return STATUS_ERROR
;
1256 strcpy (Symbol
->Name
, Argv
[1]);
1257 Symbol
->Value
= malloc (strlen (Argv
[2]) + 1);
1258 if (Symbol
->Value
== NULL
) {
1259 free (Symbol
->Name
);
1261 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1262 return STATUS_ERROR
;
1265 strcpy (Symbol
->Value
, Argv
[2]);
1267 // Add it to the list
1269 Symbol
->Next
= mGlobals
.SymbolTable
;
1270 mGlobals
.SymbolTable
= Symbol
;
1272 Error (NULL
, 0, 0, Argv
[0], "option requires a symbol name and value");
1274 return STATUS_ERROR
;
1281 } else if (_stricmp (Argv
[0], "-nosystem") == 0) {
1282 mGlobals
.NoSystem
= TRUE
;
1283 } else if (_stricmp (Argv
[0], "-nodupes") == 0) {
1284 mGlobals
.NoDupes
= TRUE
;
1285 } else if (_stricmp (Argv
[0], "-nodups") == 0) {
1286 mGlobals
.NoDupes
= TRUE
;
1287 } else if (_stricmp (Argv
[0], "-target") == 0) {
1289 // -target TargetFileName - Target object file (only one allowed right
1290 // now) is TargetFileName rather than SourceFile.obj
1293 strcpy (mGlobals
.TargetFileName
, Argv
[1]);
1295 Error (NULL
, 0, 0, Argv
[0], "option requires a target file name");
1297 return STATUS_ERROR
;
1302 } else if (_stricmp (Argv
[0], "-usesumdeps") == 0) {
1304 // -usesumdeps Path - if we find an included file xxx.h, and file
1305 // Path/xxx.dep exists, list Path/xxx.dep as a dependency rather than
1306 // xxx.h and don't parse xxx.h. This allows you to create a dependency
1307 // file for a commonly included file, and have its dependency file updated
1308 // only if its included files are updated. Then anyone else including this
1309 // common include file can simply have a dependency on that file's .dep file
1310 // rather than on all the files included by it. Confusing enough?
1312 mGlobals
.UseSumDeps
= 1;
1314 strcpy (mGlobals
.SumDepsPath
, Argv
[1]);
1316 // Add slash on end if not there
1318 if (mGlobals
.SumDepsPath
[strlen (mGlobals
.SumDepsPath
) - 1] != '\\') {
1319 strcat (mGlobals
.SumDepsPath
, "\\");
1322 Error (NULL
, 0, 0, Argv
[0], "option requires path to summary dependency files");
1324 return STATUS_ERROR
;
1330 } else if (_stricmp (Argv
[0], "-o") == 0) {
1332 // -o OutputFileName - specify an output filename for dependency list
1333 // check for one more arg
1336 mGlobals
.OutFileName
= Argv
[1];
1338 // Use temp file for output
1339 // This can avoid overwriting previous existed dep file when error
1340 // ocurred in this tool
1342 sprintf (mGlobals
.TmpFileName
, "%s2", mGlobals
.OutFileName
);
1344 // Try to open the temp file
1346 if ((mGlobals
.OutFptr
= fopen (mGlobals
.TmpFileName
, "w")) == NULL
) {
1347 Error (NULL
, 0, 0, mGlobals
.TmpFileName
, "could not open file for writing");
1348 return STATUS_ERROR
;
1351 Error (NULL
, 0, 0, Argv
[0], "option requires output file name");
1353 return STATUS_ERROR
;
1358 } else if (_stricmp (Argv
[0], "-v") == 0) {
1359 mGlobals
.Verbose
= TRUE
;
1360 } else if (_stricmp (Argv
[0], "-neverfail") == 0) {
1361 mGlobals
.NeverFail
= TRUE
;
1362 } else if (_stricmp (Argv
[0], "-q") == 0) {
1363 mGlobals
.QuietMode
= TRUE
;
1364 } else if (_stricmp (Argv
[0], "-ignorenotfound") == 0) {
1365 mGlobals
.IgnoreNotFound
= TRUE
;
1366 } else if (_stricmp (Argv
[0], "-asm") == 0) {
1367 if (mGlobals
.IsCl
) {
1368 Error (NULL
, 0, 0, Argv
[0], "option conflict with -cl");
1369 return STATUS_ERROR
;
1371 mGlobals
.IsAsm
= TRUE
;
1372 } else if (_stricmp (Argv
[0], "-cl") == 0) {
1373 if (mGlobals
.IsAsm
) {
1374 Error (NULL
, 0, 0, Argv
[0], "option conflict with -asm");
1375 return STATUS_ERROR
;
1377 mGlobals
.IsCl
= TRUE
;
1378 } else if ((_stricmp (Argv
[0], "-h") == 0) || (strcmp (Argv
[0], "-?") == 0)) {
1380 return STATUS_ERROR
;
1382 Error (NULL
, 0, 0, Argv
[0], "unrecognized option");
1384 return STATUS_ERROR
;
1391 // Had to specify at least one source file
1393 if (mGlobals
.SourceFiles
== NULL
) {
1394 Error (NULL
, 0, 0, "must specify one source file name", NULL
);
1396 return STATUS_ERROR
;
1399 // Assume output to stdout if not specified
1401 if (mGlobals
.OutFptr
== NULL
) {
1402 mGlobals
.OutFptr
= stdout
;
1405 return STATUS_SUCCESS
;
1408 // Free the global string lists we allocated memory for
1420 // printf ("Free lists.....");
1422 // Traverse the include paths, freeing each
1423 // printf ("freeing include paths\n");
1425 while (mGlobals
.IncludePaths
!= NULL
) {
1426 Temp
= mGlobals
.IncludePaths
->Next
;
1428 // printf ("Freeing include path string '%s' at 0x%X\n",
1429 // mGlobals.IncludePaths->Str, (int)(mGlobals.IncludePaths->Str));
1431 free (mGlobals
.IncludePaths
->Str
);
1433 // printf ("Freeing include path object at 0x%X\n", (int)(mGlobals.IncludePaths));
1435 free (mGlobals
.IncludePaths
);
1436 mGlobals
.IncludePaths
= Temp
;
1439 // Traverse the source files, freeing each
1441 while (mGlobals
.SourceFiles
!= NULL
) {
1442 Temp
= mGlobals
.SourceFiles
->Next
;
1443 free (mGlobals
.SourceFiles
->Str
);
1444 free (mGlobals
.SourceFiles
);
1445 mGlobals
.SourceFiles
= Temp
;
1448 // Traverse the subdirectory list, freeing each
1450 while (mGlobals
.SubDirs
!= NULL
) {
1451 Temp
= mGlobals
.SubDirs
->Next
;
1452 free (mGlobals
.SubDirs
->Str
);
1453 free (mGlobals
.SubDirs
);
1454 mGlobals
.SubDirs
= Temp
;
1457 // Free the symbol table
1459 while (mGlobals
.SymbolTable
!= NULL
) {
1460 NextSym
= mGlobals
.SymbolTable
->Next
;
1461 free (mGlobals
.SymbolTable
->Name
);
1462 free (mGlobals
.SymbolTable
->Value
);
1463 mGlobals
.SymbolTable
= NextSym
;
1466 // printf ("done\n");
1477 Routine Description:
1479 Print usage information for this utility.
1492 static const char *Str
[] = {
1493 UTILITY_NAME
" -- make dependencies",
1494 " Usage: MakeDeps [options]",
1495 " Options include:",
1496 " -h or -? for this help information",
1497 " -f SourceFile add SourceFile to list of files to scan",
1498 " -i IncludePath add IncludePath to list of search paths",
1499 " -o OutputFile write output dependencies to OutputFile",
1500 " -s SubDir for each IncludePath, also search IncludePath\\SubDir",
1501 " -v for verbose output",
1502 " -ignorenotfound don't warn for files not found",
1503 " -target Target for single SourceFile, target is Target, not SourceFile.obj",
1504 " -q quiet mode to not report files not found if ignored",
1505 " -sub sym str replace all occurrances of 'str' with 'sym' in the output",
1506 " -nosystem not process system <include> files",
1507 " -neverfail always return a success return code",
1509 // " -nodupes keep track of include files, don't rescan duplicates",
1511 " -usesumdeps path use summary dependency files in 'path' directory.",
1512 " -asm The SourceFiles are assembler files",
1513 " -cl The SourceFiles are the output of cl with /showIncludes",
1517 for (Index
= 0; Str
[Index
] != NULL
; Index
++) {
1518 fprintf (stdout
, "%s\n", Str
[Index
]);