ENH: Support full-path libs w/out valid names.

This change introduces policy CMP0008 to decide how to treat full path
libraries that do not appear to be valid library file names.  Such
libraries worked by accident in the VS IDE and Xcode generators with
CMake 2.4 and below.  We support them in CMake 2.6 by introducing this
policy.  See policy documentation added by this change for details.
This commit is contained in:
Brad King 2008-07-23 12:59:14 -04:00
parent 74d6536024
commit b93f0318fe
6 changed files with 104 additions and 40 deletions

View File

@ -1042,6 +1042,20 @@ void cmComputeLinkInformation::AddFullItem(std::string const& item)
return;
}
// Full path libraries should specify a valid library file name.
// See documentation of CMP0008.
if(this->Target->GetPolicyStatusCMP0008() != cmPolicies::NEW &&
(strstr(this->GlobalGenerator->GetName(), "Visual Studio") ||
strstr(this->GlobalGenerator->GetName(), "Xcode")))
{
std::string file = cmSystemTools::GetFilenameName(item);
if(!this->ExtractAnyLibraryName.find(file.c_str()))
{
this->HandleBadFullItem(item, file);
return;
}
}
// This is called to handle a link item that is a full path.
// If the target is not a static library make sure the link type is
// shared. This is because dynamic-mode linking can handle both
@ -1078,47 +1092,8 @@ void cmComputeLinkInformation::AddFullItem(std::string const& item)
this->Items.push_back(Item(this->LibLinkFileFlag, false));
}
// Full path libraries should have an extension. CMake 2.4 would
// add the extension after splitting the file off of the directory.
// Some existing projects depended on this to build correctly
// because they left off the extension of an otherwise full-path
// library. This worked with CMake 2.4 but only for VS IDE builds
// because the file-level dependency added to the Makefile would not
// be found. Nevertheless, some projects have this mistake but work
// because they build only with the VS IDE. We need to support them
// here by adding the missing extension.
std::string final_item = item;
if(strstr(this->GlobalGenerator->GetName(), "Visual Studio") &&
this->Makefile->NeedBackwardsCompatibility(2,4) &&
!cmSystemTools::ComparePath(
cmSystemTools::GetFilenameLastExtension(item).c_str(),
this->LibLinkSuffix.c_str()))
{
// Issue the warning at most once.
std::string wid = "VSIDE-LINK-EXT-";
wid += item;
if(!this->Target->GetPropertyAsBool(wid.c_str()))
{
this->Target->SetProperty(wid.c_str(), "1");
cmOStringStream w;
w << "Target \"" << this->Target->GetName() << "\" links to "
<< "full-path item\n"
<< " " << item << "\n"
<< "which does not have the proper link extension \""
<< this->LibLinkSuffix << "\". "
<< "CMake is adding the missing extension because compatibility "
<< "with CMake 2.4 is currently enabled and this case worked "
<< "accidentally in that version. "
<< "The link extension should be added by the project developer.";
this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str());
}
// Add the missing extension.
final_item += this->LibLinkSuffix;
}
// Now add the full path to the library.
this->Items.push_back(Item(final_item, true));
this->Items.push_back(Item(item, true));
}
//----------------------------------------------------------------------------
@ -1383,6 +1358,59 @@ void cmComputeLinkInformation::AddSharedLibNoSOName(std::string const& item)
this->OrderLinkerSearchPath->AddLinkLibrary(item);
}
//----------------------------------------------------------------------------
void cmComputeLinkInformation::HandleBadFullItem(std::string const& item,
std::string const& file)
{
// Tell the linker to search for the item and provide the proper
// path for it. Do not contribute to any CMP0003 warning (do not
// put in OldLinkDirItems or OldUserFlagItems).
this->AddUserItem(file, false);
this->OrderLinkerSearchPath->AddLinkLibrary(item);
// Produce any needed message.
switch(this->Target->GetPolicyStatusCMP0008())
{
case cmPolicies::WARN:
{
// Print the warning at most once for this item.
std::string wid = "CMP0008-WARNING-GIVEN-";
wid += item;
if(!this->CMakeInstance->GetPropertyAsBool(wid.c_str()))
{
this->CMakeInstance->SetProperty(wid.c_str(), "1");
cmOStringStream w;
w << (this->Makefile->GetPolicies()
->GetPolicyWarning(cmPolicies::CMP0008)) << "\n"
<< "Target \"" << this->Target->GetName() << "\" links to item\n"
<< " " << item << "\n"
<< "which is a full-path but not a valid library file name.";
this->CMakeInstance->IssueMessage(cmake::AUTHOR_WARNING, w.str(),
this->Target->GetBacktrace());
}
}
case cmPolicies::OLD:
// OLD behavior does not warn.
break;
case cmPolicies::NEW:
// NEW behavior will not get here.
break;
case cmPolicies::REQUIRED_IF_USED:
case cmPolicies::REQUIRED_ALWAYS:
{
cmOStringStream e;
e << (this->Makefile->GetPolicies()->
GetRequiredPolicyError(cmPolicies::CMP0008)) << "\n"
<< "Target \"" << this->Target->GetName() << "\" links to item\n"
<< " " << item << "\n"
<< "which is a full-path but not a valid library file name.";
this->CMakeInstance->IssueMessage(cmake::FATAL_ERROR, e.str(),
this->Target->GetBacktrace());
}
break;
}
}
//----------------------------------------------------------------------------
bool cmComputeLinkInformation::FinishLinkerSearchDirectories()
{

View File

@ -145,6 +145,7 @@ private:
void DropDirectoryItem(std::string const& item);
bool CheckSharedLibNoSOName(std::string const& item);
void AddSharedLibNoSOName(std::string const& item);
void HandleBadFullItem(std::string const& item, std::string const& file);
// Framework info.
void ComputeFrameworkInfo();

View File

@ -281,6 +281,32 @@ cmPolicies::cmPolicies()
"The NEW behavior for this policy is to correctly count empty "
"elements in a list. ",
2,6,0, cmPolicies::WARN);
this->DefinePolicy(
CMP0008, "CMP0008",
"Libraries linked by full-path must have a valid library file name.",
"In CMake 2.4 and below it is possible to write code like\n"
" target_link_libraries(myexe /full/path/to/somelib)\n"
"where \"somelib\" is supposed to be a valid library file name "
"such as \"libsomelib.a\" or \"somelib.lib\". "
"For Makefile generators this produces an error at build time "
"because the dependency on the full path cannot be found. "
"For VS IDE and Xcode generators this used to work by accident because "
"CMake would always split off the library directory and ask the "
"linker to search for the library by name (-lsomelib or somelib.lib). "
"Despite the failure with Makefiles, some projects have code like this "
"and build only with VS and/or Xcode. "
"This version of CMake prefers to pass the full path directly to the "
"native build tool, which will fail in this case because it does "
"not name a valid library file."
"\n"
"This policy determines what to do with full paths that do not appear "
"to name a valid library file. "
"The OLD behavior for this policy is to split the library name from the "
"path and ask the linker to search for it. "
"The NEW behavior for this policy is to trust the given path and "
"pass it directly to the native build tool unchanged.",
2,6,1, cmPolicies::WARN);
}
cmPolicies::~cmPolicies()

View File

@ -48,6 +48,7 @@ public:
CMP0005, // Definition value escaping
CMP0006, // BUNDLE install rules needed for MACOSX_BUNDLE targets
CMP0007, // list command handling of empty elements
CMP0008, // Full-path libraries must be a valid library file name
// Always the last entry. Useful mostly to avoid adding a comma
// the last policy when adding a new one.

View File

@ -55,6 +55,7 @@ cmTarget::cmTarget()
this->Makefile = 0;
this->PolicyStatusCMP0003 = cmPolicies::WARN;
this->PolicyStatusCMP0004 = cmPolicies::WARN;
this->PolicyStatusCMP0008 = cmPolicies::WARN;
this->LinkLibrariesAnalyzed = false;
this->HaveInstallRule = false;
this->DLLPlatform = false;
@ -768,6 +769,8 @@ void cmTarget::SetMakefile(cmMakefile* mf)
this->Makefile->GetPolicyStatus(cmPolicies::CMP0003);
this->PolicyStatusCMP0004 =
this->Makefile->GetPolicyStatus(cmPolicies::CMP0004);
this->PolicyStatusCMP0008 =
this->Makefile->GetPolicyStatus(cmPolicies::CMP0008);
}
//----------------------------------------------------------------------------

View File

@ -114,6 +114,10 @@ public:
cmPolicies::PolicyStatus GetPolicyStatusCMP0004() const
{ return this->PolicyStatusCMP0004; }
/** Get the status of policy CMP0008 when the target was created. */
cmPolicies::PolicyStatus GetPolicyStatusCMP0008() const
{ return this->PolicyStatusCMP0008; }
/**
* Get the list of the custom commands for this target
*/
@ -552,6 +556,7 @@ private:
// Policy status recorded when target was created.
cmPolicies::PolicyStatus PolicyStatusCMP0003;
cmPolicies::PolicyStatus PolicyStatusCMP0004;
cmPolicies::PolicyStatus PolicyStatusCMP0008;
// Internal representation details.
friend class cmTargetInternals;