BUG: Fix utility dependencies for static libraries in VS generators. This addresses bug#4789.
This commit is contained in:
parent
2803688998
commit
438a7e2fce
|
@ -177,7 +177,10 @@ void cmGlobalVisualStudio6Generator::Generate()
|
||||||
"echo", "Build all projects");
|
"echo", "Build all projects");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix utility dependencies to avoid linking to libraries.
|
||||||
|
this->FixUtilityDepends();
|
||||||
|
|
||||||
// first do the superclass method
|
// first do the superclass method
|
||||||
this->cmGlobalGenerator::Generate();
|
this->cmGlobalGenerator::Generate();
|
||||||
|
|
||||||
|
@ -438,12 +441,7 @@ void cmGlobalVisualStudio6Generator::WriteProject(std::ostream& fout,
|
||||||
{
|
{
|
||||||
if(*i != dspname)
|
if(*i != dspname)
|
||||||
{
|
{
|
||||||
std::string depName = *i;
|
std::string depName = this->GetUtilityForTarget(target, i->c_str());
|
||||||
if(strncmp(depName.c_str(), "INCLUDE_EXTERNAL_MSPROJECT", 26) == 0)
|
|
||||||
{
|
|
||||||
depName.erase(depName.begin(), depName.begin() + 27);
|
|
||||||
}
|
|
||||||
|
|
||||||
fout << "Begin Project Dependency\n";
|
fout << "Begin Project Dependency\n";
|
||||||
fout << "Project_Dep_Name " << depName << "\n";
|
fout << "Project_Dep_Name " << depName << "\n";
|
||||||
fout << "End Project Dependency\n";
|
fout << "End Project Dependency\n";
|
||||||
|
|
|
@ -349,17 +349,7 @@ cmGlobalVisualStudio71Generator
|
||||||
{
|
{
|
||||||
if(*i != dspname)
|
if(*i != dspname)
|
||||||
{
|
{
|
||||||
std::string name = i->c_str();
|
std::string name = this->GetUtilityForTarget(target, 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 guid = this->GetGUID(name.c_str());
|
std::string guid = this->GetGUID(name.c_str());
|
||||||
if(guid.size() == 0)
|
if(guid.size() == 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -235,6 +235,9 @@ void cmGlobalVisualStudio7Generator::Generate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix utility dependencies to avoid linking to libraries.
|
||||||
|
this->FixUtilityDepends();
|
||||||
|
|
||||||
// first do the superclass method
|
// first do the superclass method
|
||||||
this->cmGlobalGenerator::Generate();
|
this->cmGlobalGenerator::Generate();
|
||||||
|
|
||||||
|
@ -634,17 +637,7 @@ cmGlobalVisualStudio7Generator
|
||||||
{
|
{
|
||||||
if(*i != dspname)
|
if(*i != dspname)
|
||||||
{
|
{
|
||||||
std::string name = *i;
|
std::string name = this->GetUtilityForTarget(target, 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 guid = this->GetGUID(name.c_str());
|
std::string guid = this->GetGUID(name.c_str());
|
||||||
if(guid.size() == 0)
|
if(guid.size() == 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -50,6 +50,10 @@ public:
|
||||||
virtual void Configure();
|
virtual void Configure();
|
||||||
virtual void Generate();
|
virtual void Generate();
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
// Utility target fix is not needed for VS8.
|
||||||
|
virtual void FixUtilityDepends() {}
|
||||||
|
|
||||||
static cmVS7FlagTable const* GetExtraFlagTableVS8();
|
static cmVS7FlagTable const* GetExtraFlagTableVS8();
|
||||||
virtual void AddPlatformDefinitions(cmMakefile* mf);
|
virtual void AddPlatformDefinitions(cmMakefile* mf);
|
||||||
virtual void WriteSLNFile(std::ostream& fout, cmLocalGenerator* root,
|
virtual void WriteSLNFile(std::ostream& fout, cmLocalGenerator* root,
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
=========================================================================*/
|
=========================================================================*/
|
||||||
#include "cmGlobalVisualStudioGenerator.h"
|
#include "cmGlobalVisualStudioGenerator.h"
|
||||||
|
|
||||||
|
#include "cmLocalGenerator.h"
|
||||||
|
#include "cmMakefile.h"
|
||||||
|
#include "cmTarget.h"
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator()
|
cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator()
|
||||||
{
|
{
|
||||||
|
@ -25,3 +29,167 @@ cmGlobalVisualStudioGenerator::cmGlobalVisualStudioGenerator()
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,15 @@ class cmGlobalVisualStudioGenerator : public cmGlobalGenerator
|
||||||
public:
|
public:
|
||||||
cmGlobalVisualStudioGenerator();
|
cmGlobalVisualStudioGenerator();
|
||||||
virtual ~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
|
#endif
|
||||||
|
|
|
@ -1,3 +1,20 @@
|
||||||
|
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
|
||||||
ADD_LIBRARY( Two TwoSrc.c )
|
ADD_LIBRARY( Two TwoSrc.c )
|
||||||
TARGET_LINK_LIBRARIES( Two Three )
|
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)
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
void ThreeFunction();
|
#include <two-test.h>
|
||||||
|
|
||||||
void TwoFunction()
|
void TwoFunction()
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
extern void ThreeFunction();
|
Loading…
Reference in New Issue