Autogen: Message cleanups: Compose messages in std::stringstream

To avoid Race conditions with other processes writing to stdout/stderr compose
the whole message in a std::stringstream then submit the single complete message.
This commit is contained in:
Sebastian Holtermann 2016-04-24 15:00:26 +02:00 committed by Brad King
parent 657a446175
commit 9b58190c8f
3 changed files with 170 additions and 109 deletions

View File

@ -592,8 +592,10 @@ static std::string ListQt5RccInputs(cmSourceFile* sf,
&retVal, 0, cmSystemTools::OUTPUT_NONE); &retVal, 0, cmSystemTools::OUTPUT_NONE);
if (!result || retVal) if (!result || retVal)
{ {
std::cerr << "AUTOGEN: error: Rcc list process for " << sf->GetFullPath() std::stringstream err;
<< " failed:\n" << rccStdOut << "\n" << rccStdErr << std::endl; err << "AUTOGEN: error: Rcc list process for " << sf->GetFullPath()
<< " failed:\n" << rccStdOut << "\n" << rccStdErr << std::endl;
std::cerr << err.str();
return std::string(); return std::string();
} }
@ -623,8 +625,10 @@ static std::string ListQt5RccInputs(cmSourceFile* sf,
std::string::size_type pos = eline.find(searchString); std::string::size_type pos = eline.find(searchString);
if (pos == std::string::npos) if (pos == std::string::npos)
{ {
std::cerr << "AUTOGEN: error: Rcc lists unparsable output " std::stringstream err;
<< eline << std::endl; err << "AUTOGEN: error: Rcc lists unparsable output "
<< eline << std::endl;
std::cerr << err.str();
return std::string(); return std::string();
} }
pos += searchString.length(); pos += searchString.length();

View File

@ -549,7 +549,9 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
const std::string &absFilename = *it; const std::string &absFilename = *it;
if (this->Verbose) if (this->Verbose)
{ {
std::cout << "AUTOGEN: Checking " << absFilename << std::endl; std::stringstream err;
err << "AUTOGEN: Checking " << absFilename << std::endl;
this->LogInfo(err.str());
} }
if (this->RelaxedMode) if (this->RelaxedMode)
{ {
@ -577,7 +579,9 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
const std::string &absFilename = *it; const std::string &absFilename = *it;
if (this->Verbose) if (this->Verbose)
{ {
std::cout << "AUTOGEN: Checking " << absFilename << std::endl; std::stringstream err;
err << "AUTOGEN: Checking " << absFilename << std::endl;
this->LogInfo(err.str());
} }
this->ParseForUic(absFilename, includedUis); this->ParseForUic(absFilename, includedUis);
} }
@ -607,17 +611,20 @@ bool cmQtAutoGenerators::RunAutogen(cmMakefile* makefile)
if (this->RunMocFailed) if (this->RunMocFailed)
{ {
std::cerr << "moc failed..." << std::endl; std::stringstream err; err << "moc failed..." << std::endl;
this->LogError(err.str());
return false; return false;
} }
if (this->RunUicFailed) if (this->RunUicFailed)
{ {
std::cerr << "uic failed..." << std::endl; std::stringstream err; err << "uic failed..." << std::endl;
this->LogError(err.str());
return false; return false;
} }
if (this->RunRccFailed) if (this->RunRccFailed)
{ {
std::cerr << "rcc failed..." << std::endl; std::stringstream err; err << "rcc failed..." << std::endl;
this->LogError(err.str());
return false; return false;
} }
@ -637,8 +644,10 @@ void cmQtAutoGenerators::ParseCppFile(const std::string& absFilename,
const std::string contentsString = ReadAll(absFilename); const std::string contentsString = ReadAll(absFilename);
if (contentsString.empty()) if (contentsString.empty())
{ {
std::cerr << "AUTOGEN: warning: " << absFilename << ": file is empty\n" std::stringstream err;
<< std::endl; err << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
<< std::endl;
this->LogError(err.str());
return; return;
} }
this->ParseForUic(absFilename, contentsString, includedUis); this->ParseForUic(absFilename, contentsString, includedUis);
@ -670,7 +679,6 @@ void cmQtAutoGenerators::ParseCppFile(const std::string& absFilename,
do do
{ {
const std::string currentMoc = mocIncludeRegExp.match(1); const std::string currentMoc = mocIncludeRegExp.match(1);
//std::cout << "found moc include: " << currentMoc << std::endl;
std::string basename = cmsys::SystemTools:: std::string basename = cmsys::SystemTools::
GetFilenameWithoutLastExtension(currentMoc); GetFilenameWithoutLastExtension(currentMoc);
@ -703,20 +711,21 @@ void cmQtAutoGenerators::ParseCppFile(const std::string& absFilename,
} }
else else
{ {
std::cerr << "AUTOGEN: error: " << absFilename << ": The file " std::stringstream err;
<< "includes the moc file \"" << currentMoc << "\", " err << "AUTOGEN: error: " << absFilename << ": The file "
<< "but could not find header \"" << basename << "includes the moc file \"" << currentMoc << "\", "
<< '{' << this->JoinExts(headerExtensions) << "}\" "; << "but could not find header \"" << basename
<< '{' << this->JoinExts(headerExtensions) << "}\" ";
if (mocSubDir.empty()) if (mocSubDir.empty())
{ {
std::cerr << "in " << absPath << "\n" << std::endl; err << "in " << absPath << "\n" << std::endl;
} }
else else
{ {
std::cerr << "neither in " << absPath err << "neither in " << absPath
<< " nor in " << mocSubDir << "\n" << std::endl; << " nor in " << mocSubDir << "\n" << std::endl;
} }
this->LogError(err.str());
::exit(EXIT_FAILURE); ::exit(EXIT_FAILURE);
} }
} }
@ -734,34 +743,40 @@ void cmQtAutoGenerators::ParseCppFile(const std::string& absFilename,
fileToMoc = headerToMoc; fileToMoc = headerToMoc;
if ((requiresMoc==false) &&(basename==scannedFileBasename)) if ((requiresMoc==false) &&(basename==scannedFileBasename))
{ {
std::cerr << "AUTOGEN: warning: " << absFilename << ": The file " std::stringstream err;
"includes the moc file \"" << currentMoc << err << "AUTOGEN: warning: " << absFilename << ": The file "
"\", but does not contain a " << macroName "includes the moc file \"" << currentMoc <<
<< " macro. Running moc on " "\", but does not contain a " << macroName
<< "\"" << headerToMoc << "\" ! Include \"moc_" << " macro. Running moc on "
<< basename << ".cpp\" for a compatibility with " << "\"" << headerToMoc << "\" ! Include \"moc_"
"strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n" << basename << ".cpp\" for a compatibility with "
<< std::endl; "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
<< std::endl;
this->LogError(err.str());
} }
else else
{ {
std::cerr << "AUTOGEN: warning: " << absFilename << ": The file " std::stringstream err;
"includes the moc file \"" << currentMoc << err << "AUTOGEN: warning: " << absFilename << ": The file "
"\" instead of \"moc_" << basename << ".cpp\". " "includes the moc file \"" << currentMoc <<
"Running moc on " "\" instead of \"moc_" << basename << ".cpp\". "
<< "\"" << headerToMoc << "\" ! Include \"moc_" "Running moc on "
<< basename << ".cpp\" for compatibility with " << "\"" << headerToMoc << "\" ! Include \"moc_"
"strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n" << basename << ".cpp\" for compatibility with "
<< std::endl; "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
<< std::endl;
this->LogError(err.str());
} }
} }
else else
{ {
std::cerr <<"AUTOGEN: error: " << absFilename << ": The file " std::stringstream err;
"includes the moc file \"" << currentMoc << err << "AUTOGEN: error: " << absFilename << ": The file "
"\", which seems to be the moc file from a different " "includes the moc file \"" << currentMoc <<
"source file. CMake also could not find a matching " "\", which seems to be the moc file from a different "
"header.\n" << std::endl; "source file. CMake also could not find a matching "
"header.\n" << std::endl;
this->LogError(err.str());
::exit(EXIT_FAILURE); ::exit(EXIT_FAILURE);
} }
} }
@ -785,27 +800,33 @@ void cmQtAutoGenerators::ParseCppFile(const std::string& absFilename,
if (mocUnderscoreIncluded == true) if (mocUnderscoreIncluded == true)
{ {
// this is for KDE4 compatibility: // this is for KDE4 compatibility:
std::cerr << "AUTOGEN: warning: " << absFilename << ": The file " std::stringstream err;
<< "contains a " << macroName << " macro, but does not " err << "AUTOGEN: warning: " << absFilename << ": The file "
"include " << "contains a " << macroName << " macro, but does not "
<< "\"" << scannedFileBasename << ".moc\", but instead " "include "
"includes " << "\"" << scannedFileBasename << ".moc\", but instead "
<< "\"" << ownMocUnderscoreFile << "\". Running moc on " "includes "
<< "\"" << absFilename << "\" ! Better include \"" << "\"" << ownMocUnderscoreFile << "\". Running moc on "
<< scannedFileBasename << ".moc\" for compatibility with " << "\"" << absFilename << "\" ! Better include \""
"strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n" << scannedFileBasename << ".moc\" for compatibility with "
<< std::endl; "strict mode (see CMAKE_AUTOMOC_RELAXED_MODE).\n"
<< std::endl;
this->LogError(err.str());
includedMocs[absFilename] = ownMocUnderscoreFile; includedMocs[absFilename] = ownMocUnderscoreFile;
includedMocs.erase(ownMocHeaderFile); includedMocs.erase(ownMocHeaderFile);
} }
else else
{ {
// otherwise always error out since it will not compile: // otherwise always error out since it will not compile:
std::cerr << "AUTOGEN: error: " << absFilename << ": The file " std::stringstream err;
<< "contains a " << macroName << " macro, but does not " err << "AUTOGEN: error: " << absFilename << ": The file "
"include " << "contains a " << macroName << " macro, but does not "
<< "\"" << scannedFileBasename << ".moc\" !\n" "include "
<< std::endl; << "\"" << scannedFileBasename << ".moc\" !\n"
<< std::endl;
this->LogError(err.str());
::exit(EXIT_FAILURE); ::exit(EXIT_FAILURE);
} }
} }
@ -825,8 +846,10 @@ void cmQtAutoGenerators::StrictParseCppFile(const std::string& absFilename,
const std::string contentsString = ReadAll(absFilename); const std::string contentsString = ReadAll(absFilename);
if (contentsString.empty()) if (contentsString.empty())
{ {
std::cerr << "AUTOGEN: warning: " << absFilename << ": file is empty\n" std::stringstream err;
<< std::endl; err << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
<< std::endl;
this->LogError(err.str());
return; return;
} }
this->ParseForUic(absFilename, contentsString, includedUis); this->ParseForUic(absFilename, contentsString, includedUis);
@ -878,20 +901,21 @@ void cmQtAutoGenerators::StrictParseCppFile(const std::string& absFilename,
} }
else else
{ {
std::cerr << "AUTOGEN: error: " << absFilename << " The file " std::stringstream err;
<< "includes the moc file \"" << currentMoc << "\", " err << "AUTOGEN: error: " << absFilename << " The file "
<< "but could not find header \"" << basename << "includes the moc file \"" << currentMoc << "\", "
<< '{' << this->JoinExts(headerExtensions) << "}\" "; << "but could not find header \"" << basename
<< '{' << this->JoinExts(headerExtensions) << "}\" ";
if (mocSubDir.empty()) if (mocSubDir.empty())
{ {
std::cerr << "in " << absPath << "\n" << std::endl; err << "in " << absPath << "\n" << std::endl;
} }
else else
{ {
std::cerr << "neither in " << absPath err << "neither in " << absPath
<< " nor in " << mocSubDir << "\n" << std::endl; << " nor in " << mocSubDir << "\n" << std::endl;
} }
this->LogError(err.str());
::exit(EXIT_FAILURE); ::exit(EXIT_FAILURE);
} }
} }
@ -899,12 +923,14 @@ void cmQtAutoGenerators::StrictParseCppFile(const std::string& absFilename,
{ {
if (basename != scannedFileBasename) if (basename != scannedFileBasename)
{ {
std::cerr <<"AUTOGEN: error: " << absFilename << ": The file " std::stringstream err;
"includes the moc file \"" << currentMoc << err << "AUTOGEN: error: " << absFilename << ": The file "
"\", which seems to be the moc file from a different " "includes the moc file \"" << currentMoc <<
"source file. This is not supported. " "\", which seems to be the moc file from a different "
"Include \"" << scannedFileBasename << ".moc\" to run " "source file. This is not supported. "
"moc on this source file.\n" << std::endl; "Include \"" << scannedFileBasename << ".moc\" to run "
"moc on this source file.\n" << std::endl;
this->LogError(err.str());
::exit(EXIT_FAILURE); ::exit(EXIT_FAILURE);
} }
dotMocIncluded = true; dotMocIncluded = true;
@ -923,10 +949,12 @@ void cmQtAutoGenerators::StrictParseCppFile(const std::string& absFilename,
macroName))) macroName)))
{ {
// otherwise always error out since it will not compile: // otherwise always error out since it will not compile:
std::cerr << "AUTOGEN: error: " << absFilename << ": The file " std::stringstream err;
<< "contains a " << macroName << " macro, but does not include " err << "AUTOGEN: error: " << absFilename << ": The file "
<< "\"" << scannedFileBasename << ".moc\" !\n" << "contains a " << macroName << " macro, but does not include "
<< std::endl; << "\"" << scannedFileBasename << ".moc\" !\n"
<< std::endl;
this->LogError(err.str());
::exit(EXIT_FAILURE); ::exit(EXIT_FAILURE);
} }
@ -943,8 +971,10 @@ void cmQtAutoGenerators::ParseForUic(const std::string& absFilename,
const std::string contentsString = ReadAll(absFilename); const std::string contentsString = ReadAll(absFilename);
if (contentsString.empty()) if (contentsString.empty())
{ {
std::cerr << "AUTOGEN: warning: " << absFilename << ": file is empty\n" std::stringstream err;
<< std::endl; err << "AUTOGEN: warning: " << absFilename << ": file is empty\n"
<< std::endl;
this->LogError(err.str());
return; return;
} }
this->ParseForUic(absFilename, contentsString, includedUis); this->ParseForUic(absFilename, contentsString, includedUis);
@ -1045,13 +1075,14 @@ void cmQtAutoGenerators::ParseHeaders(const std::set<std::string>& absHeaders,
{ {
if (this->Verbose) if (this->Verbose)
{ {
std::cout << "AUTOGEN: Checking " << headerName << std::endl; std::stringstream err;
err << "AUTOGEN: Checking " << headerName << std::endl;
this->LogInfo(err.str());
} }
std::string macroName; std::string macroName;
if (requiresMocing(contents, macroName)) if (requiresMocing(contents, macroName))
{ {
//std::cout << "header contains Q_OBJECT macro";
const std::string parentDir = this->TargetBuildSubDir const std::string parentDir = this->TargetBuildSubDir
+ this->SourceRelativePath ( headerName ); + this->SourceRelativePath ( headerName );
const std::string basename = cmsys::SystemTools:: const std::string basename = cmsys::SystemTools::
@ -1077,14 +1108,15 @@ bool cmQtAutoGenerators::GenerateMocFiles(
mergedMocs.insert ( notIncludedMocs.begin(), notIncludedMocs.end() ); mergedMocs.insert ( notIncludedMocs.begin(), notIncludedMocs.end() );
if( this->NameCollisionTest ( mergedMocs, collisions ) ) if( this->NameCollisionTest ( mergedMocs, collisions ) )
{ {
std::cerr << std::stringstream err;
err <<
"AUTOGEN: error: " "AUTOGEN: error: "
"The same moc file will be generated " "The same moc file will be generated "
"from different sources." << std::endl << "from different sources." << std::endl <<
"To avoid this error either" << std::endl << "To avoid this error either" << std::endl <<
"- rename the source files or" << std::endl << "- rename the source files or" << std::endl <<
"- do not include the (moc_NAME.cpp|NAME.moc) file" << std::endl; "- do not include the (moc_NAME.cpp|NAME.moc) file" << std::endl;
this->NameCollisionLog ( collisions ); this->NameCollisionLog ( err.str(), collisions );
::exit(EXIT_FAILURE); ::exit(EXIT_FAILURE);
} }
} }
@ -1153,8 +1185,10 @@ bool cmQtAutoGenerators::GenerateMocFiles(
// nothing changed: don't touch the _automoc.cpp file // nothing changed: don't touch the _automoc.cpp file
if (this->Verbose) if (this->Verbose)
{ {
std::cout << "AUTOGEN: " << this->OutMocCppFilenameRel std::stringstream err;
<< " still up to date" << std::endl; err << "AUTOGEN: " << this->OutMocCppFilenameRel
<< " still up to date" << std::endl;
this->LogInfo(err.str());
} }
return true; return true;
} }
@ -1229,8 +1263,10 @@ bool cmQtAutoGenerators::GenerateMoc(const std::string& sourceFile,
&retVal); &retVal);
if (!result || retVal) if (!result || retVal)
{ {
std::cerr << "AUTOGEN: error: process for " << mocFilePath <<" failed:\n" std::stringstream err;
<< output << std::endl; err << "AUTOGEN: error: process for " << mocFilePath <<" failed:\n"
<< output << std::endl;
this->LogError(err.str());
this->RunMocFailed = true; this->RunMocFailed = true;
cmSystemTools::RemoveFile(mocFilePath); cmSystemTools::RemoveFile(mocFilePath);
} }
@ -1272,10 +1308,11 @@ bool cmQtAutoGenerators::GenerateUiFiles(
std::multimap<std::string, std::string> collisions; std::multimap<std::string, std::string> collisions;
if( this->NameCollisionTest ( testMap, collisions ) ) if( this->NameCollisionTest ( testMap, collisions ) )
{ {
std::cerr << "AUTOGEN: error: The same ui_NAME.h file will be generated " std::stringstream err;
"from different sources." << std::endl err << "AUTOGEN: error: The same ui_NAME.h file will be generated "
<< "To avoid this error rename the source files." << std::endl; "from different sources." << std::endl
this->NameCollisionLog ( collisions ); << "To avoid this error rename the source files." << std::endl;
this->NameCollisionLog ( err.str(), collisions );
::exit(EXIT_FAILURE); ::exit(EXIT_FAILURE);
} }
} }
@ -1356,9 +1393,11 @@ bool cmQtAutoGenerators::GenerateUi(const std::string& realName,
&retVal); &retVal);
if (!result || retVal) if (!result || retVal)
{ {
std::cerr << "AUTOUIC: error: process for " << uiOutputFile << std::stringstream err;
" needed by\n \"" << realName << "\"\nfailed:\n" << output err << "AUTOUIC: error: process for " << uiOutputFile <<
<< std::endl; " needed by\n \"" << realName << "\"\nfailed:\n" << output
<< std::endl;
this->LogError(err.str());
this->RunUicFailed = true; this->RunUicFailed = true;
cmSystemTools::RemoveFile(uiOutputFile); cmSystemTools::RemoveFile(uiOutputFile);
return false; return false;
@ -1413,11 +1452,12 @@ bool cmQtAutoGenerators::GenerateQrcFiles()
std::multimap<std::string, std::string> collisions; std::multimap<std::string, std::string> collisions;
if( this->NameCollisionTest ( qrcGenMap, collisions ) ) if( this->NameCollisionTest ( qrcGenMap, collisions ) )
{ {
std::cerr << "AUTOGEN: error: The same qrc_NAME.cpp file" std::stringstream err;
" will be generated from different sources." << std::endl err << "AUTOGEN: error: The same qrc_NAME.cpp file"
<< "To avoid this error rename the source .qrc files." " will be generated from different sources." << std::endl
<< std::endl; << "To avoid this error rename the source .qrc files."
this->NameCollisionLog ( collisions ); << std::endl;
this->NameCollisionLog ( err.str(), collisions );
::exit(EXIT_FAILURE); ::exit(EXIT_FAILURE);
} }
} }
@ -1489,8 +1529,10 @@ bool cmQtAutoGenerators::GenerateQrc (
&retVal); &retVal);
if (!result || retVal) if (!result || retVal)
{ {
std::cerr << "AUTORCC: error: process for " << qrcOutputFile << std::stringstream err;
" failed:\n" << output << std::endl; err << "AUTORCC: error: process for " << qrcOutputFile <<
" failed:\n" << output << std::endl;
this->LogError(err.str());
this->RunRccFailed = true; this->RunRccFailed = true;
cmSystemTools::RemoveFile(qrcBuildFile); cmSystemTools::RemoveFile(qrcBuildFile);
return false; return false;
@ -1582,17 +1624,30 @@ bool cmQtAutoGenerators::NameCollisionTest(
} }
void cmQtAutoGenerators::NameCollisionLog( void cmQtAutoGenerators::NameCollisionLog(
const std::multimap<std::string, std::string>& collisions) const std::string& message,
const std::multimap<std::string, std::string>& collisions)
{ {
typedef std::multimap<std::string, std::string>::const_iterator Iter; typedef std::multimap<std::string, std::string>::const_iterator Iter;
std::stringstream sbuf; std::stringstream err;
// Add message
err << message;
// Append collision list
for(Iter it = collisions.begin(); it != collisions.end(); ++it ) for(Iter it = collisions.begin(); it != collisions.end(); ++it )
{ {
sbuf << it->first << " : " << it->second << std::endl; err << it->first << " : " << it->second << std::endl;
} }
sbuf.flush(); this->LogError(err.str());
std::cerr << sbuf.str(); }
void cmQtAutoGenerators::LogInfo(const std::string& message)
{
std::cout << message;
}
void cmQtAutoGenerators::LogError(const std::string& message)
{
std::cerr << message;
} }
void cmQtAutoGenerators::LogCommand(const std::vector<std::string>& command) void cmQtAutoGenerators::LogCommand(const std::vector<std::string>& command)
@ -1608,11 +1663,10 @@ void cmQtAutoGenerators::LogCommand(const std::vector<std::string>& command)
} }
sbuf << *cmdIt; sbuf << *cmdIt;
} }
sbuf.flush();
if ( !sbuf.str().empty() ) if ( !sbuf.str().empty() )
{ {
std::cout << sbuf.str(); sbuf << std::endl;
std::cout << std::endl; this->LogInfo ( sbuf.str() );
} }
} }

View File

@ -83,8 +83,11 @@ private:
bool NameCollisionTest(const std::map<std::string, std::string >& genFiles, bool NameCollisionTest(const std::map<std::string, std::string >& genFiles,
std::multimap<std::string, std::string>& collisions ); std::multimap<std::string, std::string>& collisions );
void NameCollisionLog( void NameCollisionLog(
const std::multimap<std::string, std::string>& collisions ); const std::string& message,
const std::multimap<std::string, std::string>& collisions );
void LogInfo(const std::string& message);
void LogError(const std::string& message);
void LogCommand(const std::vector<std::string>& command); void LogCommand(const std::vector<std::string>& command);
std::string JoinExts(const std::vector<std::string>& lst); std::string JoinExts(const std::vector<std::string>& lst);