1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmDepends.cxx,v $
7 Date: $Date: 2007/12/28 16:49:59 $
8 Version: $Revision: 1.17 $
10 Date: $Date: 2008-05-08 14:09:14 $
11 Version: $Revision: 1.18 $
14 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
15 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
17 This software is distributed WITHOUT ANY WARRANTY; without even
18 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
19 PURPOSE. See the above copyright notices for more information.
21 =========================================================================*/
22 #include "cmDepends.h"
24 #include "cmLocalGenerator.h"
25 #include "cmMakefile.h"
26 #include "cmGeneratedFileStream.h"
27 #include "cmSystemTools.h"
28 #include "cmFileTimeComparison.h"
31 //----------------------------------------------------------------------------
32 cmDepends::cmDepends(cmLocalGenerator
* lg
, const char* targetDir
):
37 TargetDirectory(targetDir
),
38 MaxPath(cmSystemTools::GetMaximumFilePathLength()),
39 Dependee(new char[MaxPath
]),
40 Depender(new char[MaxPath
])
44 //----------------------------------------------------------------------------
45 cmDepends::~cmDepends()
47 delete [] this->Dependee
;
48 delete [] this->Depender
;
51 //----------------------------------------------------------------------------
52 bool cmDepends::Write(std::ostream
&makeDepends
,
53 std::ostream
&internalDepends
)
55 // Lookup the set of sources to scan.
56 std::string srcLang
= "CMAKE_DEPENDS_CHECK_";
57 srcLang
+= this->Language
;
58 cmMakefile
* mf
= this->LocalGenerator
->GetMakefile();
59 const char* srcStr
= mf
->GetSafeDefinition(srcLang
.c_str());
60 std::vector
<std::string
> pairs
;
61 cmSystemTools::ExpandListArgument(srcStr
, pairs
);
63 for(std::vector
<std::string
>::iterator si
= pairs
.begin();
66 // Get the source and object file.
67 std::string
const& src
= *si
++;
68 if(si
== pairs
.end()) { break; }
69 std::string obj
= *si
++;
71 // Make sure the object file is relative to the top of the build tree.
72 obj
= this->LocalGenerator
->Convert(obj
.c_str(),
73 cmLocalGenerator::HOME_OUTPUT
,
74 cmLocalGenerator::MAKEFILE
);
76 // Write the dependencies for this pair.
77 if(!this->WriteDependencies(src
.c_str(), obj
.c_str(),
78 makeDepends
, internalDepends
))
84 return this->Finalize(makeDepends
, internalDepends
);
87 //----------------------------------------------------------------------------
88 bool cmDepends::Finalize(std::ostream
&,
94 //----------------------------------------------------------------------------
95 bool cmDepends::Check(const char *makeFile
, const char *internalFile
)
97 // Dependency checks must be done in proper working directory.
98 std::string oldcwd
= ".";
99 if(this->CompileDirectory
!= ".")
101 // Get the CWD but do not call CollapseFullPath because
102 // we only need it to cd back, and the form does not matter
103 oldcwd
= cmSystemTools::GetCurrentWorkingDirectory(false);
104 cmSystemTools::ChangeDirectory(this->CompileDirectory
.c_str());
107 // Check whether dependencies must be regenerated.
109 std::ifstream
fin(internalFile
);
110 if(!(fin
&& this->CheckDependencies(fin
)))
112 // Clear all dependencies so they will be regenerated.
113 this->Clear(makeFile
);
114 cmSystemTools::RemoveFile(internalFile
);
118 // Restore working directory.
121 cmSystemTools::ChangeDirectory(oldcwd
.c_str());
127 //----------------------------------------------------------------------------
128 void cmDepends::Clear(const char *file
)
130 // Print verbose output.
134 msg
<< "Clearing dependencies in \"" << file
<< "\"." << std::endl
;
135 cmSystemTools::Stdout(msg
.str().c_str());
138 // Write an empty dependency file.
139 cmGeneratedFileStream
depFileStream(file
);
141 << "# Empty dependencies file\n"
142 << "# This may be replaced when dependencies are built." << std::endl
;
145 //----------------------------------------------------------------------------
146 bool cmDepends::WriteDependencies(const char*, const char*,
147 std::ostream
&, std::ostream
&)
149 // This should be implemented by the subclass.
153 //----------------------------------------------------------------------------
154 bool cmDepends::CheckDependencies(std::istream
& internalDepends
)
156 // Parse dependencies from the stream. If any dependee is missing
157 // or newer than the depender then dependencies should be
160 while(internalDepends
.getline(this->Dependee
, this->MaxPath
))
162 if ( this->Dependee
[0] == 0 || this->Dependee
[0] == '#' ||
163 this->Dependee
[0] == '\r' )
167 size_t len
= internalDepends
.gcount()-1;
168 if ( this->Dependee
[len
-1] == '\r' )
171 this->Dependee
[len
] = 0;
173 if ( this->Dependee
[0] != ' ' )
175 memcpy(this->Depender
, this->Dependee
, len
+1);
179 // Parse the dependency line.
180 if(!this->ParseDependency(line.c_str()))
186 // Dependencies must be regenerated if the dependee does not exist
187 // or if the depender exists and is older than the dependee.
188 bool regenerate
= false;
189 const char* dependee
= this->Dependee
+1;
190 const char* depender
= this->Depender
;
191 if(!cmSystemTools::FileExists(dependee
))
193 // The dependee does not exist.
196 // Print verbose output.
200 msg
<< "Dependee \"" << dependee
201 << "\" does not exist for depender \""
202 << depender
<< "\"." << std::endl
;
203 cmSystemTools::Stdout(msg
.str().c_str());
206 else if(cmSystemTools::FileExists(depender
))
208 // The dependee and depender both exist. Compare file times.
210 if((!this->FileComparison
->FileTimeCompare(depender
, dependee
,
211 &result
) || result
< 0))
213 // The depender is older than the dependee.
216 // Print verbose output.
220 msg
<< "Dependee \"" << dependee
221 << "\" is newer than depender \""
222 << depender
<< "\"." << std::endl
;
223 cmSystemTools::Stdout(msg
.str().c_str());
229 // Dependencies must be regenerated.
232 // Remove the depender to be sure it is rebuilt.
233 cmSystemTools::RemoveFile(depender
);
240 //----------------------------------------------------------------------------
241 void cmDepends::SetIncludePathFromLanguage(const char* lang
)
243 std::string includePathVar
= "CMAKE_";
244 includePathVar
+= lang
;
245 includePathVar
+= "_INCLUDE_PATH";
246 cmMakefile
* mf
= this->LocalGenerator
->GetMakefile();
247 if(const char* includePath
= mf
->GetDefinition(includePathVar
.c_str()))
249 cmSystemTools::ExpandListArgument(includePath
, this->IncludePath
);