BUG: Target names in the COMMAND part of a custom command should not create a file-level dependency that forces the command to rerun when the executable target rebuilds, but the target-level dependency should still be created. Target names in a DEPENDS should do both a target-level and file-level dependency. Updated the BuildDepends test to check that this works.

This commit is contained in:
Brad King 2007-05-23 13:27:00 -04:00
parent 702d785c9a
commit c288da754a
6 changed files with 93 additions and 47 deletions

View File

@ -124,7 +124,23 @@ public:
"it is an option is to preserve compatibility with older CMake code.\n" "it is an option is to preserve compatibility with older CMake code.\n"
"If the output of the custom command is not actually " "If the output of the custom command is not actually "
"created as a file on disk it should be marked as SYMBOLIC with " "created as a file on disk it should be marked as SYMBOLIC with "
"SET_SOURCE_FILES_PROPERTIES."; "SET_SOURCE_FILES_PROPERTIES.\n"
"If COMMAND specifies an executable target (created by "
"ADD_EXECUTABLE) it will automatically be replaced by the location "
"of the executable created at build time. Additionally a "
"target-level dependency will be added so that the executable target "
"will be built before any target using this custom command. However "
"this does NOT add a file-level dependency that would cause the "
"custom command to re-run whenever the executable is recompiled.\n"
"If DEPENDS specifies any target (created by an ADD_* command) "
"a target-level dependency is created to make sure the target is "
"built before any target using this custom command. Additionally, "
"if the target is an executable or library a file-level dependency "
"is created to cause the custom command to re-run whenever the target "
"is recompiled.\n"
;
} }
cmTypeMacro(cmAddCustomCommandCommand, cmCommand); cmTypeMacro(cmAddCustomCommandCommand, cmCommand);

View File

@ -409,7 +409,29 @@ void cmTarget::SetMakefile(cmMakefile* mf)
} }
void void cmTarget::CheckForTargetsAsCommand(const cmCustomCommand& cc)
{
for(cmCustomCommandLines::const_iterator cit = cc.GetCommandLines().begin();
cit != cc.GetCommandLines().end(); ++cit )
{
std::string const& command = *cit->begin();
// Look for a non-imported target with this name.
if(cmTarget* t = this->Makefile->GetLocalGenerator()->
GetGlobalGenerator()->FindTarget(0, command.c_str(), false))
{
if(t->GetType() == cmTarget::EXECUTABLE)
{
// The command refers to an executable target built in
// this project. Add the target-level dependency to make
// sure the executable is up to date before this custom
// command possibly runs.
this->AddUtility(command.c_str());
}
}
}
}
void
cmTarget cmTarget
::CheckForTargetsAsCommand(const std::vector<cmCustomCommand>& commands) ::CheckForTargetsAsCommand(const std::vector<cmCustomCommand>& commands)
{ {
@ -417,20 +439,7 @@ cmTarget
cli != commands.end(); cli != commands.end();
++cli ) ++cli )
{ {
for(cmCustomCommandLines::const_iterator cit = this->CheckForTargetsAsCommand(*cli);
cli->GetCommandLines().begin();
cit!=cli->GetCommandLines().end();
++cit )
{
std::string command = *cit->begin();
// see if we can find a target with this name
cmTarget* t = this->Makefile->GetLocalGenerator()->
GetGlobalGenerator()->FindTarget(0, command.c_str(), false);
if ( ( t ) && ( t->GetType() ==cmTarget::EXECUTABLE ) )
{
this->AddUtility ( command.c_str() );
}
}
} }
} }
@ -566,24 +575,8 @@ void cmTarget::TraceVSDependencies(std::string projFile,
} }
} }
// check if commands for this custom commands are names of targets and // Add target-level dependencies for the commands.
// if that's the case add these targets as dependencies this->CheckForTargetsAsCommand(*outsf->GetCustomCommand());
std::vector<std::string> automaticTargetDepends;
for(cmCustomCommandLines::const_iterator it=
outsf->GetCustomCommand()->GetCommandLines().begin();
it!=outsf->GetCustomCommand()->GetCommandLines().end();
++it)
{
const std::string& currentCommand = (*it)[0];
// see if we can find a target with this name
cmTarget* t = this->Makefile->GetLocalGenerator()->
GetGlobalGenerator()->FindTarget(0, currentCommand.c_str(), false);
if (( t) && (t->GetType()==cmTarget::EXECUTABLE))
{
automaticTargetDepends.push_back(currentCommand);
}
}
outsf->GetCustomCommand()->AppendDepends(automaticTargetDepends);
// add its dependencies to the list to check // add its dependencies to the list to check
for (unsigned int i = 0; for (unsigned int i = 0;
@ -598,10 +591,9 @@ void cmTarget::TraceVSDependencies(std::string projFile,
dep = cmSystemTools::GetFilenameWithoutLastExtension(dep); dep = cmSystemTools::GetFilenameWithoutLastExtension(dep);
} }
bool isUtility = false; bool isUtility = false;
// see if we can find a target with this name // Check for a non-imported target with this name.
cmTarget* t = this->Makefile->GetLocalGenerator()-> if(cmTarget* t = this->Makefile->GetLocalGenerator()->
GetGlobalGenerator()->FindTarget(0, dep.c_str(), false); GetGlobalGenerator()->FindTarget(0, dep.c_str(), false))
if(t)
{ {
// if we find the target and the dep was given as a full // if we find the target and the dep was given as a full
// path, then make sure it was not a full path to something // path, then make sure it was not a full path to something
@ -629,7 +621,9 @@ void cmTarget::TraceVSDependencies(std::string projFile,
} }
if(isUtility) if(isUtility)
{ {
// add the depend as a utility on the target // The dependency refers to a target built in this project.
// Add the target-level dependency to make sure the target
// is up to date before this custom command possibly runs.
this->AddUtility(dep.c_str()); this->AddUtility(dep.c_str());
} }
else else

View File

@ -296,9 +296,10 @@ private:
const LibraryID& dep); const LibraryID& dep);
/* /*
* Checks the prebuild, prelink and postbuild custom commands for known * Check custom commands for known targets and add a target-level
* targets and adds them to the dependencies. * dependency.
*/ */
void CheckForTargetsAsCommand(const cmCustomCommand& cc);
void CheckForTargetsAsCommand(const std::vector<cmCustomCommand>& commands); void CheckForTargetsAsCommand(const std::vector<cmCustomCommand>& commands);

View File

@ -60,5 +60,5 @@ message("${out}")
if("${out}" STREQUAL "foo changed ") if("${out}" STREQUAL "foo changed ")
message("Worked!") message("Worked!")
else("${out}" STREQUAL "foo changed ") else("${out}" STREQUAL "foo changed ")
message(SEND_ERROR "Program did not rebuild with changed file") message(SEND_ERROR "Project did not rebuild properly!")
endif("${out}" STREQUAL "foo changed ") endif("${out}" STREQUAL "foo changed ")

View File

@ -1,4 +1,30 @@
project(testRebuild) project(testRebuild)
add_library(foo STATIC ${testRebuild_BINARY_DIR}/foo.cxx) add_library(foo STATIC ${testRebuild_BINARY_DIR}/foo.cxx)
add_executable(bar bar.cxx)
# Add a generated header that regenerates when the generator is
# rebuilt.
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/regen.h
COMMAND generator ${CMAKE_CURRENT_BINARY_DIR}/regen.h regen
DEPENDS generator # adds file-level dependency to re-run rule
)
# Add a generated header that does NOT regenerate when the generator
# is rebuilt.
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/noregen.h
COMMAND generator ${CMAKE_CURRENT_BINARY_DIR}/noregen.h noregen
)
# Test that the generator rebuilds when the static library source file
# changes. This should cause regen.h to be recreated also.
add_executable(generator generator.cxx)
target_link_libraries(generator foo)
# Build an executable to drive the build and rebuild.
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_executable(bar bar.cxx
${CMAKE_CURRENT_BINARY_DIR}/regen.h
${CMAKE_CURRENT_BINARY_DIR}/noregen.h
)
target_link_libraries(bar foo) target_link_libraries(bar foo)

View File

@ -1,10 +1,19 @@
#include "stdio.h" #include <stdio.h>
#include <string.h>
#include <regen.h>
#include <noregen.h>
const char* foo();
int main() int main()
{ {
int i; /* Make sure the noregen header was not regenerated. */
printf("%s\n", foo()); if(strcmp("foo", noregen_string) != 0)
{
printf("FAILED: noregen.h was regenerated!\n");
return 1;
}
/* Print out the string that should have been regenerated. */
printf("%s\n", regen_string);
fflush(stdout); fflush(stdout);
for(;;); for(;;);
return 0; return 0;