From c288da754a3f1221ca4ebfd9c9efb8c935d499d6 Mon Sep 17 00:00:00 2001 From: Brad King Date: Wed, 23 May 2007 13:27:00 -0400 Subject: 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. --- Source/cmAddCustomCommandCommand.h | 18 +++++++- Source/cmTarget.cxx | 70 ++++++++++++++----------------- Source/cmTarget.h | 5 ++- Tests/BuildDepends/CMakeLists.txt | 2 +- Tests/BuildDepends/Project/CMakeLists.txt | 28 ++++++++++++- Tests/BuildDepends/Project/bar.cxx | 17 ++++++-- 6 files changed, 93 insertions(+), 47 deletions(-) diff --git a/Source/cmAddCustomCommandCommand.h b/Source/cmAddCustomCommandCommand.h index 81338d6..76d9ec7 100644 --- a/Source/cmAddCustomCommandCommand.h +++ b/Source/cmAddCustomCommandCommand.h @@ -124,7 +124,23 @@ public: "it is an option is to preserve compatibility with older CMake code.\n" "If the output of the custom command is not actually " "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); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index 6ae0aef..da33e07 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -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 ::CheckForTargetsAsCommand(const std::vector& commands) { @@ -417,20 +439,7 @@ cmTarget cli != commands.end(); ++cli ) { - for(cmCustomCommandLines::const_iterator cit = - 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() ); - } - } + this->CheckForTargetsAsCommand(*cli); } } @@ -566,24 +575,8 @@ void cmTarget::TraceVSDependencies(std::string projFile, } } - // check if commands for this custom commands are names of targets and - // if that's the case add these targets as dependencies - std::vector 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 target-level dependencies for the commands. + this->CheckForTargetsAsCommand(*outsf->GetCustomCommand()); // add its dependencies to the list to check for (unsigned int i = 0; @@ -598,10 +591,9 @@ void cmTarget::TraceVSDependencies(std::string projFile, dep = cmSystemTools::GetFilenameWithoutLastExtension(dep); } bool isUtility = false; - // see if we can find a target with this name - cmTarget* t = this->Makefile->GetLocalGenerator()-> - GetGlobalGenerator()->FindTarget(0, dep.c_str(), false); - if(t) + // Check for a non-imported target with this name. + if(cmTarget* t = this->Makefile->GetLocalGenerator()-> + GetGlobalGenerator()->FindTarget(0, dep.c_str(), false)) { // 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 @@ -629,7 +621,9 @@ void cmTarget::TraceVSDependencies(std::string projFile, } 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()); } else diff --git a/Source/cmTarget.h b/Source/cmTarget.h index 4161b35..8bb8f9b 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -296,9 +296,10 @@ private: const LibraryID& dep); /* - * Checks the prebuild, prelink and postbuild custom commands for known - * targets and adds them to the dependencies. + * Check custom commands for known targets and add a target-level + * dependency. */ + void CheckForTargetsAsCommand(const cmCustomCommand& cc); void CheckForTargetsAsCommand(const std::vector& commands); diff --git a/Tests/BuildDepends/CMakeLists.txt b/Tests/BuildDepends/CMakeLists.txt index 80793bc..3a4ba26 100644 --- a/Tests/BuildDepends/CMakeLists.txt +++ b/Tests/BuildDepends/CMakeLists.txt @@ -60,5 +60,5 @@ message("${out}") if("${out}" STREQUAL "foo changed ") message("Worked!") 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 ") diff --git a/Tests/BuildDepends/Project/CMakeLists.txt b/Tests/BuildDepends/Project/CMakeLists.txt index f9cbc56..e831676 100644 --- a/Tests/BuildDepends/Project/CMakeLists.txt +++ b/Tests/BuildDepends/Project/CMakeLists.txt @@ -1,4 +1,30 @@ project(testRebuild) 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) diff --git a/Tests/BuildDepends/Project/bar.cxx b/Tests/BuildDepends/Project/bar.cxx index 4764af5..76e934f 100644 --- a/Tests/BuildDepends/Project/bar.cxx +++ b/Tests/BuildDepends/Project/bar.cxx @@ -1,10 +1,19 @@ -#include "stdio.h" +#include +#include +#include +#include -const char* foo(); int main() { - int i; - printf("%s\n", foo()); + /* Make sure the noregen header was not regenerated. */ + 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); for(;;); return 0; -- cgit v0.12