Imported Upstream version 2.8.11.2
[platform/upstream/cmake.git] / Source / cmDepends.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12 #include "cmDepends.h"
13
14 #include "cmLocalGenerator.h"
15 #include "cmMakefile.h"
16 #include "cmGeneratedFileStream.h"
17 #include "cmSystemTools.h"
18 #include "cmFileTimeComparison.h"
19 #include <string.h>
20
21 //----------------------------------------------------------------------------
22 cmDepends::cmDepends(cmLocalGenerator* lg, const char* targetDir):
23   CompileDirectory(),
24   LocalGenerator(lg),
25   Verbose(false),
26   FileComparison(0),
27   TargetDirectory(targetDir),
28   MaxPath(16384),
29   Dependee(new char[MaxPath]),
30   Depender(new char[MaxPath])
31 {
32 }
33
34 //----------------------------------------------------------------------------
35 cmDepends::~cmDepends()
36 {
37   delete [] this->Dependee;
38   delete [] this->Depender;
39 }
40
41 //----------------------------------------------------------------------------
42 bool cmDepends::Write(std::ostream &makeDepends,
43                       std::ostream &internalDepends)
44 {
45   // Lookup the set of sources to scan.
46   std::string srcLang = "CMAKE_DEPENDS_CHECK_";
47   srcLang += this->Language;
48   cmMakefile* mf = this->LocalGenerator->GetMakefile();
49   const char* srcStr = mf->GetSafeDefinition(srcLang.c_str());
50   std::vector<std::string> pairs;
51   cmSystemTools::ExpandListArgument(srcStr, pairs);
52
53   std::map<std::string, std::set<std::string> > dependencies;
54   for(std::vector<std::string>::iterator si = pairs.begin();
55       si != pairs.end();)
56     {
57     // Get the source and object file.
58     std::string const& src = *si++;
59     if(si == pairs.end()) { break; }
60     std::string obj = *si++;
61
62     // Make sure the object file is relative to the top of the build tree.
63     obj = this->LocalGenerator->Convert(obj.c_str(),
64                                         cmLocalGenerator::HOME_OUTPUT,
65                                         cmLocalGenerator::MAKEFILE);
66     dependencies[obj].insert(src);
67     }
68   for(std::map<std::string, std::set<std::string> >::const_iterator
69       it = dependencies.begin(); it != dependencies.end(); ++it)
70     {
71
72     // Write the dependencies for this pair.
73     if(!this->WriteDependencies(it->second, it->first,
74                                 makeDepends, internalDepends))
75       {
76       return false;
77       }
78     }
79
80   return this->Finalize(makeDepends, internalDepends);
81 }
82
83 //----------------------------------------------------------------------------
84 bool cmDepends::Finalize(std::ostream&,
85                          std::ostream&)
86 {
87   return true;
88 }
89
90 //----------------------------------------------------------------------------
91 bool cmDepends::Check(const char *makeFile, const char *internalFile,
92                       std::map<std::string, DependencyVector>& validDeps)
93 {
94   // Dependency checks must be done in proper working directory.
95   std::string oldcwd = ".";
96   if(this->CompileDirectory != ".")
97     {
98     // Get the CWD but do not call CollapseFullPath because
99     // we only need it to cd back, and the form does not matter
100     oldcwd = cmSystemTools::GetCurrentWorkingDirectory(false);
101     cmSystemTools::ChangeDirectory(this->CompileDirectory.c_str());
102     }
103
104   // Check whether dependencies must be regenerated.
105   bool okay = true;
106   std::ifstream fin(internalFile);
107   if(!(fin && this->CheckDependencies(fin, internalFile, validDeps)))
108     {
109     // Clear all dependencies so they will be regenerated.
110     this->Clear(makeFile);
111     cmSystemTools::RemoveFile(internalFile);
112     okay = false;
113     }
114
115   // Restore working directory.
116   if(oldcwd != ".")
117     {
118     cmSystemTools::ChangeDirectory(oldcwd.c_str());
119     }
120
121   return okay;
122 }
123
124 //----------------------------------------------------------------------------
125 void cmDepends::Clear(const char *file)
126 {
127   // Print verbose output.
128   if(this->Verbose)
129     {
130     cmOStringStream msg;
131     msg << "Clearing dependencies in \"" << file << "\"." << std::endl;
132     cmSystemTools::Stdout(msg.str().c_str());
133     }
134
135   // Write an empty dependency file.
136   cmGeneratedFileStream depFileStream(file);
137   depFileStream
138     << "# Empty dependencies file\n"
139     << "# This may be replaced when dependencies are built." << std::endl;
140 }
141
142 //----------------------------------------------------------------------------
143 bool cmDepends::WriteDependencies(
144     const std::set<std::string>&, const std::string&,
145     std::ostream&, std::ostream&)
146 {
147   // This should be implemented by the subclass.
148   return false;
149 }
150
151 //----------------------------------------------------------------------------
152 bool cmDepends::CheckDependencies(std::istream& internalDepends,
153                                   const char* internalDependsFileName,
154                             std::map<std::string, DependencyVector>& validDeps)
155 {
156   // Parse dependencies from the stream.  If any dependee is missing
157   // or newer than the depender then dependencies should be
158   // regenerated.
159   bool okay = true;
160   bool dependerExists = false;
161   DependencyVector* currentDependencies = 0;
162
163   while(internalDepends.getline(this->Dependee, this->MaxPath))
164     {
165     if ( this->Dependee[0] == 0 || this->Dependee[0] == '#' ||
166          this->Dependee[0] == '\r' )
167       {
168       continue;
169       }
170     size_t len = internalDepends.gcount()-1;
171     if ( this->Dependee[len-1] == '\r' )
172       {
173       len --;
174       this->Dependee[len] = 0;
175       }
176     if ( this->Dependee[0] != ' ' )
177       {
178       memcpy(this->Depender, this->Dependee, len+1);
179       // Calling FileExists() for the depender here saves in many cases 50%
180       // of the calls to FileExists() further down in the loop. E.g. for
181       // kdelibs/khtml this reduces the number of calls from 184k down to 92k,
182       // or the time for cmake -E cmake_depends from 0.3 s down to 0.21 s.
183       dependerExists = cmSystemTools::FileExists(this->Depender);
184       // If we erase validDeps[this->Depender] by overwriting it with an empty
185       // vector, we lose dependencies for dependers that have multiple
186       // entries. No need to initialize the entry, std::map will do so on first
187       // access.
188       currentDependencies = &validDeps[this->Depender];
189       continue;
190       }
191     /*
192     // Parse the dependency line.
193     if(!this->ParseDependency(line.c_str()))
194       {
195       continue;
196       }
197       */
198
199     // Dependencies must be regenerated
200     // * if the dependee does not exist
201     // * if the depender exists and is older than the dependee.
202     // * if the depender does not exist, but the dependee is newer than the
203     //   depends file
204     bool regenerate = false;
205     const char* dependee = this->Dependee+1;
206     const char* depender = this->Depender;
207     if (currentDependencies != 0)
208       {
209       currentDependencies->push_back(dependee);
210       }
211
212     if(!cmSystemTools::FileExists(dependee))
213       {
214       // The dependee does not exist.
215       regenerate = true;
216
217       // Print verbose output.
218       if(this->Verbose)
219         {
220         cmOStringStream msg;
221         msg << "Dependee \"" << dependee
222             << "\" does not exist for depender \""
223             << depender << "\"." << std::endl;
224         cmSystemTools::Stdout(msg.str().c_str());
225         }
226       }
227     else
228       {
229       if(dependerExists)
230         {
231         // The dependee and depender both exist.  Compare file times.
232         int result = 0;
233         if((!this->FileComparison->FileTimeCompare(depender, dependee,
234                                               &result) || result < 0))
235           {
236           // The depender is older than the dependee.
237           regenerate = true;
238
239           // Print verbose output.
240           if(this->Verbose)
241             {
242             cmOStringStream msg;
243             msg << "Dependee \"" << dependee
244                 << "\" is newer than depender \""
245                 << depender << "\"." << std::endl;
246             cmSystemTools::Stdout(msg.str().c_str());
247             }
248           }
249         }
250       else
251         {
252         // The dependee exists, but the depender doesn't. Regenerate if the
253         // internalDepends file is older than the dependee.
254         int result = 0;
255         if((!this->FileComparison->FileTimeCompare(internalDependsFileName,
256                                              dependee, &result) || result < 0))
257           {
258           // The depends-file is older than the dependee.
259           regenerate = true;
260
261           // Print verbose output.
262           if(this->Verbose)
263             {
264             cmOStringStream msg;
265             msg << "Dependee \"" << dependee
266                 << "\" is newer than depends file \""
267                 << internalDependsFileName << "\"." << std::endl;
268             cmSystemTools::Stdout(msg.str().c_str());
269             }
270           }
271         }
272       }
273     if(regenerate)
274       {
275       // Dependencies must be regenerated.
276       okay = false;
277
278       // Remove the information of this depender from the map, it needs
279       // to be rescanned
280       if (currentDependencies != 0)
281         {
282         validDeps.erase(this->Depender);
283         currentDependencies = 0;
284         }
285
286       // Remove the depender to be sure it is rebuilt.
287       if (dependerExists)
288         {
289         cmSystemTools::RemoveFile(depender);
290         dependerExists = false;
291         }
292       }
293     }
294
295   return okay;
296 }
297
298 //----------------------------------------------------------------------------
299 void cmDepends::SetIncludePathFromLanguage(const char* lang)
300 {
301   // Look for the new per "TARGET_" variant first:
302   const char * includePath = 0;
303   std::string includePathVar = "CMAKE_";
304   includePathVar += lang;
305   includePathVar += "_TARGET_INCLUDE_PATH";
306   cmMakefile* mf = this->LocalGenerator->GetMakefile();
307   includePath = mf->GetDefinition(includePathVar.c_str());
308   if(includePath)
309     {
310     cmSystemTools::ExpandListArgument(includePath, this->IncludePath);
311     }
312   else
313     {
314     // Fallback to the old directory level variable if no per-target var:
315     includePathVar = "CMAKE_";
316     includePathVar += lang;
317     includePathVar += "_INCLUDE_PATH";
318     includePath = mf->GetDefinition(includePathVar.c_str());
319     if(includePath)
320       {
321       cmSystemTools::ExpandListArgument(includePath, this->IncludePath);
322       }
323     }
324 }