1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmMakeDepend.cxx,v $
6 <<<<<<< cmMakeDepend.cxx
7 Date: $Date: 2007/12/15 01:31:27 $
8 Version: $Revision: 1.46 $
10 Date: $Date: 2009-03-16 18:30:19 $
11 Version: $Revision: 1.47 $
14 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
15 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
17 This software is distributed WITHOUT ANY WARRANTY; without even
18 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
19 PURPOSE. See the above copyright notices for more information.
21 =========================================================================*/
22 #include "cmMakeDepend.h"
23 #include "cmSystemTools.h"
25 #include <cmsys/RegularExpression.hxx>
27 void cmDependInformation::AddDependencies(cmDependInformation
* info
)
31 this->DependencySet
.insert(info
);
35 cmMakeDepend::cmMakeDepend()
37 this->Verbose
= false;
38 this->IncludeFileRegularExpression
.compile("^.*$");
39 this->ComplainFileRegularExpression
.compile("^$");
43 cmMakeDepend::~cmMakeDepend()
45 for(DependInformationMapType::iterator i
=
46 this->DependInformationMap
.begin();
47 i
!= this->DependInformationMap
.end(); ++i
)
54 // Set the makefile that depends will be made from.
55 // The pointer is kept so the cmSourceFile array can
56 // be updated with the depend information in the cmMakefile.
58 void cmMakeDepend::SetMakefile(cmMakefile
* makefile
)
60 this->Makefile
= makefile
;
62 // Now extract the include file regular expression from the makefile.
63 this->IncludeFileRegularExpression
.compile(
64 this->Makefile
->IncludeFileRegularExpression
.c_str());
65 this->ComplainFileRegularExpression
.compile(
66 this->Makefile
->ComplainFileRegularExpression
.c_str());
68 // Now extract any include paths from the makefile flags
69 const std::vector
<std::string
>& includes
=
70 this->Makefile
->GetIncludeDirectories();
71 for(std::vector
<std::string
>::const_iterator j
= includes
.begin();
72 j
!= includes
.end(); ++j
)
74 std::string path
= *j
;
75 this->Makefile
->ExpandVariablesInString(path
);
76 this->AddSearchPath(path
.c_str());
81 const cmDependInformation
* cmMakeDepend::FindDependencies(const char* file
)
83 cmDependInformation
* info
= this->GetDependInformation(file
,0);
84 this->GenerateDependInformation(info
);
88 void cmMakeDepend::GenerateDependInformation(cmDependInformation
* info
)
90 // If dependencies are already done, stop now.
97 // Make sure we don't visit the same file more than once.
98 info
->DependDone
= true;
100 const char* path
= info
->FullPath
.c_str();
103 cmSystemTools::Error(
104 "Attempt to find dependencies for file without path!");
110 // If the file exists, use it to find dependency information.
111 if(cmSystemTools::FileExists(path
, true))
113 // Use the real file to find its dependencies.
114 this->DependWalk(info
);
119 // See if the cmSourceFile for it has any files specified as
121 if(info
->SourceFile
!= 0)
124 // Get the cmSourceFile corresponding to this.
125 const cmSourceFile
& cFile
= *(info
->SourceFile
);
126 // See if there are any hints for finding dependencies for the missing
128 if(!cFile
.GetDepends().empty())
130 // Dependency hints have been given. Use them to begin the
132 for(std::vector
<std::string
>::const_iterator file
=
133 cFile
.GetDepends().begin(); file
!= cFile
.GetDepends().end();
136 this->AddDependency(info
, file
->c_str());
139 // Found dependency information. We are done.
146 // Try to find the file amongst the sources
147 cmSourceFile
*srcFile
= this->Makefile
->GetSource
148 (cmSystemTools::GetFilenameWithoutExtension(path
).c_str());
151 if (srcFile
->GetFullPath() == path
)
157 //try to guess which include path to use
158 for(std::vector
<std::string
>::iterator t
=
159 this->IncludeDirectories
.begin();
160 t
!= this->IncludeDirectories
.end(); ++t
)
162 std::string incpath
= *t
;
163 if (incpath
.size() && incpath
[incpath
.size() - 1] != '/')
165 incpath
= incpath
+ "/";
167 incpath
= incpath
+ path
;
168 if (srcFile
->GetFullPath() == incpath
)
170 // set the path to the guessed path
171 info
->FullPath
= incpath
;
181 // Couldn't find any dependency information.
182 if(this->ComplainFileRegularExpression
.find(info
->IncludeName
.c_str()))
184 cmSystemTools::Error("error cannot find dependencies for ", path
);
188 // Destroy the name of the file so that it won't be output as a
195 // This function actually reads the file specified and scans it for
196 // #include directives
197 void cmMakeDepend::DependWalk(cmDependInformation
* info
)
199 cmsys::RegularExpression includeLine
200 ("^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)[\">]");
201 std::ifstream
fin(info
->FullPath
.c_str());
204 cmSystemTools::Error("Cannot open ", info
->FullPath
.c_str());
208 // TODO: Write real read loop (see cmSystemTools::CopyFile).
210 while( cmSystemTools::GetLineFromStream(fin
, line
) )
212 if(includeLine
.find(line
.c_str()))
214 // extract the file being included
215 std::string includeFile
= includeLine
.match(1);
216 // see if the include matches the regular expression
217 if(!this->IncludeFileRegularExpression
.find(includeFile
))
221 std::string message
= "Skipping ";
222 message
+= includeFile
;
223 message
+= " for file ";
224 message
+= info
->FullPath
.c_str();
225 cmSystemTools::Error(message
.c_str(), 0);
230 // Add this file and all its dependencies.
231 this->AddDependency(info
, includeFile
.c_str());
237 void cmMakeDepend::AddDependency(cmDependInformation
* info
, const char* file
)
239 cmDependInformation
* dependInfo
=
240 this->GetDependInformation(file
, info
->PathOnly
.c_str());
241 this->GenerateDependInformation(dependInfo
);
242 info
->AddDependencies(dependInfo
);
245 cmDependInformation
* cmMakeDepend::GetDependInformation(const char* file
,
246 const char *extraPath
)
248 // Get the full path for the file so that lookup is unambiguous.
249 std::string fullPath
= this->FullPath(file
, extraPath
);
251 // Try to find the file's instance of cmDependInformation.
252 DependInformationMapType::const_iterator result
=
253 this->DependInformationMap
.find(fullPath
);
254 if(result
!= this->DependInformationMap
.end())
256 // Found an instance, return it.
257 return result
->second
;
261 // Didn't find an instance. Create a new one and save it.
262 cmDependInformation
* info
= new cmDependInformation
;
263 info
->FullPath
= fullPath
;
264 info
->PathOnly
= cmSystemTools::GetFilenamePath(fullPath
.c_str());
265 info
->IncludeName
= file
;
266 this->DependInformationMap
[fullPath
] = info
;
272 // find the full path to fname by searching the this->IncludeDirectories array
273 std::string
cmMakeDepend::FullPath(const char* fname
, const char *extraPath
)
275 DirectoryToFileToPathMapType::iterator m
;
278 m
= this->DirectoryToFileToPathMap
.find(extraPath
);
282 m
= this->DirectoryToFileToPathMap
.find("");
285 if(m
!= this->DirectoryToFileToPathMap
.end())
287 FileToPathMapType
& map
= m
->second
;
288 FileToPathMapType::iterator p
= map
.find(fname
);
295 if(cmSystemTools::FileExists(fname
, true))
297 std::string fp
= cmSystemTools::CollapseFullPath(fname
);
298 this->DirectoryToFileToPathMap
[extraPath
? extraPath
: ""][fname
] = fp
;
302 for(std::vector
<std::string
>::iterator i
= this->IncludeDirectories
.begin();
303 i
!= this->IncludeDirectories
.end(); ++i
)
305 std::string path
= *i
;
306 if (path
.size() && path
[path
.size() - 1] != '/')
311 if(cmSystemTools::FileExists(path
.c_str(), true)
312 && !cmSystemTools::FileIsDirectory(path
.c_str()))
314 std::string fp
= cmSystemTools::CollapseFullPath(path
.c_str());
315 this->DirectoryToFileToPathMap
[extraPath
? extraPath
: ""][fname
] = fp
;
322 std::string path
= extraPath
;
323 if (path
.size() && path
[path
.size() - 1] != '/')
328 if(cmSystemTools::FileExists(path
.c_str(), true)
329 && !cmSystemTools::FileIsDirectory(path
.c_str()))
331 std::string fp
= cmSystemTools::CollapseFullPath(path
.c_str());
332 this->DirectoryToFileToPathMap
[extraPath
][fname
] = fp
;
337 // Couldn't find the file.
338 return std::string(fname
);
341 // Add a directory to the search path
342 void cmMakeDepend::AddSearchPath(const char* path
)
344 this->IncludeDirectories
.push_back(path
);