Introduce "generator expressions" to add_test()
[cmake.git] / Source / cmDepends.cxx
blob65d604f88c82c7298714f83467d6f7df72d98cc8
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmDepends.cxx,v $
5 Language: C++
6 Date: $Date: 2008-05-08 14:09:14 $
7 Version: $Revision: 1.18 $
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 "cmDepends.h"
19 #include "cmLocalGenerator.h"
20 #include "cmMakefile.h"
21 #include "cmGeneratedFileStream.h"
22 #include "cmSystemTools.h"
23 #include "cmFileTimeComparison.h"
24 #include <string.h>
26 //----------------------------------------------------------------------------
27 cmDepends::cmDepends(cmLocalGenerator* lg, const char* targetDir):
28 CompileDirectory(),
29 LocalGenerator(lg),
30 Verbose(false),
31 FileComparison(0),
32 TargetDirectory(targetDir),
33 MaxPath(cmSystemTools::GetMaximumFilePathLength()),
34 Dependee(new char[MaxPath]),
35 Depender(new char[MaxPath])
39 //----------------------------------------------------------------------------
40 cmDepends::~cmDepends()
42 delete [] this->Dependee;
43 delete [] this->Depender;
46 //----------------------------------------------------------------------------
47 bool cmDepends::Write(std::ostream &makeDepends,
48 std::ostream &internalDepends)
50 // Lookup the set of sources to scan.
51 std::string srcLang = "CMAKE_DEPENDS_CHECK_";
52 srcLang += this->Language;
53 cmMakefile* mf = this->LocalGenerator->GetMakefile();
54 const char* srcStr = mf->GetSafeDefinition(srcLang.c_str());
55 std::vector<std::string> pairs;
56 cmSystemTools::ExpandListArgument(srcStr, pairs);
58 for(std::vector<std::string>::iterator si = pairs.begin();
59 si != pairs.end();)
61 // Get the source and object file.
62 std::string const& src = *si++;
63 if(si == pairs.end()) { break; }
64 std::string obj = *si++;
66 // Make sure the object file is relative to the top of the build tree.
67 obj = this->LocalGenerator->Convert(obj.c_str(),
68 cmLocalGenerator::HOME_OUTPUT,
69 cmLocalGenerator::MAKEFILE);
71 // Write the dependencies for this pair.
72 if(!this->WriteDependencies(src.c_str(), obj.c_str(),
73 makeDepends, internalDepends))
75 return false;
79 return this->Finalize(makeDepends, internalDepends);
82 //----------------------------------------------------------------------------
83 bool cmDepends::Finalize(std::ostream&,
84 std::ostream&)
86 return true;
89 //----------------------------------------------------------------------------
90 bool cmDepends::Check(const char *makeFile, const char *internalFile)
92 // Dependency checks must be done in proper working directory.
93 std::string oldcwd = ".";
94 if(this->CompileDirectory != ".")
96 // Get the CWD but do not call CollapseFullPath because
97 // we only need it to cd back, and the form does not matter
98 oldcwd = cmSystemTools::GetCurrentWorkingDirectory(false);
99 cmSystemTools::ChangeDirectory(this->CompileDirectory.c_str());
102 // Check whether dependencies must be regenerated.
103 bool okay = true;
104 std::ifstream fin(internalFile);
105 if(!(fin && this->CheckDependencies(fin)))
107 // Clear all dependencies so they will be regenerated.
108 this->Clear(makeFile);
109 cmSystemTools::RemoveFile(internalFile);
110 okay = false;
113 // Restore working directory.
114 if(oldcwd != ".")
116 cmSystemTools::ChangeDirectory(oldcwd.c_str());
119 return okay;
122 //----------------------------------------------------------------------------
123 void cmDepends::Clear(const char *file)
125 // Print verbose output.
126 if(this->Verbose)
128 cmOStringStream msg;
129 msg << "Clearing dependencies in \"" << file << "\"." << std::endl;
130 cmSystemTools::Stdout(msg.str().c_str());
133 // Write an empty dependency file.
134 cmGeneratedFileStream depFileStream(file);
135 depFileStream
136 << "# Empty dependencies file\n"
137 << "# This may be replaced when dependencies are built." << std::endl;
140 //----------------------------------------------------------------------------
141 bool cmDepends::WriteDependencies(const char*, const char*,
142 std::ostream&, std::ostream&)
144 // This should be implemented by the subclass.
145 return false;
148 //----------------------------------------------------------------------------
149 bool cmDepends::CheckDependencies(std::istream& internalDepends)
151 // Parse dependencies from the stream. If any dependee is missing
152 // or newer than the depender then dependencies should be
153 // regenerated.
154 bool okay = true;
155 while(internalDepends.getline(this->Dependee, this->MaxPath))
157 if ( this->Dependee[0] == 0 || this->Dependee[0] == '#' ||
158 this->Dependee[0] == '\r' )
160 continue;
162 size_t len = internalDepends.gcount()-1;
163 if ( this->Dependee[len-1] == '\r' )
165 len --;
166 this->Dependee[len] = 0;
168 if ( this->Dependee[0] != ' ' )
170 memcpy(this->Depender, this->Dependee, len+1);
171 continue;
174 // Parse the dependency line.
175 if(!this->ParseDependency(line.c_str()))
177 continue;
181 // Dependencies must be regenerated if the dependee does not exist
182 // or if the depender exists and is older than the dependee.
183 bool regenerate = false;
184 const char* dependee = this->Dependee+1;
185 const char* depender = this->Depender;
186 if(!cmSystemTools::FileExists(dependee))
188 // The dependee does not exist.
189 regenerate = true;
191 // Print verbose output.
192 if(this->Verbose)
194 cmOStringStream msg;
195 msg << "Dependee \"" << dependee
196 << "\" does not exist for depender \""
197 << depender << "\"." << std::endl;
198 cmSystemTools::Stdout(msg.str().c_str());
201 else if(cmSystemTools::FileExists(depender))
203 // The dependee and depender both exist. Compare file times.
204 int result = 0;
205 if((!this->FileComparison->FileTimeCompare(depender, dependee,
206 &result) || result < 0))
208 // The depender is older than the dependee.
209 regenerate = true;
211 // Print verbose output.
212 if(this->Verbose)
214 cmOStringStream msg;
215 msg << "Dependee \"" << dependee
216 << "\" is newer than depender \""
217 << depender << "\"." << std::endl;
218 cmSystemTools::Stdout(msg.str().c_str());
222 if(regenerate)
224 // Dependencies must be regenerated.
225 okay = false;
227 // Remove the depender to be sure it is rebuilt.
228 cmSystemTools::RemoveFile(depender);
232 return okay;
235 //----------------------------------------------------------------------------
236 void cmDepends::SetIncludePathFromLanguage(const char* lang)
238 std::string includePathVar = "CMAKE_";
239 includePathVar += lang;
240 includePathVar += "_INCLUDE_PATH";
241 cmMakefile* mf = this->LocalGenerator->GetMakefile();
242 if(const char* includePath = mf->GetDefinition(includePathVar.c_str()))
244 cmSystemTools::ExpandListArgument(includePath, this->IncludePath);