CMake/Source/cmDepends.cxx

278 lines
8.9 KiB
C++
Raw Normal View History

Simplify CMake per-source license notices Per-source copyright/license notice headers that spell out copyright holder names and years are hard to maintain and often out-of-date or plain wrong. Precise contributor information is already maintained automatically by the version control tool. Ultimately it is the receiver of a file who is responsible for determining its licensing status, and per-source notices are merely a convenience. Therefore it is simpler and more accurate for each source to have a generic notice of the license name and references to more detailed information on copyright holders and full license terms. Our `Copyright.txt` file now contains a list of Contributors whose names appeared source-level copyright notices. It also references version control history for more precise information. Therefore we no longer need to spell out the list of Contributors in each source file notice. Replace CMake per-source copyright/license notice headers with a short description of the license and links to `Copyright.txt` and online information available from "https://cmake.org/licensing". The online URL also handles cases of modules being copied out of our source into other projects, so we can drop our notices about replacing links with full license text. Run the `Utilities/Scripts/filter-notices.bash` script to perform the majority of the replacements mechanically. Manually fix up shebang lines and trailing newlines in a few files. Manually update the notices in a few files that the script does not handle.
2016-09-27 22:01:08 +03:00
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmDepends.h"
#include "cmFileTimeComparison.h"
#include "cmGeneratedFileStream.h"
#include "cmLocalGenerator.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
#include <cmsys/FStream.hxx>
#include <sstream>
#include <string.h>
#include <utility>
cmDepends::cmDepends(cmLocalGenerator* lg, const char* targetDir)
: CompileDirectory()
, LocalGenerator(lg)
, Verbose(false)
2016-06-27 23:44:16 +03:00
, FileComparison(CM_NULLPTR)
, TargetDirectory(targetDir)
, MaxPath(16384)
, Dependee(new char[MaxPath])
, Depender(new char[MaxPath])
{
}
cmDepends::~cmDepends()
{
delete[] this->Dependee;
delete[] this->Depender;
}
bool cmDepends::Write(std::ostream& makeDepends, std::ostream& internalDepends)
{
// Lookup the set of sources to scan.
std::string srcLang = "CMAKE_DEPENDS_CHECK_";
srcLang += this->Language;
cmMakefile* mf = this->LocalGenerator->GetMakefile();
const char* srcStr = mf->GetSafeDefinition(srcLang);
std::vector<std::string> pairs;
cmSystemTools::ExpandListArgument(srcStr, pairs);
std::map<std::string, std::set<std::string> > dependencies;
for (std::vector<std::string>::iterator si = pairs.begin();
si != pairs.end();) {
// Get the source and object file.
std::string const& src = *si++;
if (si == pairs.end()) {
break;
}
std::string const& obj = *si++;
dependencies[obj].insert(src);
}
for (std::map<std::string, std::set<std::string> >::const_iterator it =
dependencies.begin();
it != dependencies.end(); ++it) {
// Write the dependencies for this pair.
if (!this->WriteDependencies(it->second, it->first, makeDepends,
internalDepends)) {
return false;
}
}
return this->Finalize(makeDepends, internalDepends);
}
bool cmDepends::Finalize(std::ostream& /*unused*/, std::ostream& /*unused*/)
{
return true;
}
bool cmDepends::Check(const char* makeFile, const char* internalFile,
std::map<std::string, DependencyVector>& validDeps)
{
// Dependency checks must be done in proper working directory.
std::string oldcwd = ".";
if (this->CompileDirectory != ".") {
2005-04-12 21:26:35 +04:00
// Get the CWD but do not call CollapseFullPath because
// we only need it to cd back, and the form does not matter
oldcwd = cmSystemTools::GetCurrentWorkingDirectory(false);
cmSystemTools::ChangeDirectory(this->CompileDirectory);
}
// Check whether dependencies must be regenerated.
bool okay = true;
cmsys::ifstream fin(internalFile);
if (!(fin && this->CheckDependencies(fin, internalFile, validDeps))) {
// Clear all dependencies so they will be regenerated.
this->Clear(makeFile);
cmSystemTools::RemoveFile(internalFile);
okay = false;
}
// Restore working directory.
if (oldcwd != ".") {
cmSystemTools::ChangeDirectory(oldcwd);
}
return okay;
}
void cmDepends::Clear(const char* file)
{
// Print verbose output.
if (this->Verbose) {
std::ostringstream msg;
msg << "Clearing dependencies in \"" << file << "\"." << std::endl;
cmSystemTools::Stdout(msg.str().c_str());
}
// Write an empty dependency file.
cmGeneratedFileStream depFileStream(file);
depFileStream << "# Empty dependencies file\n"
<< "# This may be replaced when dependencies are built."
<< std::endl;
}
bool cmDepends::WriteDependencies(const std::set<std::string>& /*unused*/,
const std::string& /*unused*/,
std::ostream& /*unused*/,
std::ostream& /*unused*/)
{
// This should be implemented by the subclass.
return false;
}
bool cmDepends::CheckDependencies(
std::istream& internalDepends, const char* internalDependsFileName,
std::map<std::string, DependencyVector>& validDeps)
{
// Parse dependencies from the stream. If any dependee is missing
// or newer than the depender then dependencies should be
// regenerated.
bool okay = true;
bool dependerExists = false;
2016-06-27 23:44:16 +03:00
DependencyVector* currentDependencies = CM_NULLPTR;
while (internalDepends.getline(this->Dependee, this->MaxPath)) {
if (this->Dependee[0] == 0 || this->Dependee[0] == '#' ||
this->Dependee[0] == '\r') {
continue;
}
size_t len = internalDepends.gcount() - 1;
if (this->Dependee[len - 1] == '\r') {
len--;
2006-03-15 19:02:08 +03:00
this->Dependee[len] = 0;
}
if (this->Dependee[0] != ' ') {
memcpy(this->Depender, this->Dependee, len + 1);
// Calling FileExists() for the depender here saves in many cases 50%
// of the calls to FileExists() further down in the loop. E.g. for
// kdelibs/khtml this reduces the number of calls from 184k down to 92k,
// or the time for cmake -E cmake_depends from 0.3 s down to 0.21 s.
dependerExists = cmSystemTools::FileExists(this->Depender);
// If we erase validDeps[this->Depender] by overwriting it with an empty
// vector, we lose dependencies for dependers that have multiple
// entries. No need to initialize the entry, std::map will do so on first
// access.
currentDependencies = &validDeps[this->Depender];
continue;
}
/*
// Parse the dependency line.
if(!this->ParseDependency(line.c_str()))
{
continue;
}
*/
// Dependencies must be regenerated
// * if the dependee does not exist
// * if the depender exists and is older than the dependee.
// * if the depender does not exist, but the dependee is newer than the
// depends file
bool regenerate = false;
const char* dependee = this->Dependee + 1;
2006-03-15 19:02:08 +03:00
const char* depender = this->Depender;
2016-06-27 23:44:16 +03:00
if (currentDependencies != CM_NULLPTR) {
currentDependencies->push_back(dependee);
}
if (!cmSystemTools::FileExists(dependee)) {
// The dependee does not exist.
regenerate = true;
// Print verbose output.
if (this->Verbose) {
std::ostringstream msg;
msg << "Dependee \"" << dependee << "\" does not exist for depender \""
<< depender << "\"." << std::endl;
cmSystemTools::Stdout(msg.str().c_str());
}
} else {
if (dependerExists) {
// The dependee and depender both exist. Compare file times.
int result = 0;
if ((!this->FileComparison->FileTimeCompare(depender, dependee,
&result) ||
result < 0)) {
// The depender is older than the dependee.
regenerate = true;
// Print verbose output.
if (this->Verbose) {
std::ostringstream msg;
msg << "Dependee \"" << dependee << "\" is newer than depender \""
<< depender << "\"." << std::endl;
cmSystemTools::Stdout(msg.str().c_str());
}
}
} else {
// The dependee exists, but the depender doesn't. Regenerate if the
// internalDepends file is older than the dependee.
int result = 0;
if ((!this->FileComparison->FileTimeCompare(internalDependsFileName,
dependee, &result) ||
result < 0)) {
// The depends-file is older than the dependee.
regenerate = true;
// Print verbose output.
if (this->Verbose) {
std::ostringstream msg;
msg << "Dependee \"" << dependee
<< "\" is newer than depends file \""
<< internalDependsFileName << "\"." << std::endl;
cmSystemTools::Stdout(msg.str().c_str());
}
}
}
}
if (regenerate) {
// Dependencies must be regenerated.
okay = false;
// Remove the information of this depender from the map, it needs
// to be rescanned
2016-06-27 23:44:16 +03:00
if (currentDependencies != CM_NULLPTR) {
validDeps.erase(this->Depender);
2016-06-27 23:44:16 +03:00
currentDependencies = CM_NULLPTR;
}
// Remove the depender to be sure it is rebuilt.
if (dependerExists) {
cmSystemTools::RemoveFile(depender);
dependerExists = false;
}
}
}
return okay;
}
void cmDepends::SetIncludePathFromLanguage(const std::string& lang)
{
// Look for the new per "TARGET_" variant first:
2016-06-27 23:44:16 +03:00
const char* includePath = CM_NULLPTR;
std::string includePathVar = "CMAKE_";
includePathVar += lang;
includePathVar += "_TARGET_INCLUDE_PATH";
cmMakefile* mf = this->LocalGenerator->GetMakefile();
includePath = mf->GetDefinition(includePathVar);
if (includePath) {
cmSystemTools::ExpandListArgument(includePath, this->IncludePath);
} else {
// Fallback to the old directory level variable if no per-target var:
includePathVar = "CMAKE_";
includePathVar += lang;
includePathVar += "_INCLUDE_PATH";
includePath = mf->GetDefinition(includePathVar);
if (includePath) {
cmSystemTools::ExpandListArgument(includePath, this->IncludePath);
}
}
}