3 Copyright (c) 2004 - 2010, 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"
40 #define UTILITY_VERSION "v1.0"
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
;
112 // Here's all our globals. We need a linked list of include paths, a linked
113 // list of source files, a linked list of subdirectories (appended to each
114 // include path when searching), and flags to keep track of command-line options.
117 STRING_LIST
*IncludePaths
; // all include paths to search
118 STRING_LIST
*ParentPaths
; // all parent paths to search
119 STRING_LIST
*SourceFiles
; // all source files to parse
120 STRING_LIST
*SubDirs
; // appended to each include path when searching
121 SYMBOL
*SymbolTable
; // for replacement strings
122 FILE *OutFptr
; // output dependencies to this file
123 BOOLEAN Verbose
; // for more detailed output
124 BOOLEAN IgnoreNotFound
; // no warnings if files not found
125 BOOLEAN QuietMode
; // -q - don't print missing file warnings
126 BOOLEAN NoSystem
; // don't process #include <system> files
127 BOOLEAN NeverFail
; // always return success
128 BOOLEAN NoDupes
; // to not list duplicate dependency files (for timing purposes)
129 BOOLEAN UseSumDeps
; // use summary dependency files if found
130 BOOLEAN IsAsm
; // The SourceFiles are assembler files
131 BOOLEAN IsCl
; // The SourceFiles are the output of cl with /showIncludes
132 INT8 TargetFileName
[MAX_PATH
]; // target object filename
133 INT8 SumDepsPath
[MAX_PATH
]; // path to summary files
134 INT8 TmpFileName
[MAX_PATH
]; // temp file name for output file
135 INT8
*OutFileName
; // -o option
141 INT8
*TargetFileName
,
144 STRING_LIST
*ProcessedFiles
,
145 FILE_SEARCH_TYPE FileSearchType
151 INT8
*TargetFileName
,
153 STRING_LIST
*ProcessedFiles
161 FILE_SEARCH_TYPE FileSearchType
206 Call the routine to parse the command-line options, then process each file
207 to build dependencies.
211 Argc - Standard C main() argc.
212 Argv - Standard C main() argv.
222 STRING_LIST ProcessedFiles
;
223 STRING_LIST
*TempList
;
226 INT8 TargetFileName
[MAX_PATH
];
228 SetUtilityName (UTILITY_NAME
);
230 // Process the command-line arguments
232 Status
= ProcessArgs (Argc
, Argv
);
233 if (Status
!= STATUS_SUCCESS
) {
237 // Go through the list of source files and process each.
239 memset (&ProcessedFiles
, 0, sizeof (STRING_LIST
));
240 File
= mGlobals
.SourceFiles
;
241 while (File
!= NULL
) {
243 // Clear out our list of processed files
245 TempList
= ProcessedFiles
.Next
;
246 while (ProcessedFiles
.Next
!= NULL
) {
247 TempList
= ProcessedFiles
.Next
->Next
;
248 free (ProcessedFiles
.Next
->Str
);
249 free (ProcessedFiles
.Next
);
250 ProcessedFiles
.Next
= TempList
;
253 // Replace filename extension with ".obj" if they did not
254 // specifically specify the target file
256 if (mGlobals
.TargetFileName
[0] == 0) {
257 strcpy (TargetFileName
, File
->Str
);
259 // Find the .extension
261 for (Cptr
= TargetFileName
+ strlen (TargetFileName
) - 1;
262 (*Cptr
!= '\\') && (Cptr
> TargetFileName
) && (*Cptr
!= '.');
266 if (Cptr
== TargetFileName
) {
267 Error (NULL
, 0, 0, File
->Str
, "could not locate extension in filename");
271 // Tack on the ".obj"
273 strcpy (Cptr
, ".obj");
276 // Copy the target filename they specified
278 strcpy (TargetFileName
, mGlobals
.TargetFileName
);
282 Status
= ProcessClOutput (TargetFileName
, File
->Str
, &ProcessedFiles
);
284 Status
= ProcessFile (TargetFileName
, File
->Str
, START_NEST_DEPTH
,
285 &ProcessedFiles
, SearchCurrentDir
);
287 if (Status
!= STATUS_SUCCESS
) {
300 // Free up our processed files list
302 TempList
= ProcessedFiles
.Next
;
303 while (ProcessedFiles
.Next
!= NULL
) {
304 TempList
= ProcessedFiles
.Next
->Next
;
305 free (ProcessedFiles
.Next
->Str
);
306 free (ProcessedFiles
.Next
);
307 ProcessedFiles
.Next
= TempList
;
310 // Close our temp output file
312 if ((mGlobals
.OutFptr
!= stdout
) && (mGlobals
.OutFptr
!= NULL
)) {
313 fclose (mGlobals
.OutFptr
);
316 if (mGlobals
.NeverFail
) {
317 return STATUS_SUCCESS
;
320 if (mGlobals
.OutFileName
!= NULL
) {
321 if (GetUtilityStatus () == STATUS_ERROR
) {
323 // If any errors, then delete our temp output
324 // Also try to delete target file to improve the incremental build
326 remove (mGlobals
.TmpFileName
);
327 remove (TargetFileName
);
330 // Otherwise, rename temp file to output file
332 remove (mGlobals
.OutFileName
);
333 rename (mGlobals
.TmpFileName
, mGlobals
.OutFileName
);
337 return GetUtilityStatus ();
343 INT8
*TargetFileName
,
346 STRING_LIST
*ProcessedFiles
,
347 FILE_SEARCH_TYPE FileSearchType
353 Given a source file name, open the file and parse all #include lines.
357 TargetFileName - name of the usually .obj target
358 FileName - name of the file to process
359 NestDepth - how deep we're nested in includes
360 ProcessedFiles - list of processed files.
361 FileSearchType - search type for FileName
370 INT8 Line
[MAX_LINE_LEN
];
375 INT8 FileNameCopy
[MAX_PATH
];
376 INT8 MacroIncludeFileName
[MAX_LINE_LEN
];
377 INT8 SumDepsFile
[MAX_PATH
];
381 STRING_LIST
*ListPtr
;
382 STRING_LIST ParentPath
;
384 Status
= STATUS_SUCCESS
;
387 // Print the file being processed. Indent so you can tell the include nesting
390 if (mGlobals
.Verbose
) {
391 fprintf (stdout
, "%*cProcessing file '%s'\n", NestDepth
* 2, ' ', FileName
);
394 // If we're using summary dependency files, and a matching .dep file is
395 // found for this file, then just emit the summary dependency file as
396 // a dependency and return.
398 if (mGlobals
.UseSumDeps
) {
399 strcpy (SumDepsFile
, mGlobals
.SumDepsPath
);
400 strcat (SumDepsFile
, FileName
);
401 for (Cptr
= SumDepsFile
+ strlen (SumDepsFile
) - 1;
402 (*Cptr
!= '\\') && (Cptr
> SumDepsFile
) && (*Cptr
!= '.');
407 strcpy (Cptr
, ".dep");
409 strcat (SumDepsFile
, ".dep");
412 // See if the summary dep file exists. Could use _stat() function, but
413 // it's less portable.
415 if ((Fptr
= fopen (SumDepsFile
, "r")) != NULL
) {
416 PrintDependency (TargetFileName
, SumDepsFile
);
418 return STATUS_SUCCESS
;
423 // Make sure we didn't exceed our maximum nesting depth
425 if (NestDepth
> MAX_NEST_DEPTH
) {
426 Error (NULL
, 0, 0, FileName
, "max nesting depth exceeded on file");
430 // Make a local copy of the filename. Then we can manipulate it
433 strcpy (FileNameCopy
, FileName
);
435 if (FileSearchType
== SearchCurrentDir
) {
437 // Try to open the source file locally
439 if ((Fptr
= fopen (FileNameCopy
, "r")) == NULL
) {
440 Error (NULL
, 0, 0, FileNameCopy
, "could not open source file");
445 // Try to find it among the paths.
447 Fptr
= FindFile (FileNameCopy
, sizeof (FileNameCopy
), FileSearchType
);
450 // If this is not the top-level file, and the command-line argument
451 // said to ignore missing files, then return ok
453 if (NestDepth
!= START_NEST_DEPTH
) {
454 if (mGlobals
.IgnoreNotFound
) {
455 if (!mGlobals
.QuietMode
) {
456 DebugMsg (NULL
, 0, 0, FileNameCopy
, "could not find file");
459 return STATUS_SUCCESS
;
461 Error (NULL
, 0, 0, FileNameCopy
, "could not find file");
466 // Top-level (first) file. Emit an error.
468 Error (NULL
, 0, 0, FileNameCopy
, "could not find file");
475 // If we're not doing duplicates, and we've already seen this filename,
478 if (mGlobals
.NoDupes
) {
479 for (ListPtr
= ProcessedFiles
->Next
; ListPtr
!= NULL
; ListPtr
= ListPtr
->Next
) {
480 if (_stricmp (FileNameCopy
, ListPtr
->Str
) == 0) {
485 // If we found a match, we're done. If we didn't, create a new element
486 // and add it to the list.
488 if (ListPtr
!= NULL
) {
490 // Print a message if verbose mode
492 if (mGlobals
.Verbose
) {
493 DebugMsg (NULL
, 0, 0, FileNameCopy
, "duplicate include -- not processed again");
496 return STATUS_SUCCESS
;
499 ListPtr
= malloc (sizeof (STRING_LIST
));
500 ListPtr
->Str
= malloc (strlen (FileNameCopy
) + 1);
501 strcpy (ListPtr
->Str
, FileNameCopy
);
502 ListPtr
->Next
= ProcessedFiles
->Next
;
503 ProcessedFiles
->Next
= ListPtr
;
507 // Print the dependency, with string substitution
509 PrintDependency (TargetFileName
, FileNameCopy
);
512 // Get the file path and push to ParentPaths
514 Cptr
= FileNameCopy
+ strlen (FileNameCopy
) - 1;
515 for (; (Cptr
> FileNameCopy
) && (*Cptr
!= '\\') && (*Cptr
!= '/'); Cptr
--);
516 if ((*Cptr
== '\\') || (*Cptr
== '/')) {
519 strcpy (FileNameCopy
, ".\\");
521 ParentPath
.Next
= mGlobals
.ParentPaths
;
522 ParentPath
.Str
= FileNameCopy
;
523 mGlobals
.ParentPaths
= &ParentPath
;
526 // Now read in lines and find all #include lines. Allow them to indent, and
527 // to put spaces between the # and include.
530 while ((fgets (Line
, sizeof (Line
), Fptr
) != NULL
) && (Status
== STATUS_SUCCESS
)) {
534 // Skip preceeding spaces on the line
536 while (*Cptr
&& (isspace (*Cptr
))) {
540 // Check for # character, there is no # for asm
542 if ((*Cptr
== '#') || (mGlobals
.IsAsm
)) {
548 // Check for "include", case insensitive for asm
550 while (*Cptr
&& (isspace (*Cptr
))) {
553 if (((!mGlobals
.IsAsm
) && (strncmp (Cptr
, "include", 7) == 0)) ||
554 (mGlobals
.IsAsm
&& (_strnicmp (Cptr
, "include", 7) == 0))) {
556 // Skip over "include" and move on to filename as "file" or <file> or file for asm
559 while (*Cptr
&& (isspace (*Cptr
))) {
565 } else if (*Cptr
== '"') {
567 } else if (mGlobals
.IsAsm
) {
569 // Handle include file for asm
570 // Set EndChar to null so we fall through on processing below.
575 // Look for the end of include file name
578 while (*EndPtr
&& (!isspace (*EndPtr
))) {
583 // Null terminate the filename and try to process it.
586 Status
= ProcessFile (TargetFileName
, Cptr
, NestDepth
+ 1,
587 ProcessedFiles
, SearchAllPaths
);
590 // Handle special #include MACRO_NAME(file)
591 // Set EndChar to null so we fall through on processing below.
595 // Look for all the special include macros and convert accordingly.
597 for (Index
= 0; mMacroConversion
[Index
].IncludeMacroName
!= NULL
; Index
++) {
599 // Save the start of the string in case some macros are substrings
605 mMacroConversion
[Index
].IncludeMacroName
,
606 strlen (mMacroConversion
[Index
].IncludeMacroName
)
609 // Skip over the macro name
611 Cptr
+= strlen (mMacroConversion
[Index
].IncludeMacroName
);
613 // Skip over open parenthesis, blank spaces, then find closing
614 // parenthesis or blank space
616 while (*Cptr
&& (isspace (*Cptr
))) {
622 while (*Cptr
&& (isspace (*Cptr
))) {
627 while (*EndPtr
&& !isspace (*EndPtr
) && (*EndPtr
!= ')')) {
635 strcpy (MacroIncludeFileName
, mMacroConversion
[Index
].PathName
);
636 strcat (MacroIncludeFileName
, Cptr
);
637 strcat (MacroIncludeFileName
, "\\");
638 strcat (MacroIncludeFileName
, Cptr
);
639 strcat (MacroIncludeFileName
, ".h");
641 // Process immediately, then break out of the outside FOR loop.
643 Status
= ProcessFile (TargetFileName
, MacroIncludeFileName
, NestDepth
+ 1,
644 ProcessedFiles
, SearchAllPaths
);
654 // Don't recognize the include line? Ignore it. We assume that the
655 // file compiles anyway.
657 if (mMacroConversion
[Index
].IncludeMacroName
== NULL
) {
659 // Warning (FileNameCopy, LineNum, 0, "could not parse line", NULL);
660 // Status = STATUS_WARNING;
665 // Process "normal" includes. If the endchar is 0, then the
666 // file has already been processed. Otherwise look for the
667 // endchar > or ", and process the include file.
672 while (*EndPtr
&& (*EndPtr
!= EndChar
)) {
676 if (*EndPtr
== EndChar
) {
678 // If we're processing it, do it
680 if (EndChar
!= '>') {
682 // Null terminate the filename and try to process it.
685 Status
= ProcessFile (TargetFileName
, Cptr
, NestDepth
+ 1,
686 ProcessedFiles
, SearchAllPaths
);
687 } else if (!mGlobals
.NoSystem
) {
689 // Null terminate the filename and try to process it.
692 Status
= ProcessFile (TargetFileName
, Cptr
, NestDepth
+ 1,
693 ProcessedFiles
, SearchIncludePaths
);
696 Warning (FileNameCopy
, LineNum
, 0, "malformed include", "missing closing %c", EndChar
);
697 Status
= STATUS_WARNING
;
705 // Pop the file path from ParentPaths
707 mGlobals
.ParentPaths
= ParentPath
.Next
;
711 // Close open files and return status
723 INT8
*TargetFileName
,
725 STRING_LIST
*ProcessedFiles
731 Given a source file name, open the file and parse all "Note: including file: xxx.h" lines.
735 TargetFileName - name of the usually .obj target
736 FileName - name of the file to process
737 ProcessedFiles - list of processed files.
746 INT8 Line
[MAX_LINE_LEN
];
747 INT8 IncludeFileName
[MAX_LINE_LEN
];
748 STRING_LIST
*ListPtr
;
753 if ((Fptr
= fopen (FileName
, "r")) == NULL
) {
754 Error (NULL
, 0, 0, FileName
, "could not open file for reading");
757 if (fgets (Line
, sizeof (Line
), Fptr
) != NULL
) {
759 // First line is the source file name, print it
767 Error (NULL
, 0, 0, NULL
, "incorrect cl tool path may be used ");
772 while (fgets (Line
, sizeof (Line
), Fptr
) != NULL
) {
773 Ret
= sscanf (Line
, "Note: including file: %s %c", IncludeFileName
, &Char
);
776 // There is space in include file name. It's VS header file. Ignore it.
779 } else if ( Ret
!= 1) {
781 // Cl error info, print it
782 // the tool will return error code to stop the nmake
790 // If we're not doing duplicates, and we've already seen this filename,
793 if (mGlobals
.NoDupes
) {
794 for (ListPtr
= ProcessedFiles
->Next
; ListPtr
!= NULL
; ListPtr
= ListPtr
->Next
) {
795 if (_stricmp (IncludeFileName
, ListPtr
->Str
) == 0) {
800 // If we found a match, we're done. If we didn't, create a new element
801 // and add it to the list.
803 if (ListPtr
!= NULL
) {
805 // Print a message if verbose mode
807 if (mGlobals
.Verbose
) {
808 DebugMsg (NULL
, 0, 0, IncludeFileName
, "duplicate include -- not processed again");
814 ListPtr
= malloc (sizeof (STRING_LIST
));
815 ListPtr
->Str
= malloc (strlen (IncludeFileName
) + 1);
816 strcpy (ListPtr
->Str
, IncludeFileName
);
817 ListPtr
->Next
= ProcessedFiles
->Next
;
818 ProcessedFiles
->Next
= ListPtr
;
821 PrintDependency (TargetFileName
, IncludeFileName
);
827 Error (NULL
, 0, 0, NULL
, "cl error");
830 return STATUS_SUCCESS
;
837 INT8
*TargetFileName
,
844 Given a target (.obj) file name, and a dependent file name, do any string
845 substitutions (per the command line options) on the file names, then
846 print the dependency line of form:
848 TargetFileName : DependentFile
852 TargetFileName - build target file name
853 DependentFile - file on which TargetFileName depends
864 // Go through the symbols and do replacements
866 strcpy (Str
, TargetFileName
);
867 ReplaceSymbols (Str
, sizeof (Str
));
868 fprintf (mGlobals
.OutFptr
, "%s : ", Str
);
869 strcpy (Str
, DependentFile
);
870 ReplaceSymbols (Str
, sizeof (Str
));
871 fprintf (mGlobals
.OutFptr
, "%s\n", Str
);
873 // Add pseudo target to avoid incremental build failure when the file is deleted
875 fprintf (mGlobals
.OutFptr
, "%s : \n", Str
);
886 INT8 StrCopy
[MAX_LINE_LEN
];
892 // Go through the entire string to look for replacement strings at
899 // Copy the character
904 // Go through each symbol and try to find a string substitution
906 Sym
= mGlobals
.SymbolTable
;
907 while (Sym
!= NULL
) {
908 if (_strnicmp (From
, Sym
->Value
, strlen (Sym
->Value
)) == 0) {
910 // Replace the string, then advance the pointers past the
913 strcpy (To
, Sym
->Name
);
914 To
+= strlen (Sym
->Name
);
915 From
+= strlen (Sym
->Value
);
918 // Break from the while()
932 // Null terminate, and return it
935 if (strlen (StrCopy
) < StrSize
) {
936 strcpy (Str
, StrCopy
);
940 // Given a filename, try to find it along the include paths.
947 FILE_SEARCH_TYPE FileSearchType
953 INT8 FullFileName
[MAX_PATH
* 2];
956 // Traverse the list of paths and try to find the file
958 if (FileSearchType
== SearchAllPaths
) {
959 List
= mGlobals
.ParentPaths
;
960 while (List
!= NULL
) {
962 // Put the path and filename together
964 if (strlen (List
->Str
) + strlen (FileName
) + 1 > sizeof (FullFileName
)) {
970 "cannot concatenate '%s' + '%s'",
977 // Append the filename to this include path and try to open the file.
979 strcpy (FullFileName
, List
->Str
);
980 strcat (FullFileName
, FileName
);
981 if ((Fptr
= fopen (FullFileName
, "r")) != NULL
) {
983 // Return the file name
985 if (FileNameLen
<= strlen (FullFileName
)) {
986 Error (__FILE__
, __LINE__
, 0, "application error", "internal path name of insufficient length");
988 // fprintf (stdout, "File length > %d: %s\n", FileNameLen, FullFileName);
993 strcpy (FileName
, FullFileName
);
1001 List
= mGlobals
.IncludePaths
;
1002 while (List
!= NULL
) {
1004 // Put the path and filename together
1006 if (strlen (List
->Str
) + strlen (FileName
) + 1 > sizeof (FullFileName
)) {
1011 "application error",
1012 "cannot concatenate '%s' + '%s'",
1019 // Append the filename to this include path and try to open the file.
1021 strcpy (FullFileName
, List
->Str
);
1022 strcat (FullFileName
, FileName
);
1023 if ((Fptr
= fopen (FullFileName
, "r")) != NULL
) {
1025 // Return the file name
1027 if (FileNameLen
<= strlen (FullFileName
)) {
1028 Error (__FILE__
, __LINE__
, 0, "application error", "internal path name of insufficient length");
1030 // fprintf (stdout, "File length > %d: %s\n", FileNameLen, FullFileName);
1035 strcpy (FileName
, FullFileName
);
1039 // Didn't find it there. Now try this directory with every subdirectory
1040 // the user specified on the command line
1042 for (SubDir
= mGlobals
.SubDirs
; SubDir
!= NULL
; SubDir
= SubDir
->Next
) {
1043 strcpy (FullFileName
, List
->Str
);
1044 strcat (FullFileName
, SubDir
->Str
);
1045 strcat (FullFileName
, FileName
);
1046 if ((Fptr
= fopen (FullFileName
, "r")) != NULL
) {
1048 // Return the file name
1050 if (FileNameLen
<= strlen (FullFileName
)) {
1051 Error (__FILE__
, __LINE__
, 0, "application error", "internal path name of insufficient length");
1055 strcpy (FileName
, FullFileName
);
1068 // Process the command-line arguments
1077 STRING_LIST
*NewList
;
1078 STRING_LIST
*LastIncludePath
;
1079 STRING_LIST
*LastSourceFile
;
1083 // Clear our globals
1085 memset ((char *) &mGlobals
, 0, sizeof (mGlobals
));
1086 mGlobals
.NoDupes
= TRUE
;
1088 // Skip program name
1093 // Initialize locals
1095 LastIncludePath
= NULL
;
1096 LastSourceFile
= NULL
;
1098 // Process until no more args
1102 // -i path add include search path
1104 if (_stricmp (Argv
[0], "-i") == 0) {
1106 // check for one more arg
1110 // Allocate memory for a new list element, fill it in, and
1111 // add it to our list of include paths. Always make sure it
1112 // has a "\" on the end of it.
1114 NewList
= malloc (sizeof (STRING_LIST
));
1115 if (NewList
== NULL
) {
1116 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1117 return STATUS_ERROR
;
1120 NewList
->Next
= NULL
;
1121 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
1122 if (NewList
->Str
== NULL
) {
1124 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1125 return STATUS_ERROR
;
1128 strcpy (NewList
->Str
, Argv
[1]);
1129 if (NewList
->Str
[strlen (NewList
->Str
) - 1] != '\\') {
1130 strcat (NewList
->Str
, "\\");
1133 // Add it to the end of the our list of include paths
1135 if (mGlobals
.IncludePaths
== NULL
) {
1136 mGlobals
.IncludePaths
= NewList
;
1138 LastIncludePath
->Next
= NewList
;
1141 LastIncludePath
= NewList
;
1143 // fprintf (stdout, "Added path: %s\n", NewList->Str);
1146 Error (NULL
, 0, 0, Argv
[0], "option requires an include path");
1148 return STATUS_ERROR
;
1153 } else if (_stricmp (Argv
[0], "-f") == 0) {
1155 // Check for one more arg
1159 // Allocate memory for a new list element, fill it in, and
1160 // add it to our list of source files.
1162 NewList
= malloc (sizeof (STRING_LIST
));
1163 if (NewList
== NULL
) {
1164 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1165 return STATUS_ERROR
;
1168 NewList
->Next
= NULL
;
1170 // Allocate space to replace ".c" with ".obj", plus null termination
1172 NewList
->Str
= malloc (strlen (Argv
[1]) + 5);
1173 if (NewList
->Str
== NULL
) {
1175 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1176 return STATUS_ERROR
;
1179 strcpy (NewList
->Str
, Argv
[1]);
1180 if (mGlobals
.SourceFiles
== NULL
) {
1181 mGlobals
.SourceFiles
= NewList
;
1183 LastSourceFile
->Next
= NewList
;
1186 LastSourceFile
= NewList
;
1188 Error (NULL
, 0, 0, Argv
[0], "option requires a file name");
1190 return STATUS_ERROR
;
1195 } else if (_stricmp (Argv
[0], "-s") == 0) {
1197 // -s subdir add subdirectory subdir to list of subdirecties to scan.
1198 // Check for one more arg first.
1202 // Allocate memory for a new list element, fill it in, and
1203 // add it to our list of subdirectory include paths. Always
1204 // make sure it has a "\" on the end of it.
1206 NewList
= malloc (sizeof (STRING_LIST
));
1207 if (NewList
== NULL
) {
1208 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1209 return STATUS_ERROR
;
1212 NewList
->Str
= malloc (strlen (Argv
[1]) + 2);
1213 if (NewList
->Str
== NULL
) {
1215 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1216 return STATUS_ERROR
;
1219 strcpy (NewList
->Str
, Argv
[1]);
1220 if (NewList
->Str
[strlen (NewList
->Str
) - 1] != '\\') {
1221 strcat (NewList
->Str
, "\\");
1224 NewList
->Next
= mGlobals
.SubDirs
;
1225 mGlobals
.SubDirs
= NewList
;
1227 Error (NULL
, 0, 0, Argv
[0], "option requires a subdirectory name");
1229 return STATUS_ERROR
;
1234 } else if (_stricmp (Argv
[0], "-sub") == 0) {
1236 // -sub symname symvalue to do string substitution in the output
1240 // Allocate memory for the symbol object
1242 Symbol
= malloc (sizeof (SYMBOL
));
1243 if (Symbol
== NULL
) {
1244 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1245 return STATUS_ERROR
;
1248 // Allocate memory for the symbol name and value, then save copies
1250 Symbol
->Name
= malloc (strlen (Argv
[1]) + 1);
1251 if (Symbol
->Name
== NULL
) {
1253 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1254 return STATUS_ERROR
;
1257 strcpy (Symbol
->Name
, Argv
[1]);
1258 Symbol
->Value
= malloc (strlen (Argv
[2]) + 1);
1259 if (Symbol
->Value
== NULL
) {
1260 free (Symbol
->Name
);
1262 Error (__FILE__
, __LINE__
, 0, "memory allocation failure", NULL
);
1263 return STATUS_ERROR
;
1266 strcpy (Symbol
->Value
, Argv
[2]);
1268 // Add it to the list
1270 Symbol
->Next
= mGlobals
.SymbolTable
;
1271 mGlobals
.SymbolTable
= Symbol
;
1273 Error (NULL
, 0, 0, Argv
[0], "option requires a symbol name and value");
1275 return STATUS_ERROR
;
1282 } else if (_stricmp (Argv
[0], "-nosystem") == 0) {
1283 mGlobals
.NoSystem
= TRUE
;
1284 } else if (_stricmp (Argv
[0], "-nodupes") == 0) {
1285 mGlobals
.NoDupes
= TRUE
;
1286 } else if (_stricmp (Argv
[0], "-nodups") == 0) {
1287 mGlobals
.NoDupes
= TRUE
;
1288 } else if (_stricmp (Argv
[0], "-target") == 0) {
1290 // -target TargetFileName - Target object file (only one allowed right
1291 // now) is TargetFileName rather than SourceFile.obj
1294 strcpy (mGlobals
.TargetFileName
, Argv
[1]);
1296 Error (NULL
, 0, 0, Argv
[0], "option requires a target file name");
1298 return STATUS_ERROR
;
1303 } else if (_stricmp (Argv
[0], "-usesumdeps") == 0) {
1305 // -usesumdeps Path - if we find an included file xxx.h, and file
1306 // Path/xxx.dep exists, list Path/xxx.dep as a dependency rather than
1307 // xxx.h and don't parse xxx.h. This allows you to create a dependency
1308 // file for a commonly included file, and have its dependency file updated
1309 // only if its included files are updated. Then anyone else including this
1310 // common include file can simply have a dependency on that file's .dep file
1311 // rather than on all the files included by it. Confusing enough?
1313 mGlobals
.UseSumDeps
= 1;
1315 strcpy (mGlobals
.SumDepsPath
, Argv
[1]);
1317 // Add slash on end if not there
1319 if (mGlobals
.SumDepsPath
[strlen (mGlobals
.SumDepsPath
) - 1] != '\\') {
1320 strcat (mGlobals
.SumDepsPath
, "\\");
1323 Error (NULL
, 0, 0, Argv
[0], "option requires path to summary dependency files");
1325 return STATUS_ERROR
;
1331 } else if (_stricmp (Argv
[0], "-o") == 0) {
1333 // -o OutputFileName - specify an output filename for dependency list
1334 // check for one more arg
1337 mGlobals
.OutFileName
= Argv
[1];
1339 // Use temp file for output
1340 // This can avoid overwriting previous existed dep file when error
1341 // ocurred in this tool
1343 sprintf (mGlobals
.TmpFileName
, "%s2", mGlobals
.OutFileName
);
1345 // Try to open the temp file
1347 if ((mGlobals
.OutFptr
= fopen (mGlobals
.TmpFileName
, "w")) == NULL
) {
1348 Error (NULL
, 0, 0, mGlobals
.TmpFileName
, "could not open file for writing");
1349 return STATUS_ERROR
;
1352 Error (NULL
, 0, 0, Argv
[0], "option requires output file name");
1354 return STATUS_ERROR
;
1359 } else if (_stricmp (Argv
[0], "-v") == 0) {
1360 mGlobals
.Verbose
= TRUE
;
1361 } else if (_stricmp (Argv
[0], "-neverfail") == 0) {
1362 mGlobals
.NeverFail
= TRUE
;
1363 } else if (_stricmp (Argv
[0], "-q") == 0) {
1364 mGlobals
.QuietMode
= TRUE
;
1365 } else if (_stricmp (Argv
[0], "-ignorenotfound") == 0) {
1366 mGlobals
.IgnoreNotFound
= TRUE
;
1367 } else if (_stricmp (Argv
[0], "-asm") == 0) {
1368 if (mGlobals
.IsCl
) {
1369 Error (NULL
, 0, 0, Argv
[0], "option conflict with -cl");
1370 return STATUS_ERROR
;
1372 mGlobals
.IsAsm
= TRUE
;
1373 } else if (_stricmp (Argv
[0], "-cl") == 0) {
1374 if (mGlobals
.IsAsm
) {
1375 Error (NULL
, 0, 0, Argv
[0], "option conflict with -asm");
1376 return STATUS_ERROR
;
1378 mGlobals
.IsCl
= TRUE
;
1379 } else if ((_stricmp (Argv
[0], "-h") == 0) || (strcmp (Argv
[0], "-?") == 0)) {
1381 return STATUS_ERROR
;
1383 Error (NULL
, 0, 0, Argv
[0], "unrecognized option");
1385 return STATUS_ERROR
;
1392 // Had to specify at least one source file
1394 if (mGlobals
.SourceFiles
== NULL
) {
1395 Error (NULL
, 0, 0, "must specify one source file name", NULL
);
1397 return STATUS_ERROR
;
1400 // Assume output to stdout if not specified
1402 if (mGlobals
.OutFptr
== NULL
) {
1403 mGlobals
.OutFptr
= stdout
;
1406 return STATUS_SUCCESS
;
1409 // Free the global string lists we allocated memory for
1421 // printf ("Free lists.....");
1423 // Traverse the include paths, freeing each
1424 // printf ("freeing include paths\n");
1426 while (mGlobals
.IncludePaths
!= NULL
) {
1427 Temp
= mGlobals
.IncludePaths
->Next
;
1429 // printf ("Freeing include path string '%s' at 0x%X\n",
1430 // mGlobals.IncludePaths->Str, (int)(mGlobals.IncludePaths->Str));
1432 free (mGlobals
.IncludePaths
->Str
);
1434 // printf ("Freeing include path object at 0x%X\n", (int)(mGlobals.IncludePaths));
1436 free (mGlobals
.IncludePaths
);
1437 mGlobals
.IncludePaths
= Temp
;
1440 // Traverse the source files, freeing each
1442 while (mGlobals
.SourceFiles
!= NULL
) {
1443 Temp
= mGlobals
.SourceFiles
->Next
;
1444 free (mGlobals
.SourceFiles
->Str
);
1445 free (mGlobals
.SourceFiles
);
1446 mGlobals
.SourceFiles
= Temp
;
1449 // Traverse the subdirectory list, freeing each
1451 while (mGlobals
.SubDirs
!= NULL
) {
1452 Temp
= mGlobals
.SubDirs
->Next
;
1453 free (mGlobals
.SubDirs
->Str
);
1454 free (mGlobals
.SubDirs
);
1455 mGlobals
.SubDirs
= Temp
;
1458 // Free the symbol table
1460 while (mGlobals
.SymbolTable
!= NULL
) {
1461 NextSym
= mGlobals
.SymbolTable
->Next
;
1462 free (mGlobals
.SymbolTable
->Name
);
1463 free (mGlobals
.SymbolTable
->Value
);
1464 mGlobals
.SymbolTable
= NextSym
;
1467 // printf ("done\n");
1478 Routine Description:
1480 Print usage information for this utility.
1493 const char *Str
[] = {
1494 UTILITY_NAME
" "UTILITY_VERSION
" - Intel Make Dependencies Utility",
1495 " Copyright (C), 2004 - 2008 Intel Corporation",
1497 #if ( defined(UTILITY_BUILD) && defined(UTILITY_VENDOR) )
1498 " Built from "UTILITY_BUILD
", project of "UTILITY_VENDOR
,
1502 " "UTILITY_NAME
" [OPTION]...",
1504 " -h or -? for this help information",
1505 " -f SourceFile add SourceFile to list of files to scan",
1506 " -i IncludePath add IncludePath to list of search paths",
1507 " -o OutputFile write output dependencies to OutputFile",
1508 " -s SubDir for each IncludePath, also search IncludePath\\SubDir",
1509 " -v for verbose output",
1510 " -ignorenotfound don't warn for files not found",
1511 " -target Target for single SourceFile, target is Target, not SourceFile.obj",
1512 " -q quiet mode to not report files not found if ignored",
1513 " -sub sym str replace all occurrances of 'str' with 'sym' in the output",
1514 " -nosystem not process system <include> files",
1515 " -neverfail always return a success return code",
1517 // " -nodupes keep track of include files, don't rescan duplicates",
1519 " -usesumdeps path use summary dependency files in 'path' directory.",
1520 " -asm The SourceFiles are assembler files",
1521 " -cl The SourceFiles are the output of cl with /showIncludes",
1524 for (Index
= 0; Str
[Index
] != NULL
; Index
++) {
1525 fprintf (stdout
, "%s\n", Str
[Index
]);