1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
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"
14 #include "cmLocalGenerator.h"
15 #include "cmMakefile.h"
16 #include "cmGeneratedFileStream.h"
17 #include "cmSystemTools.h"
18 #include "cmFileTimeComparison.h"
21 //----------------------------------------------------------------------------
22 cmDepends::cmDepends(cmLocalGenerator* lg, const char* targetDir):
27 TargetDirectory(targetDir),
29 Dependee(new char[MaxPath]),
30 Depender(new char[MaxPath])
34 //----------------------------------------------------------------------------
35 cmDepends::~cmDepends()
37 delete [] this->Dependee;
38 delete [] this->Depender;
41 //----------------------------------------------------------------------------
42 bool cmDepends::Write(std::ostream &makeDepends,
43 std::ostream &internalDepends)
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);
53 for(std::vector<std::string>::iterator si = pairs.begin();
56 // Get the source and object file.
57 std::string const& src = *si++;
58 if(si == pairs.end()) { break; }
59 std::string obj = *si++;
61 // Make sure the object file is relative to the top of the build tree.
62 obj = this->LocalGenerator->Convert(obj.c_str(),
63 cmLocalGenerator::HOME_OUTPUT,
64 cmLocalGenerator::MAKEFILE);
66 // Write the dependencies for this pair.
67 if(!this->WriteDependencies(src.c_str(), obj.c_str(),
68 makeDepends, internalDepends))
74 return this->Finalize(makeDepends, internalDepends);
77 //----------------------------------------------------------------------------
78 bool cmDepends::Finalize(std::ostream&,
84 //----------------------------------------------------------------------------
85 bool cmDepends::Check(const char *makeFile, const char *internalFile,
86 std::map<std::string, DependencyVector>& validDeps)
88 // Dependency checks must be done in proper working directory.
89 std::string oldcwd = ".";
90 if(this->CompileDirectory != ".")
92 // Get the CWD but do not call CollapseFullPath because
93 // we only need it to cd back, and the form does not matter
94 oldcwd = cmSystemTools::GetCurrentWorkingDirectory(false);
95 cmSystemTools::ChangeDirectory(this->CompileDirectory.c_str());
98 // Check whether dependencies must be regenerated.
100 std::ifstream fin(internalFile);
101 if(!(fin && this->CheckDependencies(fin, validDeps)))
103 // Clear all dependencies so they will be regenerated.
104 this->Clear(makeFile);
105 cmSystemTools::RemoveFile(internalFile);
109 // Restore working directory.
112 cmSystemTools::ChangeDirectory(oldcwd.c_str());
118 //----------------------------------------------------------------------------
119 void cmDepends::Clear(const char *file)
121 // Print verbose output.
125 msg << "Clearing dependencies in \"" << file << "\"." << std::endl;
126 cmSystemTools::Stdout(msg.str().c_str());
129 // Write an empty dependency file.
130 cmGeneratedFileStream depFileStream(file);
132 << "# Empty dependencies file\n"
133 << "# This may be replaced when dependencies are built." << std::endl;
136 //----------------------------------------------------------------------------
137 bool cmDepends::WriteDependencies(const char*, const char*,
138 std::ostream&, std::ostream&)
140 // This should be implemented by the subclass.
144 //----------------------------------------------------------------------------
145 bool cmDepends::CheckDependencies(std::istream& internalDepends,
146 std::map<std::string, DependencyVector>& validDeps)
148 // Parse dependencies from the stream. If any dependee is missing
149 // or newer than the depender then dependencies should be
152 bool dependerExists = false;
153 DependencyVector* currentDependencies = 0;
155 while(internalDepends.getline(this->Dependee, this->MaxPath))
157 if ( this->Dependee[0] == 0 || this->Dependee[0] == '#' ||
158 this->Dependee[0] == '\r' )
162 size_t len = internalDepends.gcount()-1;
163 if ( this->Dependee[len-1] == '\r' )
166 this->Dependee[len] = 0;
168 if ( this->Dependee[0] != ' ' )
170 memcpy(this->Depender, this->Dependee, len+1);
171 // Calling FileExists() for the depender here saves in many cases 50%
172 // of the calls to FileExists() further down in the loop. E.g. for
173 // kdelibs/khtml this reduces the number of calls from 184k down to 92k,
174 // or the time for cmake -E cmake_depends from 0.3 s down to 0.21 s.
175 dependerExists = cmSystemTools::FileExists(this->Depender);
176 DependencyVector tmp;
177 validDeps[this->Depender] = tmp;
178 currentDependencies = &validDeps[this->Depender];
182 // Parse the dependency line.
183 if(!this->ParseDependency(line.c_str()))
189 // Dependencies must be regenerated if the dependee does not exist
190 // or if the depender exists and is older than the dependee.
191 bool regenerate = false;
192 const char* dependee = this->Dependee+1;
193 const char* depender = this->Depender;
194 if (currentDependencies != 0)
196 currentDependencies->push_back(dependee);
199 if(!cmSystemTools::FileExists(dependee))
201 // The dependee does not exist.
204 // Print verbose output.
208 msg << "Dependee \"" << dependee
209 << "\" does not exist for depender \""
210 << depender << "\"." << std::endl;
211 cmSystemTools::Stdout(msg.str().c_str());
214 else if(dependerExists)
216 // The dependee and depender both exist. Compare file times.
218 if((!this->FileComparison->FileTimeCompare(depender, dependee,
219 &result) || result < 0))
221 // The depender is older than the dependee.
224 // Print verbose output.
228 msg << "Dependee \"" << dependee
229 << "\" is newer than depender \""
230 << depender << "\"." << std::endl;
231 cmSystemTools::Stdout(msg.str().c_str());
237 // Dependencies must be regenerated.
240 // Remove the information of this depender from the map, it needs
242 if (currentDependencies != 0)
244 validDeps.erase(this->Depender);
245 currentDependencies = 0;
248 // Remove the depender to be sure it is rebuilt.
251 cmSystemTools::RemoveFile(depender);
252 dependerExists = false;
260 //----------------------------------------------------------------------------
261 void cmDepends::SetIncludePathFromLanguage(const char* lang)
263 // Look for the new per "TARGET_" variant first:
264 const char * includePath = 0;
265 std::string includePathVar = "CMAKE_";
266 includePathVar += lang;
267 includePathVar += "_TARGET_INCLUDE_PATH";
268 cmMakefile* mf = this->LocalGenerator->GetMakefile();
269 includePath = mf->GetDefinition(includePathVar.c_str());
272 cmSystemTools::ExpandListArgument(includePath, this->IncludePath);
276 // Fallback to the old directory level variable if no per-target var:
277 includePathVar = "CMAKE_";
278 includePathVar += lang;
279 includePathVar += "_INCLUDE_PATH";
280 includePath = mf->GetDefinition(includePathVar.c_str());
283 cmSystemTools::ExpandListArgument(includePath, this->IncludePath);