|
1 # Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 # All rights reserved. |
|
3 # This component and the accompanying materials are made available |
|
4 # under the terms of "Eclipse Public License v1.0" |
|
5 # which accompanies this distribution, and is available |
|
6 # at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 # |
|
8 # Initial Contributors: |
|
9 # Nokia Corporation - initial contribution. |
|
10 # |
|
11 # Contributors: |
|
12 # |
|
13 # Description: |
|
14 # Module which wraps the dependency information provided the preprocessor when invoked with certain switches |
|
15 # so that dependency information rather than preprocessing information is produced. |
|
16 # |
|
17 # |
|
18 |
|
19 package Makdeps; |
|
20 require Exporter; |
|
21 @ISA=qw(Exporter); |
|
22 @EXPORT=qw( |
|
23 Deps_InitL |
|
24 Deps_SetVerbose |
|
25 Deps_SetUserHdrsOnly |
|
26 Deps_SetNoDependencies |
|
27 Deps_SetSysIncPaths |
|
28 Deps_SetUserIncPaths |
|
29 Deps_SetPlatMacros |
|
30 Deps_SetStdIncSysIncPaths |
|
31 Deps_GenDependsL |
|
32 Deps_SetPrefixFile |
|
33 Deps_GetNoDependencies |
|
34 Deps_SetNoDependenciesStatus |
|
35 Deps_GetOSVariantFile |
|
36 Deps_SetOSVariantFile |
|
37 ); |
|
38 |
|
39 use Checkgcc; |
|
40 use Pathutl; |
|
41 use Preprocessor; |
|
42 |
|
43 |
|
44 my $ChopSysDecoyPath; |
|
45 my $EPOCIncPath; |
|
46 my @StdPaths; |
|
47 my %Mode; |
|
48 my @PlatMacros; |
|
49 my $SysDecoyPath; |
|
50 my @SysFlags; |
|
51 my @SysPaths; |
|
52 my @UserFlags; |
|
53 my @UserPaths; |
|
54 my $PrefixFileOption = ""; |
|
55 my $VariantFile=&main::VariantFile(); |
|
56 |
|
57 # special variable used in pattern-matching - special characters nullified |
|
58 my $S_SysDecoyPath; |
|
59 |
|
60 BEGIN { # NB don't initialise essential items to be provided later by calling module, then will cause errors with undef |
|
61 $Mode{'Verbose'}=0; |
|
62 $Mode{'UserHdrsOnly'}=0; |
|
63 $Mode{'NoDependencies'}=0; |
|
64 @PlatMacros=(); |
|
65 # note -MG option assumes missing user headers live in 1st userincpath and missing sys headers in 1st sysdir |
|
66 @SysPaths=(); |
|
67 @UserPaths=(); |
|
68 @StdPaths=(); |
|
69 @SysFlags=(); |
|
70 @UserFlags=(); |
|
71 # Use random number to ensure DecoyPath is unique (ish) |
|
72 srand(); |
|
73 my $randnum=int(rand(100)); |
|
74 if (defined $ENV{PBUILDPID}) { |
|
75 $SysDecoyPath=&Path_WorkPath."TEMPMAK$ENV{PBUILDPID}SYSDECOY$randnum\\"; |
|
76 } else { |
|
77 $SysDecoyPath=&Path_WorkPath."TEMPMAKSYSDECOY$randnum\\"; |
|
78 } |
|
79 $S_SysDecoyPath=quotemeta($SysDecoyPath); |
|
80 $ChopSysDecoyPath=&Path_Chop($SysDecoyPath); |
|
81 } |
|
82 |
|
83 sub Deps_InitL ($@) { # abs Generated Hdr dir, StdIncsysdir (with drive letter if required) |
|
84 # set up a decoy system include path, and set which path will contain generated headers, eg .RSG files, and which |
|
85 # paths are the standard system include paths for the compiler used - eg \MSDEV\INCLUDE |
|
86 ($EPOCIncPath,@StdPaths)=@_; |
|
87 |
|
88 # remove the decoy directory then try to make it again - if it contains files rmdir won't work, so mkdir won't |
|
89 # work and the user will have to sort it out. If it doesn't contain files and has been left lying around |
|
90 # because someone has killed the program half-way through, then rmdir will remove it and mkdir will work OK |
|
91 rmdir $ChopSysDecoyPath if -d $ChopSysDecoyPath; |
|
92 mkdir $ChopSysDecoyPath,2 or die "ERROR: Can't make temp dir \"$ChopSysDecoyPath\"\nIf it already exists, please remove it\n"; |
|
93 } |
|
94 sub Deps_SetVerbose { |
|
95 $Mode{'Verbose'}=1; |
|
96 } |
|
97 |
|
98 sub Deps_SetUserHdrsOnly { |
|
99 # allow calling program to dictate that only listings of user headers, not system headers, be produced |
|
100 $Mode{'UserHdrsOnly'}=1; |
|
101 } |
|
102 |
|
103 sub Deps_SetNoDependencies { |
|
104 # Ensure that we do not create a list of dependencies. |
|
105 $Mode{'NoDependencies'}=1; |
|
106 } |
|
107 |
|
108 sub Deps_GetNoDependencies { |
|
109 # Get the status of NoDependencies. |
|
110 return $Mode{'NoDependencies'}; |
|
111 } |
|
112 |
|
113 sub Deps_SetNoDependenciesStatus($) { |
|
114 # Ensure that we do not create a list of dependencies. |
|
115 $Mode{'NoDependencies'}=shift; |
|
116 } |
|
117 |
|
118 sub Deps_GetOSVariantFile() { |
|
119 # Return the variant .hrh file currently defined |
|
120 return $VariantFile; |
|
121 } |
|
122 |
|
123 sub Deps_SetOSVariantFile($) { |
|
124 # Override the variant .hrh file currently defined |
|
125 $VariantFile=shift; |
|
126 } |
|
127 |
|
128 sub Deps_SetSysIncPaths (@) { # takes list abs paths |
|
129 # set the system include paths where we'll look for system included files, and |
|
130 # for user included files if these are not found in the user include directories |
|
131 return unless @_; |
|
132 @SysPaths=@_; |
|
133 @SysFlags=&Path_Chop(@SysPaths); # newer gcc doesn't like trailing backslash |
|
134 @SysFlags=&Path_PrefixWithDriveAndQuote(@SysFlags); |
|
135 my $Flag; |
|
136 foreach $Flag (@SysFlags) { |
|
137 $Flag=~s/^(.*)$/-I $1/o; |
|
138 } |
|
139 } |
|
140 sub Deps_SetUserIncPaths (@) { # takes list of abs paths |
|
141 # set the user include paths to find user included files in |
|
142 return unless @_; |
|
143 @UserPaths=@_; |
|
144 @UserFlags=&Path_Chop(@UserPaths); # newer gcc doesn't like trailing backslash |
|
145 @UserFlags=&Path_PrefixWithDriveAndQuote(@UserFlags); |
|
146 my $Flag; |
|
147 foreach $Flag (@UserFlags) { |
|
148 $Flag=~s/^(.*)$/-I $1/o; |
|
149 } |
|
150 } |
|
151 sub Deps_SetPlatMacros (@) { |
|
152 # set the macros to be defined by the preprocessor |
|
153 return unless @_; |
|
154 @PlatMacros=@_; |
|
155 my $Flag; |
|
156 foreach $Flag (@PlatMacros) { |
|
157 if($Flag =~ m/\\\"/) { |
|
158 $Flag =~ s/\\\"/\"/g ; |
|
159 } |
|
160 $Flag=~s/^(.*)$/-D$1/o; |
|
161 } |
|
162 } |
|
163 |
|
164 sub Deps_SetPrefixFile($) { |
|
165 my ($file) = @_; |
|
166 $PrefixFileOption = " -include $file "; |
|
167 } |
|
168 |
|
169 sub Deps_GenDependsL ($@) { # takes abs source filepath and list of Build Macros |
|
170 |
|
171 if ( $Mode{'NoDependencies'} ) { |
|
172 # no need build a dependency list. |
|
173 return; |
|
174 } |
|
175 |
|
176 # Set any more macros the preprocessor needs to be defined for the source file |
|
177 # to be preprocessed. |
|
178 # Call preprocessor and produce the dependency listing. |
|
179 |
|
180 my ($Src,@BldMacros)=@_; |
|
181 |
|
182 if (not -e $Src) { |
|
183 warn "WARNING: \"",$Src,"\" not found!\n"; |
|
184 return; |
|
185 } |
|
186 |
|
187 # Always put the source path at the head of the user path list |
|
188 # and take it out at the end of this function |
|
189 unshift @UserPaths, &Path_Split('Path', lc $Src); |
|
190 |
|
191 my $ChopSysDecoyPath=&Path_Chop($SysDecoyPath); # newer gcc doesn't like trailing backslash |
|
192 my $MacroFlag; |
|
193 foreach $MacroFlag (@BldMacros) { |
|
194 $MacroFlag=~s/^(.*)$/-D$1/o; |
|
195 } |
|
196 undef $MacroFlag; |
|
197 |
|
198 my $ChopSrcPath=&Path_Chop(&Path_Split('Path',$Src)); # newer gcc doesn't like trailing backslash |
|
199 my $ProductVariantFlag = ""; |
|
200 if($VariantFile){ |
|
201 $ProductVariantFlag = "-include " . &Path_PrefixWithDriveAndQuote($VariantFile); |
|
202 } |
|
203 my $VariantIncludePath; |
|
204 if (defined &main::PMPrefixFile) |
|
205 { |
|
206 $VariantIncludePath = &main::PMPrefixFile; |
|
207 $VariantIncludePath =~ s/"//g; |
|
208 $VariantIncludePath = Path_Split("path", $VariantIncludePath); |
|
209 |
|
210 $VariantIncludePath = Path_Chop($VariantIncludePath); |
|
211 $VariantIncludePath = Path_PrefixWithDriveAndQuote($VariantIncludePath); |
|
212 } |
|
213 my $CPPCommand; |
|
214 my $exe = &PreprocessorToUseExe(); |
|
215 $CPPCommand = "$exe -undef -M -MG -nostdinc $PrefixFileOption"; |
|
216 $CPPCommand .= " -I $VariantIncludePath" if $VariantIncludePath; |
|
217 $CPPCommand .= " -I ".&Path_PrefixWithDriveAndQuote($ChopSrcPath)." @UserFlags -I- -I ".&Path_PrefixWithDriveAndQuote($ChopSysDecoyPath)." @SysFlags @PlatMacros @BldMacros $ProductVariantFlag ".&Path_PrefixWithDriveAndQuote($Src); |
|
218 |
|
219 if ($Mode{'Verbose'}) { |
|
220 print "$CPPCommand\n" |
|
221 } |
|
222 open CPPPIPE,"$CPPCommand |" or die "ERROR: Can't invoke $exe.EXE\n"; |
|
223 |
|
224 # XYZ.CPP.o: \ |
|
225 # ..\..\..\base\bafl\src\xyz.cpp \ |
|
226 # ..\..\..\EPOC32\INCLUDE\E32DES16.H ..\..\..\EPOC32\INCLUDE\E32STD.INL \ |
|
227 # ..\..\..\EPOC32\INCLUDE\E32BASE.INL \ |
|
228 # ..\..\..\base\bafl\inc\bautil.h \ |
|
229 # ..\..\..\awkward\ name\bafl\inc\bautil.h \ |
|
230 # ..\..\..\lastthing.h |
|
231 |
|
232 my @RTWDepList; |
|
233 while (<CPPPIPE>) { |
|
234 s/ \\$//oi; # remove trailing continuation character |
|
235 s/\\ /;/go; # convert embedded spaces (\<space>) into semicolon which can't occur in filenames |
|
236 # avoid the target of the rule by requiring whitespace in front of each element |
|
237 while (/\s(\S+)/go) { |
|
238 my $dep = $1; |
|
239 $dep =~ s/;/ /go; # spaces were turned into semicolon, so convert back again here |
|
240 $dep =~ s-/-\\-go; # replace forward slashes with backward slashes |
|
241 $dep =~ s/^.\://; |
|
242 $dep =~ s/\s+$//; # remove trailing spaces |
|
243 push @RTWDepList,$dep; |
|
244 } |
|
245 } |
|
246 close CPPPIPE or die "ERROR: $exe.EXE failure\n"; |
|
247 |
|
248 # drop the first dependent, which is the source file itself |
|
249 shift @RTWDepList; |
|
250 |
|
251 # make all paths absolute |
|
252 my @DepList=&Path_AbsToWork(@RTWDepList); |
|
253 undef @RTWDepList; |
|
254 |
|
255 # test the dependencies |
|
256 eval { @DepList=&TestDepends($Src,@DepList); }; |
|
257 die $@ if $@; |
|
258 |
|
259 my @SortedDepList; |
|
260 # get just those headers found in the user include path if user headers only specified |
|
261 if (not $Mode{'UserHdrsOnly'}) { |
|
262 @SortedDepList=sort @DepList; |
|
263 } |
|
264 else { |
|
265 my @UserDepList=(); |
|
266 my $Dep; |
|
267 my $UserPath; |
|
268 DEPLOOP: foreach $Dep (@DepList) { |
|
269 foreach $UserPath (@UserPaths) { |
|
270 if ($UserPath eq &Path_Split('Path',$Dep)) { |
|
271 push @UserDepList, $Dep; |
|
272 next DEPLOOP; |
|
273 } |
|
274 } |
|
275 } |
|
276 @SortedDepList=sort @UserDepList; |
|
277 } |
|
278 |
|
279 # take the source path out of the user path list |
|
280 shift @UserPaths; |
|
281 |
|
282 @SortedDepList; |
|
283 } |
|
284 |
|
285 |
|
286 sub TestDepends (@) { # takes source list of absolute dependencies - called by GenDepends |
|
287 # check that the dependencies exist or are to be generated later, because gcc with the -MG switch |
|
288 # will assume that missing system headers live in the first system include path specified (the decoy |
|
289 # directory in our case), and the missing user headers live in the current working directory |
|
290 |
|
291 my ($Src,@DepList)=@_; |
|
292 |
|
293 my @BadSysList; |
|
294 my @BadUserList; |
|
295 my $Dep; |
|
296 my @GoodList; |
|
297 my $SrcPath=&Path_Split('Path', $Src); |
|
298 |
|
299 my $Path; |
|
300 my $File; |
|
301 DEPLOOP: foreach $Dep (@DepList) { # system dependencies not found |
|
302 $Path=&Path_Split('Path', lc $Dep); |
|
303 if ($Dep=~/^$S_SysDecoyPath(.*)$/o) { # allow things like "#include <sys\stats.h>" |
|
304 # any files listed as existing in the system decoy directory will be missing system include files |
|
305 $File=$1; |
|
306 # change any missing generated header entries so that they are thought to be in $EPOCIncPath, where they will be generated to |
|
307 if ($File=~/\.(RSG|MBG)$/oi) { |
|
308 push @GoodList, "$EPOCIncPath$File"; |
|
309 next DEPLOOP; |
|
310 } |
|
311 # remove missing system include files from the list if they actually exist in standard directories - since the makefiles can't handle |
|
312 # files which may be on a different drive - we don't mind this because if we're using MSVC then we can assume |
|
313 # the MSVC include files will exist |
|
314 my $LR; |
|
315 foreach $LR (@StdPaths) { # tackle MSDEV include dir on diff drive |
|
316 if (-e "$LR$File") { # don't put MSDEV includes in dep list - drive letter would end up in makefile |
|
317 next DEPLOOP; |
|
318 } |
|
319 } |
|
320 # put any other missing system files on the bad list after checking that they really don't exist on the system paths |
|
321 # at this point in time. This check is applied in an attempt to avoid sporadic warnings in the build where system |
|
322 # headers have been listed in the system decoy directory, and hence flagged as missing, when they do seem to have |
|
323 # been present at this time post-build... |
|
324 foreach $Path (@SysPaths) { |
|
325 if (-e "$Path$File") { |
|
326 next DEPLOOP; |
|
327 } |
|
328 } |
|
329 push @BadSysList, $File; |
|
330 next DEPLOOP; |
|
331 } |
|
332 # preprocessor lists any missing user headers as existing in the current directory, |
|
333 # and, if no userinclude paths are specified, |
|
334 # searches to path containing the source file for user headers by default |
|
335 if ($Path eq lc &Path_WorkPath) { # possible missing user headers |
|
336 $File=&Path_Split('File',$Dep); |
|
337 # does the userinclude path contain the current working directory? |
|
338 my $LoopPath; |
|
339 my $WorkPathInUserPaths=0; |
|
340 foreach $LoopPath (@UserPaths) { |
|
341 if ( (lc $LoopPath) eq (lc &Path_WorkPath) ) { |
|
342 $WorkPathInUserPaths=1; |
|
343 next; |
|
344 } |
|
345 } |
|
346 if ($WorkPathInUserPaths) { # the user include path contains the current working directory |
|
347 if (-e $Dep) { |
|
348 push @GoodList,$Dep; # file found in specified userinclude path, OK |
|
349 next DEPLOOP; |
|
350 } |
|
351 } |
|
352 push @BadUserList, $File; # file not found in specified userinclude path, bad |
|
353 next DEPLOOP; |
|
354 } |
|
355 push @GoodList, $Dep; |
|
356 } |
|
357 |
|
358 my $Bad; |
|
359 if (@BadSysList) { |
|
360 warn "\nWARNING: Can't find following headers in System Include Path\n"; |
|
361 foreach $Bad (@BadSysList) { |
|
362 print STDERR " <$Bad>"; |
|
363 } |
|
364 print STDERR "\n(Sys Inc Paths"; |
|
365 foreach $Path (@SysPaths,@StdPaths) { |
|
366 print STDERR " \"$Path\""; |
|
367 } |
|
368 warn |
|
369 ")\nDependency list for \"$Src\" may be incomplete\n", |
|
370 "\n" |
|
371 ; |
|
372 } |
|
373 if (@BadUserList) { |
|
374 warn "\nWARNING: Can't find following headers in User or System Include Paths\n"; |
|
375 my $GenHdr=0; |
|
376 foreach $Bad (@BadUserList) { |
|
377 print STDERR " \"$Bad\""; |
|
378 if ($File=~/\.(RSG|MBG)$/o) { |
|
379 $GenHdr=1; |
|
380 } |
|
381 } |
|
382 print STDERR "\n(User Inc Paths"; |
|
383 foreach $Path (@UserPaths) { |
|
384 print STDERR " \"$Path\""; |
|
385 } |
|
386 warn |
|
387 ")\nDependency list for \"$Src\" may be incomplete\n", |
|
388 "\n" |
|
389 ; |
|
390 if ($GenHdr) { |
|
391 warn |
|
392 "Note that generated headers should be system-included with angle brackets <>\n", |
|
393 "\n" |
|
394 ; |
|
395 } |
|
396 } |
|
397 |
|
398 @GoodList; |
|
399 } |
|
400 |
|
401 |
|
402 END { |
|
403 # remove the dependency decoy directories |
|
404 if (-d "$ChopSysDecoyPath") { |
|
405 rmdir "$ChopSysDecoyPath" or warn "Please remove temp dir \"$ChopSysDecoyPath\"\n"; |
|
406 } |
|
407 } |
|
408 |
|
409 1; |