ENH: put the 64 bit paths first
[cmake.git] / Source / cmMakeDepend.cxx
blob418582a350d06b62d3edbdc0d6203275046ce676
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmMakeDepend.cxx,v $
5 Language: C++
6 Date: $Date: 2009-03-16 18:30:19 $
7 Version: $Revision: 1.47 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmMakeDepend.h"
18 #include "cmSystemTools.h"
20 #include <cmsys/RegularExpression.hxx>
22 void cmDependInformation::AddDependencies(cmDependInformation* info)
24 if(this != info)
26 this->DependencySet.insert(info);
30 cmMakeDepend::cmMakeDepend()
32 this->Verbose = false;
33 this->IncludeFileRegularExpression.compile("^.*$");
34 this->ComplainFileRegularExpression.compile("^$");
38 cmMakeDepend::~cmMakeDepend()
40 for(DependInformationMapType::iterator i =
41 this->DependInformationMap.begin();
42 i != this->DependInformationMap.end(); ++i)
44 delete i->second;
49 // Set the makefile that depends will be made from.
50 // The pointer is kept so the cmSourceFile array can
51 // be updated with the depend information in the cmMakefile.
53 void cmMakeDepend::SetMakefile(cmMakefile* makefile)
55 this->Makefile = makefile;
57 // Now extract the include file regular expression from the makefile.
58 this->IncludeFileRegularExpression.compile(
59 this->Makefile->IncludeFileRegularExpression.c_str());
60 this->ComplainFileRegularExpression.compile(
61 this->Makefile->ComplainFileRegularExpression.c_str());
63 // Now extract any include paths from the makefile flags
64 const std::vector<std::string>& includes =
65 this->Makefile->GetIncludeDirectories();
66 for(std::vector<std::string>::const_iterator j = includes.begin();
67 j != includes.end(); ++j)
69 std::string path = *j;
70 this->Makefile->ExpandVariablesInString(path);
71 this->AddSearchPath(path.c_str());
76 const cmDependInformation* cmMakeDepend::FindDependencies(const char* file)
78 cmDependInformation* info = this->GetDependInformation(file,0);
79 this->GenerateDependInformation(info);
80 return info;
83 void cmMakeDepend::GenerateDependInformation(cmDependInformation* info)
85 // If dependencies are already done, stop now.
86 if(info->DependDone)
88 return;
90 else
92 // Make sure we don't visit the same file more than once.
93 info->DependDone = true;
95 const char* path = info->FullPath.c_str();
96 if(!path)
98 cmSystemTools::Error(
99 "Attempt to find dependencies for file without path!");
100 return;
103 bool found = false;
105 // If the file exists, use it to find dependency information.
106 if(cmSystemTools::FileExists(path, true))
108 // Use the real file to find its dependencies.
109 this->DependWalk(info);
110 found = true;
114 // See if the cmSourceFile for it has any files specified as
115 // dependency hints.
116 if(info->SourceFile != 0)
119 // Get the cmSourceFile corresponding to this.
120 const cmSourceFile& cFile = *(info->SourceFile);
121 // See if there are any hints for finding dependencies for the missing
122 // file.
123 if(!cFile.GetDepends().empty())
125 // Dependency hints have been given. Use them to begin the
126 // recursion.
127 for(std::vector<std::string>::const_iterator file =
128 cFile.GetDepends().begin(); file != cFile.GetDepends().end();
129 ++file)
131 this->AddDependency(info, file->c_str());
134 // Found dependency information. We are done.
135 found = true;
139 if(!found)
141 // Try to find the file amongst the sources
142 cmSourceFile *srcFile = this->Makefile->GetSource
143 (cmSystemTools::GetFilenameWithoutExtension(path).c_str());
144 if (srcFile)
146 if (srcFile->GetFullPath() == path)
148 found=true;
150 else
152 //try to guess which include path to use
153 for(std::vector<std::string>::iterator t =
154 this->IncludeDirectories.begin();
155 t != this->IncludeDirectories.end(); ++t)
157 std::string incpath = *t;
158 if (incpath.size() && incpath[incpath.size() - 1] != '/')
160 incpath = incpath + "/";
162 incpath = incpath + path;
163 if (srcFile->GetFullPath() == incpath)
165 // set the path to the guessed path
166 info->FullPath = incpath;
167 found=true;
174 if(!found)
176 // Couldn't find any dependency information.
177 if(this->ComplainFileRegularExpression.find(info->IncludeName.c_str()))
179 cmSystemTools::Error("error cannot find dependencies for ", path);
181 else
183 // Destroy the name of the file so that it won't be output as a
184 // dependency.
185 info->FullPath = "";
190 // This function actually reads the file specified and scans it for
191 // #include directives
192 void cmMakeDepend::DependWalk(cmDependInformation* info)
194 cmsys::RegularExpression includeLine
195 ("^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)[\">]");
196 std::ifstream fin(info->FullPath.c_str());
197 if(!fin)
199 cmSystemTools::Error("Cannot open ", info->FullPath.c_str());
200 return;
203 // TODO: Write real read loop (see cmSystemTools::CopyFile).
204 std::string line;
205 while( cmSystemTools::GetLineFromStream(fin, line) )
207 if(includeLine.find(line.c_str()))
209 // extract the file being included
210 std::string includeFile = includeLine.match(1);
211 // see if the include matches the regular expression
212 if(!this->IncludeFileRegularExpression.find(includeFile))
214 if(this->Verbose)
216 std::string message = "Skipping ";
217 message += includeFile;
218 message += " for file ";
219 message += info->FullPath.c_str();
220 cmSystemTools::Error(message.c_str(), 0);
222 continue;
225 // Add this file and all its dependencies.
226 this->AddDependency(info, includeFile.c_str());
232 void cmMakeDepend::AddDependency(cmDependInformation* info, const char* file)
234 cmDependInformation* dependInfo =
235 this->GetDependInformation(file, info->PathOnly.c_str());
236 this->GenerateDependInformation(dependInfo);
237 info->AddDependencies(dependInfo);
240 cmDependInformation* cmMakeDepend::GetDependInformation(const char* file,
241 const char *extraPath)
243 // Get the full path for the file so that lookup is unambiguous.
244 std::string fullPath = this->FullPath(file, extraPath);
246 // Try to find the file's instance of cmDependInformation.
247 DependInformationMapType::const_iterator result =
248 this->DependInformationMap.find(fullPath);
249 if(result != this->DependInformationMap.end())
251 // Found an instance, return it.
252 return result->second;
254 else
256 // Didn't find an instance. Create a new one and save it.
257 cmDependInformation* info = new cmDependInformation;
258 info->FullPath = fullPath;
259 info->PathOnly = cmSystemTools::GetFilenamePath(fullPath.c_str());
260 info->IncludeName = file;
261 this->DependInformationMap[fullPath] = info;
262 return info;
267 // find the full path to fname by searching the this->IncludeDirectories array
268 std::string cmMakeDepend::FullPath(const char* fname, const char *extraPath)
270 DirectoryToFileToPathMapType::iterator m;
271 if(extraPath)
273 m = this->DirectoryToFileToPathMap.find(extraPath);
275 else
277 m = this->DirectoryToFileToPathMap.find("");
280 if(m != this->DirectoryToFileToPathMap.end())
282 FileToPathMapType& map = m->second;
283 FileToPathMapType::iterator p = map.find(fname);
284 if(p != map.end())
286 return p->second;
290 if(cmSystemTools::FileExists(fname, true))
292 std::string fp = cmSystemTools::CollapseFullPath(fname);
293 this->DirectoryToFileToPathMap[extraPath? extraPath: ""][fname] = fp;
294 return fp;
297 for(std::vector<std::string>::iterator i = this->IncludeDirectories.begin();
298 i != this->IncludeDirectories.end(); ++i)
300 std::string path = *i;
301 if (path.size() && path[path.size() - 1] != '/')
303 path = path + "/";
305 path = path + fname;
306 if(cmSystemTools::FileExists(path.c_str(), true)
307 && !cmSystemTools::FileIsDirectory(path.c_str()))
309 std::string fp = cmSystemTools::CollapseFullPath(path.c_str());
310 this->DirectoryToFileToPathMap[extraPath? extraPath: ""][fname] = fp;
311 return fp;
315 if (extraPath)
317 std::string path = extraPath;
318 if (path.size() && path[path.size() - 1] != '/')
320 path = path + "/";
322 path = path + fname;
323 if(cmSystemTools::FileExists(path.c_str(), true)
324 && !cmSystemTools::FileIsDirectory(path.c_str()))
326 std::string fp = cmSystemTools::CollapseFullPath(path.c_str());
327 this->DirectoryToFileToPathMap[extraPath][fname] = fp;
328 return fp;
332 // Couldn't find the file.
333 return std::string(fname);
336 // Add a directory to the search path
337 void cmMakeDepend::AddSearchPath(const char* path)
339 this->IncludeDirectories.push_back(path);