1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmDepends.cxx,v $
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"
26 //----------------------------------------------------------------------------
27 cmDepends::cmDepends(cmLocalGenerator
* lg
, const char* targetDir
):
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();
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
))
79 return this->Finalize(makeDepends
, internalDepends
);
82 //----------------------------------------------------------------------------
83 bool cmDepends::Finalize(std::ostream
&,
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.
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
);
113 // Restore working directory.
116 cmSystemTools::ChangeDirectory(oldcwd
.c_str());
122 //----------------------------------------------------------------------------
123 void cmDepends::Clear(const char *file
)
125 // Print verbose output.
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
);
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.
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
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);
174 // Parse the dependency line.
175 if(!this->ParseDependency(line.c_str()))
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.
191 // Print verbose output.
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.
205 if((!this->FileComparison
->FileTimeCompare(depender
, dependee
,
206 &result
) || result
< 0))
208 // The depender is older than the dependee.
211 // Print verbose output.
215 msg
<< "Dependee \"" << dependee
216 << "\" is newer than depender \""
217 << depender
<< "\"." << std::endl
;
218 cmSystemTools::Stdout(msg
.str().c_str());
224 // Dependencies must be regenerated.
227 // Remove the depender to be sure it is rebuilt.
228 cmSystemTools::RemoveFile(depender
);
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
);