Makefile: Fix multiple custom command outputs with one missing

The use of "cmake -E touch_nocreate" added in commit v3.2.1~4^2
(Makefile: Fix multiple custom command outputs regression, 2015-03-06)
caused builds to fail when one of the outputs is intentionally not
created.  This was fixed by our parent commit by making touch_nocreate
succeed when the file is missing.  Add a test case covering it.

For the Watcom WMake generator, check for the SYMBOLIC source file
property separately on each output.  The mark is needed on outputs that
are not really created to tell 'wmake' not to complain that it is
missing.  The mark is also needed on outputs that are created or 'wmake'
will not consider them out of date when they exist.

Inspired-by: Ben Boeckel <ben.boeckel@kitware.com>
This commit is contained in:
Brad King 2015-04-10 13:03:34 -04:00
parent 5c08e2559c
commit 9660a3ccea
4 changed files with 118 additions and 26 deletions

View File

@ -767,7 +767,7 @@ cmMakefileTargetGenerator
// Write the rule.
this->WriteMakeRule(*this->BuildFileStream, 0, outputs,
depends, commands, false);
depends, commands);
bool do_preprocess_rules = lang_has_preprocessor &&
this->LocalGenerator->GetCreatePreprocessedSourceRules();
@ -989,18 +989,30 @@ void cmMakefileTargetGenerator::WriteTargetCleanRules()
}
//----------------------------------------------------------------------------
void cmMakefileTargetGenerator::WriteMakeRule(
bool cmMakefileTargetGenerator::WriteMakeRule(
std::ostream& os,
const char* comment,
const std::vector<std::string>& outputs,
const std::vector<std::string>& depends,
const std::vector<std::string>& commands,
bool symbolic,
bool in_help)
{
bool symbolic = false;
if (outputs.size() == 0)
{
return;
return symbolic;
}
// Check whether we need to bother checking for a symbolic output.
bool need_symbolic = this->GlobalGenerator->GetNeedSymbolicMark();
// Check whether the first output is marked as symbolic.
if(need_symbolic)
{
if(cmSourceFile* sf = this->Makefile->GetSource(outputs[0]))
{
symbolic = sf->GetPropertyAsBool("SYMBOLIC");
}
}
// We always attach the actual commands to the first output.
@ -1010,7 +1022,7 @@ void cmMakefileTargetGenerator::WriteMakeRule(
// For single outputs, we are done.
if (outputs.size() == 1)
{
return;
return symbolic;
}
// For multiple outputs, make the extra ones depend on the first one.
@ -1023,14 +1035,25 @@ void cmMakefileTargetGenerator::WriteMakeRule(
std::string const out = this->Convert(*o, cmLocalGenerator::HOME_OUTPUT,
cmLocalGenerator::SHELL);
std::vector<std::string> output_commands;
if (!symbolic)
bool o_symbolic = false;
if(need_symbolic)
{
if(cmSourceFile* sf = this->Makefile->GetSource(*o))
{
o_symbolic = sf->GetPropertyAsBool("SYMBOLIC");
}
}
symbolic = symbolic && o_symbolic;
if (!o_symbolic)
{
output_commands.push_back("@$(CMAKE_COMMAND) -E touch_nocreate " + out);
}
this->LocalGenerator->WriteMakeRule(os, 0, *o, output_depends,
output_commands, symbolic, in_help);
output_commands, o_symbolic, in_help);
if (!symbolic)
if (!o_symbolic)
{
// At build time, remove the first output if this one does not exist
// so that "make" will rerun the real commands that create this one.
@ -1038,6 +1061,7 @@ void cmMakefileTargetGenerator::WriteMakeRule(
this->MultipleOutputPairs.insert(p);
}
}
return symbolic;
}
//----------------------------------------------------------------------------
@ -1289,30 +1313,16 @@ void cmMakefileTargetGenerator
std::vector<std::string> depends;
this->LocalGenerator->AppendCustomDepend(depends, ccg);
// Check whether we need to bother checking for a symbolic output.
bool need_symbolic = this->GlobalGenerator->GetNeedSymbolicMark();
// Write the rule.
const std::vector<std::string>& outputs = ccg.GetOutputs();
std::vector<std::string>::const_iterator o = outputs.begin();
{
bool symbolic = false;
if(need_symbolic)
{
if(cmSourceFile* sf = this->Makefile->GetSource(*o))
{
symbolic = sf->GetPropertyAsBool("SYMBOLIC");
}
}
this->WriteMakeRule(*this->BuildFileStream, 0, outputs,
depends, commands, symbolic);
bool symbolic = this->WriteMakeRule(*this->BuildFileStream, 0,
outputs, depends, commands);
// If the rule has changed make sure the output is rebuilt.
if(!symbolic)
{
this->GlobalGenerator->AddRuleHash(ccg.GetOutputs(), content.str());
}
}
// Setup implicit dependency scanning.
for(cmCustomCommand::ImplicitDependsList::const_iterator

View File

@ -224,12 +224,11 @@ protected:
typedef std::map<std::string, std::string> MultipleOutputPairsType;
MultipleOutputPairsType MultipleOutputPairs;
void WriteMakeRule(std::ostream& os,
bool WriteMakeRule(std::ostream& os,
const char* comment,
const std::vector<std::string>& outputs,
const std::vector<std::string>& depends,
const std::vector<std::string>& commands,
bool symbolic,
bool in_help = false);
// Target name info.

View File

@ -42,6 +42,11 @@ list(APPEND _cmake_options "-DTEST_LINK_DEPENDS=${TEST_LINK_DEPENDS}")
list(APPEND _cmake_options "-DCMAKE_FORCE_DEPFILES=1")
if(NOT CMAKE_GENERATOR MATCHES "Visual Studio ([^6789]|[6789][0-9])")
set(TEST_MULTI3 1)
list(APPEND _cmake_options "-DTEST_MULTI3=1")
endif()
file(MAKE_DIRECTORY ${BuildDepends_BINARY_DIR}/Project)
message("Creating Project/foo.cxx")
write_file(${BuildDepends_BINARY_DIR}/Project/foo.cxx
@ -66,6 +71,8 @@ set(link_depends_no_shared_check_txt ${BuildDepends_BINARY_DIR}/Project/link_dep
file(WRITE ${BuildDepends_BINARY_DIR}/Project/external.in "external original\n")
file(WRITE ${BuildDepends_BINARY_DIR}/Project/multi1-in.txt "multi1-in original\n")
file(WRITE ${BuildDepends_BINARY_DIR}/Project/multi2-stamp.txt "multi2-stamp original\n")
file(WRITE ${BuildDepends_BINARY_DIR}/Project/multi3-stamp.txt "multi3-stamp original\n")
help_xcode_depends()
@ -191,6 +198,34 @@ else()
"multi1-out2-copy.txt is missing")
endif()
if(EXISTS ${BuildDepends_BINARY_DIR}/Project/multi2-real.txt)
if(${BuildDepends_BINARY_DIR}/Project/multi2-real.txt
IS_NEWER_THAN ${BuildDepends_BINARY_DIR}/Project/multi2-stamp.txt)
message(STATUS "multi2-real.txt is newer than multi2-stamp.txt")
else()
message(SEND_ERROR "Project did not initially build properly: "
"multi2-real.txt is not newer than multi2-stamp.txt")
endif()
else()
message(SEND_ERROR "Project did not initially build properly: "
"multi2-real.txt is missing")
endif()
if(TEST_MULTI3)
if(EXISTS ${BuildDepends_BINARY_DIR}/Project/multi3-real.txt)
if(${BuildDepends_BINARY_DIR}/Project/multi3-real.txt
IS_NEWER_THAN ${BuildDepends_BINARY_DIR}/Project/multi3-stamp.txt)
message(STATUS "multi3-real.txt is newer than multi3-stamp.txt")
else()
message(SEND_ERROR "Project did not initially build properly: "
"multi3-real.txt is not newer than multi3-stamp.txt")
endif()
else()
message(SEND_ERROR "Project did not initially build properly: "
"multi3-real.txt is missing")
endif()
endif()
message("Waiting 3 seconds...")
execute_process(COMMAND ${CMAKE_COMMAND} -E sleep 3)
@ -217,6 +252,8 @@ endif()
file(WRITE ${BuildDepends_BINARY_DIR}/Project/external.in "external changed\n")
file(WRITE ${BuildDepends_BINARY_DIR}/Project/multi1-in.txt "multi1-in changed\n")
file(WRITE ${BuildDepends_BINARY_DIR}/Project/multi2-stamp.txt "multi2-stamp changed\n")
file(WRITE ${BuildDepends_BINARY_DIR}/Project/multi3-stamp.txt "multi3-stamp changed\n")
help_xcode_depends()
@ -347,3 +384,31 @@ else()
message(SEND_ERROR "Project did not rebuild properly: "
"multi1-out2-copy.txt is missing")
endif()
if(EXISTS ${BuildDepends_BINARY_DIR}/Project/multi2-real.txt)
if(${BuildDepends_BINARY_DIR}/Project/multi2-real.txt
IS_NEWER_THAN ${BuildDepends_BINARY_DIR}/Project/multi2-stamp.txt)
message(STATUS "multi2-real.txt is newer than multi2-stamp.txt")
else()
message(SEND_ERROR "Project did not rebuild properly: "
"multi2-real.txt is not newer than multi2-stamp.txt")
endif()
else()
message(SEND_ERROR "Project did not rebuild properly: "
"multi2-real.txt is missing")
endif()
if(TEST_MULTI3)
if(EXISTS ${BuildDepends_BINARY_DIR}/Project/multi3-real.txt)
if(${BuildDepends_BINARY_DIR}/Project/multi3-real.txt
IS_NEWER_THAN ${BuildDepends_BINARY_DIR}/Project/multi3-stamp.txt)
message(STATUS "multi3-real.txt is newer than multi3-stamp.txt")
else()
message(SEND_ERROR "Project did not rebuild properly: "
"multi3-real.txt is not newer than multi3-stamp.txt")
endif()
else()
message(SEND_ERROR "Project did not rebuild properly: "
"multi3-real.txt is missing")
endif()
endif()

View File

@ -164,3 +164,21 @@ add_custom_command(
DEPENDS multi1-out2.txt
)
add_custom_target(multi1 ALL DEPENDS multi1-out2-copy.txt)
# Test having the first output never created.
add_custom_command(
OUTPUT multi2-dummy.txt multi2-real.txt
COMMAND ${CMAKE_COMMAND} -E touch multi2-real.txt
)
set_property(SOURCE multi2-real.txt multi2-dummy.txt PROPERTY SYMBOLIC 1)
add_custom_target(multi2 ALL DEPENDS multi2-real.txt)
if(TEST_MULTI3)
# Test having the second output never created. Does not work with msbuild.
add_custom_command(
OUTPUT multi3-real.txt multi3-dummy.txt
COMMAND ${CMAKE_COMMAND} -E touch multi3-real.txt
)
set_property(SOURCE multi3-real.txt multi3-dummy.txt PROPERTY SYMBOLIC 1)
add_custom_target(multi3 ALL DEPENDS multi3-real.txt)
endif()