Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / cmMakeDepend.cxx
blobebeaf4a416496d881e3e9dc66b74032b2fd65953
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmMakeDepend.cxx,v $
5 Language: C++
6 <<<<<<< cmMakeDepend.cxx
7 Date: $Date: 2007/12/15 01:31:27 $
8 Version: $Revision: 1.46 $
9 =======
10 Date: $Date: 2009-03-16 18:30:19 $
11 Version: $Revision: 1.47 $
12 >>>>>>> 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)
29 if(this != 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)
49 delete i->second;
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);
85 return info;
88 void cmMakeDepend::GenerateDependInformation(cmDependInformation* info)
90 // If dependencies are already done, stop now.
91 if(info->DependDone)
93 return;
95 else
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();
101 if(!path)
103 cmSystemTools::Error(
104 "Attempt to find dependencies for file without path!");
105 return;
108 bool found = false;
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);
115 found = true;
119 // See if the cmSourceFile for it has any files specified as
120 // dependency hints.
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
127 // file.
128 if(!cFile.GetDepends().empty())
130 // Dependency hints have been given. Use them to begin the
131 // recursion.
132 for(std::vector<std::string>::const_iterator file =
133 cFile.GetDepends().begin(); file != cFile.GetDepends().end();
134 ++file)
136 this->AddDependency(info, file->c_str());
139 // Found dependency information. We are done.
140 found = true;
144 if(!found)
146 // Try to find the file amongst the sources
147 cmSourceFile *srcFile = this->Makefile->GetSource
148 (cmSystemTools::GetFilenameWithoutExtension(path).c_str());
149 if (srcFile)
151 if (srcFile->GetFullPath() == path)
153 found=true;
155 else
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;
172 found=true;
179 if(!found)
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);
186 else
188 // Destroy the name of the file so that it won't be output as a
189 // dependency.
190 info->FullPath = "";
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());
202 if(!fin)
204 cmSystemTools::Error("Cannot open ", info->FullPath.c_str());
205 return;
208 // TODO: Write real read loop (see cmSystemTools::CopyFile).
209 std::string line;
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))
219 if(this->Verbose)
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);
227 continue;
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;
259 else
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;
267 return 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;
276 if(extraPath)
278 m = this->DirectoryToFileToPathMap.find(extraPath);
280 else
282 m = this->DirectoryToFileToPathMap.find("");
285 if(m != this->DirectoryToFileToPathMap.end())
287 FileToPathMapType& map = m->second;
288 FileToPathMapType::iterator p = map.find(fname);
289 if(p != map.end())
291 return p->second;
295 if(cmSystemTools::FileExists(fname, true))
297 std::string fp = cmSystemTools::CollapseFullPath(fname);
298 this->DirectoryToFileToPathMap[extraPath? extraPath: ""][fname] = fp;
299 return 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] != '/')
308 path = path + "/";
310 path = path + fname;
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;
316 return fp;
320 if (extraPath)
322 std::string path = extraPath;
323 if (path.size() && path[path.size() - 1] != '/')
325 path = path + "/";
327 path = path + fname;
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;
333 return 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);