ENH: During file installation treat the source file as a dependency of the installed file. Install the file only if the destination is older than the source. Set the file times on the installed file to match those of the source file. This should greatly improve the speed of repeated installations because it removes the comparison of file contents. This addresses bug#3349.
This commit is contained in:
parent
b5ca9ba3c8
commit
a2b2742543
|
@ -17,9 +17,11 @@
|
||||||
#include "cmFileCommand.h"
|
#include "cmFileCommand.h"
|
||||||
#include "cmake.h"
|
#include "cmake.h"
|
||||||
#include "cmHexFileConverter.h"
|
#include "cmHexFileConverter.h"
|
||||||
|
#include "cmFileTimeComparison.h"
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#include <cmsys/Directory.hxx>
|
#include <cmsys/Directory.hxx>
|
||||||
#include <cmsys/Glob.hxx>
|
#include <cmsys/Glob.hxx>
|
||||||
#include <cmsys/RegularExpression.hxx>
|
#include <cmsys/RegularExpression.hxx>
|
||||||
|
@ -716,6 +718,7 @@ struct cmFileInstaller
|
||||||
private:
|
private:
|
||||||
cmFileCommand* FileCommand;
|
cmFileCommand* FileCommand;
|
||||||
cmMakefile* Makefile;
|
cmMakefile* Makefile;
|
||||||
|
cmFileTimeComparison FileTimes;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// The length of the destdir setting.
|
// The length of the destdir setting.
|
||||||
|
@ -807,11 +810,6 @@ private:
|
||||||
bool cmFileInstaller::InstallSymlink(const char* fromFile, const char* toFile,
|
bool cmFileInstaller::InstallSymlink(const char* fromFile, const char* toFile,
|
||||||
bool always)
|
bool always)
|
||||||
{
|
{
|
||||||
// Inform the user about this file installation.
|
|
||||||
std::string message = "Installing ";
|
|
||||||
message += toFile;
|
|
||||||
this->Makefile->DisplayStatus(message.c_str(), -1);
|
|
||||||
|
|
||||||
// Read the original symlink.
|
// Read the original symlink.
|
||||||
std::string symlinkTarget;
|
std::string symlinkTarget;
|
||||||
if(!cmSystemTools::ReadSymlink(fromFile, symlinkTarget))
|
if(!cmSystemTools::ReadSymlink(fromFile, symlinkTarget))
|
||||||
|
@ -825,6 +823,7 @@ bool cmFileInstaller::InstallSymlink(const char* fromFile, const char* toFile,
|
||||||
|
|
||||||
// Compare the symlink value to that at the destination if not
|
// Compare the symlink value to that at the destination if not
|
||||||
// always installing.
|
// always installing.
|
||||||
|
bool copy = true;
|
||||||
if(!always)
|
if(!always)
|
||||||
{
|
{
|
||||||
std::string oldSymlinkTarget;
|
std::string oldSymlinkTarget;
|
||||||
|
@ -832,22 +831,30 @@ bool cmFileInstaller::InstallSymlink(const char* fromFile, const char* toFile,
|
||||||
{
|
{
|
||||||
if(symlinkTarget == oldSymlinkTarget)
|
if(symlinkTarget == oldSymlinkTarget)
|
||||||
{
|
{
|
||||||
return true;
|
copy = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the destination file so we can always create the symlink.
|
// Inform the user about this file installation.
|
||||||
cmSystemTools::RemoveFile(toFile);
|
std::string message = (copy? "Installing: " : "Up-to-date: ");
|
||||||
|
message += toFile;
|
||||||
|
this->Makefile->DisplayStatus(message.c_str(), -1);
|
||||||
|
|
||||||
// Create the symlink.
|
if(copy)
|
||||||
if(!cmSystemTools::CreateSymlink(symlinkTarget.c_str(), toFile))
|
|
||||||
{
|
{
|
||||||
cmOStringStream e;
|
// Remove the destination file so we can always create the symlink.
|
||||||
e << "INSTALL cannot duplicate symlink \"" << fromFile
|
cmSystemTools::RemoveFile(toFile);
|
||||||
<< "\" at \"" << toFile << "\".";
|
|
||||||
this->FileCommand->SetError(e.str().c_str());
|
// Create the symlink.
|
||||||
return false;
|
if(!cmSystemTools::CreateSymlink(symlinkTarget.c_str(), toFile))
|
||||||
|
{
|
||||||
|
cmOStringStream e;
|
||||||
|
e << "INSTALL cannot duplicate symlink \"" << fromFile
|
||||||
|
<< "\" at \"" << toFile << "\".";
|
||||||
|
this->FileCommand->SetError(e.str().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the file to the manifest.
|
// Add the file to the manifest.
|
||||||
|
@ -875,13 +882,27 @@ bool cmFileInstaller::InstallFile(const char* fromFile, const char* toFile,
|
||||||
return this->InstallSymlink(fromFile, toFile, always);
|
return this->InstallSymlink(fromFile, toFile, always);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine whether we will copy the file.
|
||||||
|
bool copy = true;
|
||||||
|
if(!always)
|
||||||
|
{
|
||||||
|
// If both files exist and "fromFile" is not newer than "toFile"
|
||||||
|
// do not copy.
|
||||||
|
int timeResult;
|
||||||
|
if(this->FileTimes.FileTimeCompare(fromFile, toFile, &timeResult) &&
|
||||||
|
timeResult <= 0)
|
||||||
|
{
|
||||||
|
copy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Inform the user about this file installation.
|
// Inform the user about this file installation.
|
||||||
std::string message = "Installing ";
|
std::string message = (copy? "Installing: " : "Up-to-date: ");
|
||||||
message += toFile;
|
message += toFile;
|
||||||
this->Makefile->DisplayStatus(message.c_str(), -1);
|
this->Makefile->DisplayStatus(message.c_str(), -1);
|
||||||
|
|
||||||
// Copy the file.
|
// Copy the file.
|
||||||
if(!cmSystemTools::CopyAFile(fromFile, toFile, always))
|
if(copy && !cmSystemTools::CopyAFile(fromFile, toFile, true))
|
||||||
{
|
{
|
||||||
cmOStringStream e;
|
cmOStringStream e;
|
||||||
e << "INSTALL cannot copy file \"" << fromFile
|
e << "INSTALL cannot copy file \"" << fromFile
|
||||||
|
@ -893,6 +914,12 @@ bool cmFileInstaller::InstallFile(const char* fromFile, const char* toFile,
|
||||||
// Add the file to the manifest.
|
// Add the file to the manifest.
|
||||||
this->ManifestAppend(toFile);
|
this->ManifestAppend(toFile);
|
||||||
|
|
||||||
|
// Set the file modification time of the destination file.
|
||||||
|
if(copy && !always)
|
||||||
|
{
|
||||||
|
cmSystemTools::CopyFileTime(fromFile, toFile);
|
||||||
|
}
|
||||||
|
|
||||||
// Set permissions of the destination file.
|
// Set permissions of the destination file.
|
||||||
mode_t permissions = (match_properties.Permissions?
|
mode_t permissions = (match_properties.Permissions?
|
||||||
match_properties.Permissions : this->FilePermissions);
|
match_properties.Permissions : this->FilePermissions);
|
||||||
|
@ -934,7 +961,7 @@ bool cmFileInstaller::InstallDirectory(const char* source,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inform the user about this directory installation.
|
// Inform the user about this directory installation.
|
||||||
std::string message = "Installing ";
|
std::string message = "Installing: ";
|
||||||
message += destination;
|
message += destination;
|
||||||
this->Makefile->DisplayStatus(message.c_str(), -1);
|
this->Makefile->DisplayStatus(message.c_str(), -1);
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32) && (defined(_MSC_VER) || defined(__BORLANDC__))
|
#if defined(_WIN32) && (defined(_MSC_VER) || defined(__BORLANDC__))
|
||||||
|
# define CM_SYSTEM_TOOLS_WINDOWS
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
|
@ -41,6 +42,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <utime.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
@ -66,6 +68,26 @@ extern char** environ;
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CM_SYSTEM_TOOLS_WINDOWS
|
||||||
|
class cmSystemToolsWindowsHandle
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
cmSystemToolsWindowsHandle(HANDLE h): handle_(h) {}
|
||||||
|
~cmSystemToolsWindowsHandle()
|
||||||
|
{
|
||||||
|
if(this->handle_ != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
CloseHandle(this->handle_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
operator bool() const { return this->handle_ != INVALID_HANDLE_VALUE; }
|
||||||
|
operator !() const { return this->handle_ == INVALID_HANDLE_VALUE; }
|
||||||
|
operator HANDLE() const { return this->handle_; }
|
||||||
|
private:
|
||||||
|
HANDLE handle_;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
bool cmSystemTools::s_RunCommandHideConsole = false;
|
bool cmSystemTools::s_RunCommandHideConsole = false;
|
||||||
bool cmSystemTools::s_DisableRunCommandOutput = false;
|
bool cmSystemTools::s_DisableRunCommandOutput = false;
|
||||||
bool cmSystemTools::s_ErrorOccured = false;
|
bool cmSystemTools::s_ErrorOccured = false;
|
||||||
|
@ -2006,3 +2028,45 @@ void cmSystemTools::DoNotInheritStdPipes()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
bool cmSystemTools::CopyFileTime(const char* fromFile, const char* toFile)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) && !defined(__CYGWIN__)
|
||||||
|
cmSystemToolsWindowsHandle hFrom =
|
||||||
|
CreateFile(fromFile, GENERIC_READ, FILE_SHARE_READ, 0,
|
||||||
|
OPEN_EXISTING, 0, 0);
|
||||||
|
cmSystemToolsWindowsHandle hTo =
|
||||||
|
CreateFile(toFile, GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
|
||||||
|
if(!hFrom || !hTo)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
FILETIME timeCreation;
|
||||||
|
FILETIME timeLastAccess;
|
||||||
|
FILETIME timeLastWrite;
|
||||||
|
if(!GetFileTime(hFrom, &timeCreation, &timeLastAccess, &timeLastWrite))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!SetFileTime(hFrom, &timeCreation, &timeLastAccess, &timeLastWrite))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
struct stat fromStat;
|
||||||
|
if(stat(fromFile, &fromStat) < 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct utimbuf buf;
|
||||||
|
buf.actime = fromStat.st_atime;
|
||||||
|
buf.modtime = fromStat.st_mtime;
|
||||||
|
if(utime(toFile, &buf) < 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -345,6 +345,11 @@ public:
|
||||||
// if you want to be able to kill child processes and
|
// if you want to be able to kill child processes and
|
||||||
// not get stuck waiting for all the output on the pipes.
|
// not get stuck waiting for all the output on the pipes.
|
||||||
static void DoNotInheritStdPipes();
|
static void DoNotInheritStdPipes();
|
||||||
|
|
||||||
|
/** Copy the file create/access/modify times from the file named by
|
||||||
|
the first argument to that named by the second. */
|
||||||
|
static bool CopyFileTime(const char* fromFile, const char* toFile);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool s_ForceUnixPaths;
|
static bool s_ForceUnixPaths;
|
||||||
static bool s_RunCommandHideConsole;
|
static bool s_RunCommandHideConsole;
|
||||||
|
|
Loading…
Reference in New Issue