Makefile: Fix output during parallel builds (#12991)

Replace use of separate "cmake -E cmake_progress_report" and "cmake -E
cmake_echo_color" commands to report the progress and message portions
of build output lines with --progress-* options to the latter to print
everything with a single command.  The line buffering of the stdout FILE
stream should cause the whole line to be printed with one atomic write.
This will avoid inter-mixing of line-wise messages from different
processes during a parallel build.
This commit is contained in:
Brad King 2015-02-05 16:48:16 -05:00
parent 69ac6d2755
commit 8521fdf56e
6 changed files with 133 additions and 93 deletions

View File

@ -779,29 +779,24 @@ cmGlobalUnixMakefileGenerator3
localName += "/all"; localName += "/all";
depends.clear(); depends.clear();
std::string progressDir = cmLocalUnixMakefileGenerator3::EchoProgress progress;
lg->GetMakefile()->GetHomeOutputDirectory(); progress.Dir = lg->GetMakefile()->GetHomeOutputDirectory();
progressDir += cmake::GetCMakeFilesDirectory(); progress.Dir += cmake::GetCMakeFilesDirectory();
{ {
std::ostringstream progCmd; std::ostringstream progressArg;
progCmd << "$(CMAKE_COMMAND) -E cmake_progress_report "; const char* sep = "";
// all target counts
progCmd << lg->Convert(progressDir,
cmLocalGenerator::FULL,
cmLocalGenerator::SHELL);
progCmd << " ";
std::vector<unsigned long>& progFiles = std::vector<unsigned long>& progFiles =
this->ProgressMap[gtarget->Target].Marks; this->ProgressMap[gtarget->Target].Marks;
for (std::vector<unsigned long>::iterator i = progFiles.begin(); for (std::vector<unsigned long>::iterator i = progFiles.begin();
i != progFiles.end(); ++i) i != progFiles.end(); ++i)
{ {
progCmd << " " << *i; progressArg << sep << *i;
sep = ",";
} }
commands.push_back(progCmd.str()); progress.Arg = progressArg.str();
} }
progressDir = "Built target "; lg->AppendEcho(commands, "Built target " + name,
progressDir += name; cmLocalUnixMakefileGenerator3::EchoNormal, &progress);
lg->AppendEcho(commands,progressDir.c_str());
this->AppendGlobalTargetDepends(depends,*gtarget->Target); this->AppendGlobalTargetDepends(depends,*gtarget->Target);
lg->WriteMakeRule(ruleFileStream, "All Build rule for target.", lg->WriteMakeRule(ruleFileStream, "All Build rule for target.",
@ -819,15 +814,13 @@ cmGlobalUnixMakefileGenerator3
// Write the rule. // Write the rule.
commands.clear(); commands.clear();
progressDir = lg->GetMakefile()->GetHomeOutputDirectory();
progressDir += cmake::GetCMakeFilesDirectory();
{ {
// TODO: Convert the total progress count to a make variable. // TODO: Convert the total progress count to a make variable.
std::ostringstream progCmd; std::ostringstream progCmd;
progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start ";
// # in target // # in target
progCmd << lg->Convert(progressDir, progCmd << lg->Convert(progress.Dir,
cmLocalGenerator::FULL, cmLocalGenerator::FULL,
cmLocalGenerator::SHELL); cmLocalGenerator::SHELL);
// //
@ -843,7 +836,7 @@ cmGlobalUnixMakefileGenerator3
{ {
std::ostringstream progCmd; std::ostringstream progCmd;
progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0 progCmd << "$(CMAKE_COMMAND) -E cmake_progress_start "; // # 0
progCmd << lg->Convert(progressDir, progCmd << lg->Convert(progress.Dir,
cmLocalGenerator::FULL, cmLocalGenerator::FULL,
cmLocalGenerator::SHELL); cmLocalGenerator::SHELL);
progCmd << " 0"; progCmd << " 0";

View File

@ -1346,8 +1346,9 @@ cmLocalUnixMakefileGenerator3
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void void
cmLocalUnixMakefileGenerator3::AppendEcho(std::vector<std::string>& commands, cmLocalUnixMakefileGenerator3::AppendEcho(std::vector<std::string>& commands,
const char* text, std::string const& text,
EchoColor color) EchoColor color,
EchoProgress const* progress)
{ {
// Choose the color for the text. // Choose the color for the text.
std::string color_name; std::string color_name;
@ -1380,7 +1381,7 @@ cmLocalUnixMakefileGenerator3::AppendEcho(std::vector<std::string>& commands,
// Echo one line at a time. // Echo one line at a time.
std::string line; std::string line;
line.reserve(200); line.reserve(200);
for(const char* c = text;; ++c) for(const char* c = text.c_str();; ++c)
{ {
if(*c == '\n' || *c == '\0') if(*c == '\n' || *c == '\0')
{ {
@ -1389,7 +1390,7 @@ cmLocalUnixMakefileGenerator3::AppendEcho(std::vector<std::string>& commands,
{ {
// Add a command to echo this line. // Add a command to echo this line.
std::string cmd; std::string cmd;
if(color_name.empty()) if(color_name.empty() && !progress)
{ {
// Use the native echo command. // Use the native echo command.
cmd = "@echo "; cmd = "@echo ";
@ -1400,6 +1401,17 @@ cmLocalUnixMakefileGenerator3::AppendEcho(std::vector<std::string>& commands,
// Use cmake to echo the text in color. // Use cmake to echo the text in color.
cmd = "@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) "; cmd = "@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) ";
cmd += color_name; cmd += color_name;
if (progress)
{
cmd += "--progress-dir=";
cmd += this->Convert(progress->Dir,
cmLocalGenerator::FULL,
cmLocalGenerator::SHELL);
cmd += " ";
cmd += "--progress-num=";
cmd += progress->Arg;
cmd += " ";
}
cmd += this->EscapeForShell(line); cmd += this->EscapeForShell(line);
} }
commands.push_back(cmd); commands.push_back(cmd);
@ -1408,6 +1420,9 @@ cmLocalUnixMakefileGenerator3::AppendEcho(std::vector<std::string>& commands,
// Reset the line to emtpy. // Reset the line to emtpy.
line = ""; line = "";
// Progress appears only on first line.
progress = 0;
// Terminate on end-of-string. // Terminate on end-of-string.
if(*c == '\0') if(*c == '\0')
{ {

View File

@ -184,8 +184,9 @@ public:
// append an echo command // append an echo command
enum EchoColor { EchoNormal, EchoDepend, EchoBuild, EchoLink, enum EchoColor { EchoNormal, EchoDepend, EchoBuild, EchoLink,
EchoGenerate, EchoGlobal }; EchoGenerate, EchoGlobal };
void AppendEcho(std::vector<std::string>& commands, const char* text, struct EchoProgress { std::string Dir; std::string Arg; };
EchoColor color = EchoNormal); void AppendEcho(std::vector<std::string>& commands, std::string const& text,
EchoColor color = EchoNormal, EchoProgress const* = 0);
/** Get whether the makefile is to have color. */ /** Get whether the makefile is to have color. */
bool GetColorMakefile() const { return this->ColorMakefile; } bool GetColorMakefile() const { return this->ColorMakefile; }

View File

@ -618,16 +618,19 @@ cmMakefileTargetGenerator
std::vector<std::string> commands; std::vector<std::string> commands;
// add in a progress call if needed // add in a progress call if needed
this->AppendProgress(commands); this->NumberOfProgressActions++;
if(!this->NoRuleMessages) if(!this->NoRuleMessages)
{ {
cmLocalUnixMakefileGenerator3::EchoProgress progress;
this->MakeEchoProgress(progress);
std::string buildEcho = "Building "; std::string buildEcho = "Building ";
buildEcho += lang; buildEcho += lang;
buildEcho += " object "; buildEcho += " object ";
buildEcho += relativeObj; buildEcho += relativeObj;
this->LocalGenerator->AppendEcho this->LocalGenerator->AppendEcho
(commands, buildEcho.c_str(), cmLocalUnixMakefileGenerator3::EchoBuild); (commands, buildEcho.c_str(), cmLocalUnixMakefileGenerator3::EchoBuild,
&progress);
} }
std::string targetOutPathReal; std::string targetOutPathReal;
@ -1200,12 +1203,15 @@ void cmMakefileTargetGenerator
if(!comment.empty()) if(!comment.empty())
{ {
// add in a progress call if needed // add in a progress call if needed
this->AppendProgress(commands); this->NumberOfProgressActions++;
if(!this->NoRuleMessages) if(!this->NoRuleMessages)
{ {
cmLocalUnixMakefileGenerator3::EchoProgress progress;
this->MakeEchoProgress(progress);
this->LocalGenerator this->LocalGenerator
->AppendEcho(commands, comment.c_str(), ->AppendEcho(commands, comment.c_str(),
cmLocalUnixMakefileGenerator3::EchoGenerate); cmLocalUnixMakefileGenerator3::EchoGenerate,
&progress);
} }
} }
@ -1263,22 +1269,14 @@ void cmMakefileTargetGenerator
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void void
cmMakefileTargetGenerator::AppendProgress(std::vector<std::string>& commands) cmMakefileTargetGenerator
::MakeEchoProgress(cmLocalUnixMakefileGenerator3::EchoProgress& progress) const
{ {
this->NumberOfProgressActions++; progress.Dir = this->Makefile->GetHomeOutputDirectory();
if(this->NoRuleMessages) progress.Dir += cmake::GetCMakeFilesDirectory();
{ std::ostringstream progressArg;
return; progressArg << "$(CMAKE_PROGRESS_" << this->NumberOfProgressActions << ")";
} progress.Arg = progressArg.str();
std::string progressDir = this->Makefile->GetHomeOutputDirectory();
progressDir += cmake::GetCMakeFilesDirectory();
std::ostringstream progCmd;
progCmd << "$(CMAKE_COMMAND) -E cmake_progress_report ";
progCmd << this->LocalGenerator->Convert(progressDir,
cmLocalGenerator::FULL,
cmLocalGenerator::SHELL);
progCmd << " $(CMAKE_PROGRESS_" << this->NumberOfProgressActions << ")";
commands.push_back(progCmd.str());
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------

View File

@ -109,7 +109,7 @@ protected:
void GenerateExtraOutput(const char* out, const char* in, void GenerateExtraOutput(const char* out, const char* in,
bool symbolic = false); bool symbolic = false);
void AppendProgress(std::vector<std::string>& commands); void MakeEchoProgress(cmLocalUnixMakefileGenerator3::EchoProgress&) const;
// write out the variable that lists the objects for this target // write out the variable that lists the objects for this target
void WriteObjectsVariable(std::string& variableName, void WriteObjectsVariable(std::string& variableName,

View File

@ -534,48 +534,9 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args)
// Command to report progress for a build // Command to report progress for a build
else if (args[1] == "cmake_progress_report" && args.size() >= 3) else if (args[1] == "cmake_progress_report" && args.size() >= 3)
{ {
std::string dirName = args[2]; // This has been superseded by cmake_echo_color --progress-*
dirName += "/Progress"; // options. We leave it here to avoid errors if somehow this
std::string fName; // is invoked by an existing makefile without regenerating.
FILE *progFile;
// read the count
fName = dirName;
fName += "/count.txt";
progFile = cmsys::SystemTools::Fopen(fName,"r");
int count = 0;
if (!progFile)
{
return 0;
}
else
{
if (1!=fscanf(progFile,"%i",&count))
{
cmSystemTools::Message("Could not read from progress file.");
}
fclose(progFile);
}
unsigned int i;
for (i = 3; i < args.size(); ++i)
{
fName = dirName;
fName += "/";
fName += args[i];
progFile = cmsys::SystemTools::Fopen(fName,"w");
if (progFile)
{
fprintf(progFile,"empty");
fclose(progFile);
}
}
int fileNum = static_cast<int>
(cmsys::Directory::GetNumberOfFilesInDirectory(dirName));
if (count > 0)
{
// print the progress
fprintf(stdout,"[%3i%%] ",((fileNum-3)*100)/count);
}
return 0; return 0;
} }
@ -986,6 +947,65 @@ bool cmcmd::SymlinkInternal(std::string const& file, std::string const& link)
#endif #endif
} }
//----------------------------------------------------------------------------
static void cmcmdProgressReport(std::string const& dir,
std::string const& num)
{
std::string dirName = dir;
dirName += "/Progress";
std::string fName;
FILE *progFile;
// read the count
fName = dirName;
fName += "/count.txt";
progFile = cmsys::SystemTools::Fopen(fName,"r");
int count = 0;
if (!progFile)
{
return;
}
else
{
if (1!=fscanf(progFile,"%i",&count))
{
cmSystemTools::Message("Could not read from progress file.");
}
fclose(progFile);
}
const char* last = num.c_str();
for(const char* c = last;; ++c)
{
if (*c == ',' || *c == '\0')
{
if (c != last)
{
fName = dirName;
fName += "/";
fName.append(last, c-last);
progFile = cmsys::SystemTools::Fopen(fName,"w");
if (progFile)
{
fprintf(progFile,"empty");
fclose(progFile);
}
}
if(*c == '\0')
{
break;
}
last = c + 1;
}
}
int fileNum = static_cast<int>
(cmsys::Directory::GetNumberOfFilesInDirectory(dirName));
if (count > 0)
{
// print the progress
fprintf(stdout,"[%3i%%] ",((fileNum-3)*100)/count);
}
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
int cmcmd::ExecuteEchoColor(std::vector<std::string>& args) int cmcmd::ExecuteEchoColor(std::vector<std::string>& args)
{ {
@ -996,6 +1016,7 @@ int cmcmd::ExecuteEchoColor(std::vector<std::string>& args)
bool enabled = true; bool enabled = true;
int color = cmsysTerminal_Color_Normal; int color = cmsysTerminal_Color_Normal;
bool newline = true; bool newline = true;
std::string progressDir;
for(unsigned int i=2; i < args.size(); ++i) for(unsigned int i=2; i < args.size(); ++i)
{ {
if(args[i].find("--switch=") == 0) if(args[i].find("--switch=") == 0)
@ -1014,6 +1035,18 @@ int cmcmd::ExecuteEchoColor(std::vector<std::string>& args)
} }
} }
} }
else if(cmHasLiteralPrefix(args[i], "--progress-dir="))
{
progressDir = args[i].substr(15);
}
else if(cmHasLiteralPrefix(args[i], "--progress-num="))
{
if (!progressDir.empty())
{
std::string const& progressNum = args[i].substr(15);
cmcmdProgressReport(progressDir, progressNum);
}
}
else if(args[i] == "--normal") else if(args[i] == "--normal")
{ {
color = cmsysTerminal_Color_Normal; color = cmsysTerminal_Color_Normal;