ENH: change the search path order (if several Tcl/Tk are installed, the "current...
[cmake.git] / Source / cmMakeDepend.cxx
blobd2de6f69104eea4b07c97113c7fa94218ede24f7
1 /*=========================================================================
3 Program: Insight Segmentation & Registration Toolkit
4 Module: $RCSfile: cmMakeDepend.cxx,v $
5 Language: C++
6 Date: $Date: 2002-06-27 19:57:09 $
7 Version: $Revision: 1.30 $
9 Copyright (c) 2002 Insight Consortium. All rights reserved.
10 See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm 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 "cmStandardIncludes.h"
19 #include "cmSystemTools.h"
22 void cmDependInformation::AddDependencies(cmDependInformation* info)
24 if(this != info)
26 m_DependencySet.insert(info);
27 for (cmDependInformation::DependencySet::const_iterator
28 d = info->m_DependencySet.begin();
29 d != info->m_DependencySet.end(); ++d)
31 m_DependencySet.insert(*d);
36 cmMakeDepend::cmMakeDepend()
38 m_Verbose = false;
39 m_IncludeFileRegularExpression.compile("^.*$");
40 m_ComplainFileRegularExpression.compile("^$");
44 cmMakeDepend::~cmMakeDepend()
46 for(DependInformationMap::iterator i = m_DependInformationMap.begin();
47 i != m_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(const cmMakefile* makefile)
60 m_Makefile = makefile;
62 // Now extract the include file regular expression from the makefile.
63 m_IncludeFileRegularExpression.compile(
64 m_Makefile->m_IncludeFileRegularExpression.c_str());
65 m_ComplainFileRegularExpression.compile(
66 m_Makefile->m_ComplainFileRegularExpression.c_str());
68 // Now extract any include paths from the makefile flags
69 const std::vector<std::string>& includes =
70 m_Makefile->GetIncludeDirectories();
71 for(std::vector<std::string>::const_iterator j = includes.begin();
72 j != includes.end(); ++j)
74 std::string path = *j;
75 m_Makefile->ExpandVariablesInString(path);
76 this->AddSearchPath(path.c_str());
81 const cmDependInformation* cmMakeDepend::FindDependencies(const char* file)
83 cmDependInformation* info = this->GetDependInformation(file,NULL);
84 this->GenerateDependInformation(info);
85 return info;
88 void cmMakeDepend::GenerateDependInformation(cmDependInformation* info)
90 // If dependencies are already done, stop now.
91 if(info->m_DependDone)
93 return;
95 else
97 // Make sure we don't visit the same file more than once.
98 info->m_DependDone = true;
100 const char* path = info->m_FullPath.c_str();
101 if(!path)
103 cmSystemTools::Error("Attempt to find dependencies for file without path!");
104 return;
107 bool found = false;
109 // If the file exists, use it to find dependency information.
110 if(cmSystemTools::FileExists(path))
112 // Use the real file to find its dependencies.
113 this->DependWalk(info);
114 found = true;
118 // See if the cmSourceFile for it has any files specified as
119 // dependency hints.
120 if(info->m_cmSourceFile != 0)
123 // Get the cmSourceFile corresponding to this.
124 const cmSourceFile& cFile = *(info->m_cmSourceFile);
125 // See if there are any hints for finding dependencies for the missing
126 // file.
127 if(!cFile.GetDepends().empty())
129 // Dependency hints have been given. Use them to begin the
130 // recursion.
131 for(std::vector<std::string>::const_iterator file =
132 cFile.GetDepends().begin(); file != cFile.GetDepends().end();
133 ++file)
135 this->AddDependency(info, file->c_str());
138 // Found dependency information. We are done.
139 found = true;
143 if(!found)
145 // Try to find the file amongst the sources
146 cmSourceFile *srcFile =
147 m_Makefile->GetSource(cmSystemTools::GetFilenameWithoutExtension(path).c_str());
148 if (srcFile)
150 if (srcFile->GetFullPath() == path)
152 found=true;
154 else
156 //try to guess which include path to use
157 for(std::vector<std::string>::iterator t =
158 m_IncludeDirectories.begin();
159 t != m_IncludeDirectories.end(); ++t)
161 std::string incpath = *t;
162 incpath = incpath + "/";
163 incpath = incpath + path;
164 if (srcFile->GetFullPath() == incpath)
166 // set the path to the guessed path
167 info->m_FullPath = incpath;
168 found=true;
175 if(!found)
177 // Couldn't find any dependency information.
178 if(m_ComplainFileRegularExpression.find(info->m_IncludeName.c_str()))
180 cmSystemTools::Error("error cannot find dependencies for ", path);
182 else
184 // Destroy the name of the file so that it won't be output as a
185 // dependency.
186 info->m_FullPath = "";
191 // This function actually reads the file specified and scans it for
192 // #include directives
193 void cmMakeDepend::DependWalk(cmDependInformation* info)
195 cmRegularExpression includeLine("^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)[\">]");
196 std::ifstream fin(info->m_FullPath.c_str());
197 if(!fin)
199 cmSystemTools::Error("Cannot open ", info->m_FullPath.c_str());
200 return;
203 // TODO: Write real read loop (see cmSystemTools::CopyFile).
204 char line[255];
205 for(fin.getline(line, 255); fin; fin.getline(line, 255))
207 if(includeLine.find(line))
209 // extract the file being included
210 std::string includeFile = includeLine.match(1);
211 // see if the include matches the regular expression
212 if(!m_IncludeFileRegularExpression.find(includeFile))
214 if(m_Verbose)
216 std::string message = "Skipping ";
217 message += includeFile;
218 message += " for file ";
219 message += info->m_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,
236 cmSystemTools::GetFilenamePath(
237 cmSystemTools::CollapseFullPath(
238 info->m_FullPath.c_str())).c_str());
239 this->GenerateDependInformation(dependInfo);
240 info->AddDependencies(dependInfo);
243 cmDependInformation* cmMakeDepend::GetDependInformation(const char* file,
244 const char *extraPath)
246 // Get the full path for the file so that lookup is unambiguous.
247 std::string fullPath = this->FullPath(file, extraPath);
249 // Try to find the file's instance of cmDependInformation.
250 DependInformationMap::const_iterator result =
251 m_DependInformationMap.find(fullPath);
252 if(result != m_DependInformationMap.end())
254 // Found an instance, return it.
255 return result->second;
257 else
259 // Didn't find an instance. Create a new one and save it.
260 cmDependInformation* info = new cmDependInformation;
261 info->m_FullPath = fullPath;
262 info->m_IncludeName = file;
263 m_DependInformationMap[fullPath] = info;
264 return info;
269 void cmMakeDepend::GenerateMakefileDependencies()
271 // Now create cmDependInformation objects for files in the directory
272 const cmTargets &tgts = m_Makefile->GetTargets();
273 for(cmTargets::const_iterator l = tgts.begin();
274 l != tgts.end(); l++)
276 const std::vector<cmSourceFile*> &classes = l->second.GetSourceFiles();
277 for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
278 i != classes.end(); ++i)
280 if(!(*i)->GetIsAHeaderFileOnly())
282 cmDependInformation* info =
283 this->GetDependInformation((*i)->GetFullPath().c_str(),NULL);
284 this->AddFileToSearchPath(info->m_FullPath.c_str());
285 info->m_cmSourceFile = *i;
286 this->GenerateDependInformation(info);
293 // find the full path to fname by searching the m_IncludeDirectories array
294 std::string cmMakeDepend::FullPath(const char* fname, const char *extraPath)
296 if(cmSystemTools::FileExists(fname))
298 return std::string(cmSystemTools::CollapseFullPath(fname));
301 for(std::vector<std::string>::iterator i = m_IncludeDirectories.begin();
302 i != m_IncludeDirectories.end(); ++i)
304 std::string path = *i;
305 path = path + "/";
306 path = path + fname;
307 if(cmSystemTools::FileExists(path.c_str()))
309 return cmSystemTools::CollapseFullPath(path.c_str());
313 if (extraPath)
315 std::string path = extraPath;
316 path = path + "/";
317 path = path + fname;
318 if(cmSystemTools::FileExists(path.c_str()))
320 return cmSystemTools::CollapseFullPath(path.c_str());
324 // Couldn't find the file.
325 return std::string(fname);
328 // Add a directory to the search path
329 void cmMakeDepend::AddSearchPath(const char* path)
331 m_IncludeDirectories.push_back(path);
334 // Add a directory to the search path
335 void cmMakeDepend::AddFileToSearchPath(const char* file)
337 std::string filepath = file;
338 std::string::size_type pos = filepath.rfind('/');
339 if(pos != std::string::npos)
341 std::string path = filepath.substr(0, pos);
342 if(std::find(m_IncludeDirectories.begin(),
343 m_IncludeDirectories.end(), path)
344 == m_IncludeDirectories.end())
346 m_IncludeDirectories.push_back(path);
347 return;
352 const cmDependInformation*
353 cmMakeDepend::GetDependInformationForSourceFile(const cmSourceFile &sf) const
355 for(DependInformationMap::const_iterator i = m_DependInformationMap.begin();
356 i != m_DependInformationMap.end(); ++i)
358 const cmDependInformation* info = i->second;
359 if(info->m_cmSourceFile == &sf)
361 return info;
364 return 0;