diff options
author | Brad King <brad.king@kitware.com> | 2007-04-04 18:50:35 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2007-04-04 18:50:35 (GMT) |
commit | 438a7e2fcef6c82dd93e0106208dbaee7e9ccfc4 (patch) | |
tree | 457a6595797e62866b70c4d7e6b4f428b7da033b | |
parent | 2803688998cebbd40df1a0678106e62271217add (diff) | |
download | CMake-438a7e2fcef6c82dd93e0106208dbaee7e9ccfc4.zip CMake-438a7e2fcef6c82dd93e0106208dbaee7e9ccfc4.tar.gz CMake-438a7e2fcef6c82dd93e0106208dbaee7e9ccfc4.tar.bz2 |
BUG: Fix utility dependencies for static libraries in VS generators. This addresses bug#4789.
-rw-r--r-- | Source/cmGlobalVisualStudio6Generator.cxx | 12 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudio71Generator.cxx | 12 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudio7Generator.cxx | 15 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudio8Generator.h | 4 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudioGenerator.cxx | 168 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudioGenerator.h | 9 | ||||
-rw-r--r-- | Tests/Dependency/Two/CMakeLists.txt | 17 | ||||
-rw-r--r-- | Tests/Dependency/Two/TwoCustomSrc.c | 10 | ||||
-rw-r--r-- | Tests/Dependency/Two/TwoSrc.c | 2 | ||||
-rw-r--r-- | Tests/Dependency/Two/two-test.h.in | 1 |
10 files changed, 220 insertions, 30 deletions
diff --git a/Source/cmGlobalVisualStudio6Generator.cxx b/Source/cmGlobalVisualStudio6Generator.cxx index 10260d7..fb475c3 100644 --- a/Source/cmGlobalVisualStudio6Generator.cxx +++ b/Source/cmGlobalVisualStudio6Generator.cxx @@ -177,7 +177,10 @@ void cmGlobalVisualStudio6Generator::Generate() "echo", "Build all projects"); } } - + + // Fix utility dependencies to avoid linking to libraries. + this->FixUtilityDepends(); + // first do the superclass method this->cmGlobalGenerator::Generate(); @@ -438,12 +441,7 @@ void cmGlobalVisualStudio6Generator::WriteProject(std::ostream& fout, { if(*i != dspname) { - std::string depName = *i; - if(strncmp(depName.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) - { - depName.erase(depName.begin(), depName.begin() + 27); - } - + std::string depName = this->GetUtilityForTarget(target, i->c_str()); fout << "Begin Project Dependency\n"; fout << "Project_Dep_Name " << depName << "\n"; fout << "End Project Dependency\n"; diff --git a/Source/cmGlobalVisualStudio71Generator.cxx b/Source/cmGlobalVisualStudio71Generator.cxx index e29227d..fec8df9 100644 --- a/Source/cmGlobalVisualStudio71Generator.cxx +++ b/Source/cmGlobalVisualStudio71Generator.cxx @@ -349,17 +349,7 @@ cmGlobalVisualStudio71Generator { if(*i != dspname) { - std::string name = i->c_str(); - if(strncmp(name.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) - { - // kind of weird removing the first 27 letters. my - // recommendatsions: use cmCustomCommand::GetCommand() to get the - // project name or get rid of the target name starting with - // "INCLUDE_EXTERNAL_MSPROJECT_" and use another indicator/flag - // somewhere. These external project names shouldn't conflict - // with cmake target names anyways. - name.erase(name.begin(), name.begin() + 27); - } + std::string name = this->GetUtilityForTarget(target, i->c_str()); std::string guid = this->GetGUID(name.c_str()); if(guid.size() == 0) { diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 278ebb2..1918674 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -235,6 +235,9 @@ void cmGlobalVisualStudio7Generator::Generate() } } + // Fix utility dependencies to avoid linking to libraries. + this->FixUtilityDepends(); + // first do the superclass method this->cmGlobalGenerator::Generate(); @@ -634,17 +637,7 @@ cmGlobalVisualStudio7Generator { if(*i != dspname) { - std::string name = *i; - if(strncmp(name.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) - { - // kind of weird removing the first 27 letters. my - // recommendatsions: use cmCustomCommand::GetCommand() to get the - // project name or get rid of the target name starting with - // "INCLUDE_EXTERNAL_MSPROJECT_" and use another indicator/flag - // somewhere. These external project names shouldn't conflict - // with cmake target names anyways. - name.erase(name.begin(), name.begin() + 27); - } + std::string name = this->GetUtilityForTarget(target, i->c_str()); std::string guid = this->GetGUID(name.c_str()); if(guid.size() == 0) { diff --git a/Source/cmGlobalVisualStudio8Generator.h b/Source/cmGlobalVisualStudio8Generator.h index 486c885..38963e3 100644 --- a/Source/cmGlobalVisualStudio8Generator.h +++ b/Source/cmGlobalVisualStudio8Generator.h @@ -50,6 +50,10 @@ public: virtual void Configure(); virtual void Generate(); protected: + + // Utility target fix is not needed for VS8. + virtual void FixUtilityDepends() {} + static cmVS7FlagTable const* GetExtraFlagTableVS8(); virtual void AddPlatformDefinitions(cmMakefile* mf); virtual void WriteSLNFile(std::ostream& fout, cmLocalGenerator* root, diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index 8a7c4ff..46ce76e 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -16,6 +16,10 @@ =========================================================================*/ #include "cmGlobalVisualStudioGenerator.h" +#include "cmLocalGenerator.h" +#include "cmMakefile.h" +#include "cmTarget.h" + //---------------------------------------------------------------------------- cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator() { @@ -25,3 +29,167 @@ cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator() cmGlobalVisualStudioGenerator::~cmGlobalVisualStudioGenerator() { } + +//---------------------------------------------------------------------------- +void cmGlobalVisualStudioGenerator::FixUtilityDepends() +{ + // For VS versions before 8: + // + // When a target that links contains a project-level dependency on a + // library target that library is automatically linked. In order to + // allow utility-style project-level dependencies that do not + // actually link we need to automatically insert an intermediate + // custom target. + // + // Here we edit the utility dependencies of a target to add the + // intermediate custom target when necessary. + for(unsigned i = 0; i < this->LocalGenerators.size(); ++i) + { + cmTargets* targets = + &(this->LocalGenerators[i]->GetMakefile()->GetTargets()); + for(cmTargets::iterator tarIt = targets->begin(); + tarIt != targets->end(); ++tarIt) + { + this->FixUtilityDependsForTarget(tarIt->second); + } + } +} + +//---------------------------------------------------------------------------- +void +cmGlobalVisualStudioGenerator::FixUtilityDependsForTarget(cmTarget& target) +{ + // Only targets that link need to be fixed. + if(target.GetType() != cmTarget::STATIC_LIBRARY && + target.GetType() != cmTarget::SHARED_LIBRARY && + target.GetType() != cmTarget::MODULE_LIBRARY && + target.GetType() != cmTarget::EXECUTABLE) + { + return; + } + + // Look at each utility dependency. + for(std::set<cmStdString>::const_iterator ui = + target.GetUtilities().begin(); + ui != target.GetUtilities().end(); ++ui) + { + if(cmTarget* depTarget = this->FindTarget(0, ui->c_str())) + { + if(depTarget->GetType() == cmTarget::STATIC_LIBRARY || + depTarget->GetType() == cmTarget::SHARED_LIBRARY || + depTarget->GetType() == cmTarget::MODULE_LIBRARY) + { + // This utility dependency will cause an attempt to link. If + // the depender does not already link the dependee we need an + // intermediate target. + if(!this->CheckTargetLinks(target, ui->c_str())) + { + this->CreateUtilityDependTarget(*depTarget); + } + } + } + } +} + +//---------------------------------------------------------------------------- +void +cmGlobalVisualStudioGenerator::CreateUtilityDependTarget(cmTarget& target) +{ + // This target is a library on which a utility dependency exists. + // We need to create an intermediate custom target to hook up the + // dependency without causing a link. + const char* altName = target.GetProperty("ALTERNATIVE_DEPENDENCY_NAME"); + if(!altName) + { + // Create the intermediate utility target. + std::string altNameStr = target.GetName(); + altNameStr += "_UTILITY"; + const std::vector<std::string> no_depends; + cmCustomCommandLines no_commands; + const char* no_working_dir = 0; + const char* no_comment = 0; + target.GetMakefile()->AddUtilityCommand(altNameStr.c_str(), true, + no_working_dir, no_depends, + no_commands, false, no_comment); + target.SetProperty("ALTERNATIVE_DEPENDENCY_NAME", altNameStr.c_str()); + + // Most targets have a GUID created in ConfigureFinalPass. Since + // that has already been called, create one for this target now. + this->CreateGUID(altNameStr.c_str()); + + // The intermediate target should depend on the original target. + if(cmTarget* alt = this->FindTarget(0, altNameStr.c_str())) + { + alt->AddUtility(target.GetName()); + } + } +} + +//---------------------------------------------------------------------------- +bool cmGlobalVisualStudioGenerator::CheckTargetLinks(cmTarget& target, + const char* name) +{ + // Return whether the given target links to a target with the given name. + if(target.GetType() == cmTarget::STATIC_LIBRARY) + { + // Static libraries never link to anything. + return false; + } + cmTarget::LinkLibraryVectorType const& libs = target.GetLinkLibraries(); + for(cmTarget::LinkLibraryVectorType::const_iterator i = libs.begin(); + i != libs.end(); ++i) + { + if(i->first == name) + { + return true; + } + } + return false; +} + +//---------------------------------------------------------------------------- +const char* +cmGlobalVisualStudioGenerator::GetUtilityForTarget(cmTarget& target, + const char* name) +{ + // Handle the external MS project special case. + if(strncmp(name, "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0) + { + // Note from Ken: + // kind of weird removing the first 27 letters. my + // recommendatsions: use cmCustomCommand::GetCommand() to get the + // project name or get rid of the target name starting with + // "INCLUDE_EXTERNAL_MSPROJECT_" and use another indicator/flag + // somewhere. These external project names shouldn't conflict + // with cmake target names anyways. + return name+27; + } + + // Possibly depend on an intermediate utility target to avoid + // linking. + if(target.GetType() == cmTarget::STATIC_LIBRARY || + target.GetType() == cmTarget::SHARED_LIBRARY || + target.GetType() == cmTarget::MODULE_LIBRARY || + target.GetType() == cmTarget::EXECUTABLE) + { + // The depender is a target that links. Lookup the dependee to + // see if it provides an alternative dependency name. + if(cmTarget* depTarget = this->FindTarget(0, name)) + { + // Check for an alternative name created by FixUtilityDepends. + if(const char* altName = + depTarget->GetProperty("ALTERNATIVE_DEPENDENCY_NAME")) + { + // The alternative name is needed only if the depender does + // not really link to the dependee. + if(!this->CheckTargetLinks(target, name)) + { + return altName; + } + } + } + } + + // No special case. Just use the original dependency name. + return name; +} diff --git a/Source/cmGlobalVisualStudioGenerator.h b/Source/cmGlobalVisualStudioGenerator.h index 53bee5f..5e08443 100644 --- a/Source/cmGlobalVisualStudioGenerator.h +++ b/Source/cmGlobalVisualStudioGenerator.h @@ -30,6 +30,15 @@ class cmGlobalVisualStudioGenerator : public cmGlobalGenerator public: cmGlobalVisualStudioGenerator(); virtual ~cmGlobalVisualStudioGenerator(); + +protected: + virtual void CreateGUID(const char*) {} + virtual void FixUtilityDepends(); + const char* GetUtilityForTarget(cmTarget& target, const char*); +private: + void FixUtilityDependsForTarget(cmTarget& target); + void CreateUtilityDependTarget(cmTarget& target); + bool CheckTargetLinks(cmTarget& target, const char* name); }; #endif diff --git a/Tests/Dependency/Two/CMakeLists.txt b/Tests/Dependency/Two/CMakeLists.txt index 6a9630e..587c848 100644 --- a/Tests/Dependency/Two/CMakeLists.txt +++ b/Tests/Dependency/Two/CMakeLists.txt @@ -1,3 +1,20 @@ +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) ADD_LIBRARY( Two TwoSrc.c ) TARGET_LINK_LIBRARIES( Two Three ) +# Setup a target to cause failure if Two does not depend on it or if +# Two actually links to it. This will test that a utility dependency +# on a library target works properly. +ADD_CUSTOM_COMMAND( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/two-test.h + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${CMAKE_CURRENT_SOURCE_DIR}/two-test.h.in + ${CMAKE_CURRENT_BINARY_DIR}/two-test.h + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/two-test.h.in + ) +ADD_LIBRARY( TwoCustom TwoCustomSrc.c ${CMAKE_CURRENT_BINARY_DIR}/two-test.h) +SET_TARGET_PROPERTIES(TwoCustom PROPERTIES EXCLUDE_FROM_ALL 1) +TARGET_LINK_LIBRARIES(TwoCustom Three) + +# Add a utility dependency to make sure it works without linking. +ADD_DEPENDENCIES(Two TwoCustom) diff --git a/Tests/Dependency/Two/TwoCustomSrc.c b/Tests/Dependency/Two/TwoCustomSrc.c new file mode 100644 index 0000000..ac31dcf --- /dev/null +++ b/Tests/Dependency/Two/TwoCustomSrc.c @@ -0,0 +1,10 @@ +extern void NoFunction(); + +/* Provide a function that is supposed to be found in the Three + library. If Two links to TwoCustom then TwoCustom will come before + Three and this symbol will be used. Since NoFunction is not + defined, that will cause a link failure. */ +void ThreeFunction() +{ + NoFunction(); +} diff --git a/Tests/Dependency/Two/TwoSrc.c b/Tests/Dependency/Two/TwoSrc.c index 981df09..0b3366b 100644 --- a/Tests/Dependency/Two/TwoSrc.c +++ b/Tests/Dependency/Two/TwoSrc.c @@ -1,4 +1,4 @@ -void ThreeFunction(); +#include <two-test.h> void TwoFunction() { diff --git a/Tests/Dependency/Two/two-test.h.in b/Tests/Dependency/Two/two-test.h.in new file mode 100644 index 0000000..8c6a7f7 --- /dev/null +++ b/Tests/Dependency/Two/two-test.h.in @@ -0,0 +1 @@ +extern void ThreeFunction(); |