blob: ee0ddbc849a9cc75e111c9adb9c9446708e36095 [file] [log] [blame]
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmQtAutoGen.h"
#include "cmQtAutoGenerator.h"
#include "cmsys/FStream.hxx"
#include "cmsys/Terminal.h"
#include "cmAlgorithms.h"
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
#include "cmSystemTools.h"
#include "cmake.h"
// -- Static functions
static std::string HeadLine(std::string const& title)
{
std::string head = title;
head += '\n';
head.append(head.size() - 1, '-');
head += '\n';
return head;
}
static std::string QuotedCommand(std::vector<std::string> const& command)
{
std::string res;
for (std::string const& item : command) {
if (!res.empty()) {
res.push_back(' ');
}
std::string const cesc = cmQtAutoGen::Quoted(item);
if (item.empty() || (cesc.size() > (item.size() + 2)) ||
(cesc.find(' ') != std::string::npos)) {
res += cesc;
} else {
res += item;
}
}
return res;
}
// -- Class methods
cmQtAutoGenerator::cmQtAutoGenerator()
: Verbose(cmSystemTools::HasEnv("VERBOSE"))
, ColorOutput(true)
{
{
std::string colorEnv;
cmSystemTools::GetEnv("COLOR", colorEnv);
if (!colorEnv.empty()) {
this->ColorOutput = cmSystemTools::IsOn(colorEnv.c_str());
}
}
}
bool cmQtAutoGenerator::Run(std::string const& infoFile,
std::string const& config)
{
// Info settings
this->InfoFile = infoFile;
cmSystemTools::ConvertToUnixSlashes(this->InfoFile);
this->InfoDir = cmSystemTools::GetFilenamePath(infoFile);
this->InfoConfig = config;
cmake cm(cmake::RoleScript);
cm.SetHomeOutputDirectory(this->InfoDir);
cm.SetHomeDirectory(this->InfoDir);
cm.GetCurrentSnapshot().SetDefaultDefinitions();
cmGlobalGenerator gg(&cm);
cmStateSnapshot snapshot = cm.GetCurrentSnapshot();
snapshot.GetDirectory().SetCurrentBinary(this->InfoDir);
snapshot.GetDirectory().SetCurrentSource(this->InfoDir);
auto makefile = cm::make_unique<cmMakefile>(&gg, snapshot);
// The OLD/WARN behavior for policy CMP0053 caused a speed regression.
// https://gitlab.kitware.com/cmake/cmake/issues/17570
makefile->SetPolicyVersion("3.9");
gg.SetCurrentMakefile(makefile.get());
return this->Process(makefile.get());
}
void cmQtAutoGenerator::LogBold(std::string const& message) const
{
cmSystemTools::MakefileColorEcho(cmsysTerminal_Color_ForegroundBlue |
cmsysTerminal_Color_ForegroundBold,
message.c_str(), true, this->ColorOutput);
}
void cmQtAutoGenerator::LogInfo(cmQtAutoGen::Generator genType,
std::string const& message) const
{
std::string msg = cmQtAutoGen::GeneratorName(genType);
msg += ": ";
msg += message;
if (msg.back() != '\n') {
msg.push_back('\n');
}
cmSystemTools::Stdout(msg.c_str(), msg.size());
}
void cmQtAutoGenerator::LogWarning(cmQtAutoGen::Generator genType,
std::string const& message) const
{
std::string msg = cmQtAutoGen::GeneratorName(genType);
msg += " warning:";
if (message.find('\n') == std::string::npos) {
// Single line message
msg.push_back(' ');
} else {
// Multi line message
msg.push_back('\n');
}
// Message
msg += message;
if (msg.back() != '\n') {
msg.push_back('\n');
}
msg.push_back('\n');
cmSystemTools::Stdout(msg.c_str(), msg.size());
}
void cmQtAutoGenerator::LogFileWarning(cmQtAutoGen::Generator genType,
std::string const& filename,
std::string const& message) const
{
std::string msg = " ";
msg += cmQtAutoGen::Quoted(filename);
msg.push_back('\n');
// Message
msg += message;
this->LogWarning(genType, msg);
}
void cmQtAutoGenerator::LogError(cmQtAutoGen::Generator genType,
std::string const& message) const
{
std::string msg;
msg.push_back('\n');
msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " error");
// Message
msg += message;
if (msg.back() != '\n') {
msg.push_back('\n');
}
msg.push_back('\n');
cmSystemTools::Stderr(msg.c_str(), msg.size());
}
void cmQtAutoGenerator::LogFileError(cmQtAutoGen::Generator genType,
std::string const& filename,
std::string const& message) const
{
std::string emsg = " ";
emsg += cmQtAutoGen::Quoted(filename);
emsg += '\n';
// Message
emsg += message;
this->LogError(genType, emsg);
}
void cmQtAutoGenerator::LogCommandError(
cmQtAutoGen::Generator genType, std::string const& message,
std::vector<std::string> const& command, std::string const& output) const
{
std::string msg;
msg.push_back('\n');
msg += HeadLine(cmQtAutoGen::GeneratorName(genType) + " subprocess error");
msg += message;
if (msg.back() != '\n') {
msg.push_back('\n');
}
msg.push_back('\n');
msg += HeadLine("Command");
msg += QuotedCommand(command);
if (msg.back() != '\n') {
msg.push_back('\n');
}
msg.push_back('\n');
msg += HeadLine("Output");
msg += output;
if (msg.back() != '\n') {
msg.push_back('\n');
}
msg.push_back('\n');
cmSystemTools::Stderr(msg.c_str(), msg.size());
}
/**
* @brief Generates the parent directory of the given file on demand
* @return True on success
*/
bool cmQtAutoGenerator::MakeParentDirectory(cmQtAutoGen::Generator genType,
std::string const& filename) const
{
bool success = true;
std::string const dirName = cmSystemTools::GetFilenamePath(filename);
if (!dirName.empty()) {
if (!cmSystemTools::MakeDirectory(dirName)) {
this->LogFileError(genType, filename,
"Could not create parent directory");
success = false;
}
}
return success;
}
/**
* @brief Tests if buildFile is older than sourceFile
* @return True if buildFile is older than sourceFile.
* False may indicate an error.
*/
bool cmQtAutoGenerator::FileIsOlderThan(std::string const& buildFile,
std::string const& sourceFile,
std::string* error)
{
int result = 0;
if (cmSystemTools::FileTimeCompare(buildFile, sourceFile, &result)) {
return (result < 0);
}
if (error != nullptr) {
error->append(
"File modification time comparison failed for the files\n ");
error->append(cmQtAutoGen::Quoted(buildFile));
error->append("\nand\n ");
error->append(cmQtAutoGen::Quoted(sourceFile));
}
return false;
}
bool cmQtAutoGenerator::FileRead(std::string& content,
std::string const& filename,
std::string* error)
{
bool success = false;
if (cmSystemTools::FileExists(filename)) {
std::size_t const length = cmSystemTools::FileLength(filename);
cmsys::ifstream ifs(filename.c_str(), (std::ios::in | std::ios::binary));
if (ifs) {
content.resize(length);
ifs.read(&content.front(), content.size());
if (ifs) {
success = true;
} else {
content.clear();
if (error != nullptr) {
error->append("Reading from the file failed.");
}
}
} else if (error != nullptr) {
error->append("Opening the file for reading failed.");
}
} else if (error != nullptr) {
error->append("The file does not exist.");
}
return success;
}
bool cmQtAutoGenerator::FileWrite(cmQtAutoGen::Generator genType,
std::string const& filename,
std::string const& content)
{
std::string error;
// Make sure the parent directory exists
if (this->MakeParentDirectory(genType, filename)) {
cmsys::ofstream outfile;
outfile.open(filename.c_str(),
(std::ios::out | std::ios::binary | std::ios::trunc));
if (outfile) {
outfile << content;
// Check for write errors
if (!outfile.good()) {
error = "File writing failed";
}
} else {
error = "Opening file for writing failed";
}
}
if (!error.empty()) {
this->LogFileError(genType, filename, error);
return false;
}
return true;
}
bool cmQtAutoGenerator::FileDiffers(std::string const& filename,
std::string const& content)
{
bool differs = true;
{
std::string oldContents;
if (this->FileRead(oldContents, filename)) {
differs = (oldContents != content);
}
}
return differs;
}
/**
* @brief Runs a command and returns true on success
* @return True on success
*/
bool cmQtAutoGenerator::RunCommand(std::vector<std::string> const& command,
std::string& output) const
{
// Log command
if (this->Verbose) {
std::string qcmd = QuotedCommand(command);
qcmd.push_back('\n');
cmSystemTools::Stdout(qcmd.c_str(), qcmd.size());
}
// Execute command
int retVal = 0;
bool res = cmSystemTools::RunSingleCommand(
command, &output, &output, &retVal, nullptr, cmSystemTools::OUTPUT_NONE);
return (res && (retVal == 0));
}