summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2007-04-04 18:50:35 (GMT)
committerBrad King <brad.king@kitware.com>2007-04-04 18:50:35 (GMT)
commit438a7e2fcef6c82dd93e0106208dbaee7e9ccfc4 (patch)
tree457a6595797e62866b70c4d7e6b4f428b7da033b
parent2803688998cebbd40df1a0678106e62271217add (diff)
downloadCMake-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.cxx12
-rw-r--r--Source/cmGlobalVisualStudio71Generator.cxx12
-rw-r--r--Source/cmGlobalVisualStudio7Generator.cxx15
-rw-r--r--Source/cmGlobalVisualStudio8Generator.h4
-rw-r--r--Source/cmGlobalVisualStudioGenerator.cxx168
-rw-r--r--Source/cmGlobalVisualStudioGenerator.h9
-rw-r--r--Tests/Dependency/Two/CMakeLists.txt17
-rw-r--r--Tests/Dependency/Two/TwoCustomSrc.c10
-rw-r--r--Tests/Dependency/Two/TwoSrc.c2
-rw-r--r--Tests/Dependency/Two/two-test.h.in1
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();