Merge topic 'find_library-NAMES_PER_DIR'

66759ee find_library: Optionally consider all names in each directory
9cb68b1 find_library: Generalize helper macro in test case
b64dd76 find_library: Simplify framework search logic
531c71b find_library: Refactor internal name iteration
This commit is contained in:
David Cole 2012-10-31 16:32:41 -04:00 committed by CMake Topic Stage
commit 6df05b93b1
7 changed files with 205 additions and 66 deletions

View File

@ -15,6 +15,8 @@ cmFindBase::cmFindBase()
{ {
this->AlreadyInCache = false; this->AlreadyInCache = false;
this->AlreadyInCacheWithoutMetaInfo = false; this->AlreadyInCacheWithoutMetaInfo = false;
this->NamesPerDir = false;
this->NamesPerDirAllowed = false;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -213,6 +215,19 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
compatibility = false; compatibility = false;
newStyle = true; newStyle = true;
} }
else if (args[j] == "NAMES_PER_DIR")
{
doing = DoingNone;
if(this->NamesPerDirAllowed)
{
this->NamesPerDir = true;
}
else
{
this->SetError("does not support NAMES_PER_DIR");
return false;
}
}
else if (args[j] == "NO_SYSTEM_PATH") else if (args[j] == "NO_SYSTEM_PATH")
{ {
doing = DoingNone; doing = DoingNone;

View File

@ -49,6 +49,8 @@ protected:
cmStdString VariableDocumentation; cmStdString VariableDocumentation;
cmStdString VariableName; cmStdString VariableName;
std::vector<std::string> Names; std::vector<std::string> Names;
bool NamesPerDir;
bool NamesPerDirAllowed;
// CMAKE_*_PATH CMAKE_SYSTEM_*_PATH FRAMEWORK|LIBRARY|INCLUDE|PROGRAM // CMAKE_*_PATH CMAKE_SYSTEM_*_PATH FRAMEWORK|LIBRARY|INCLUDE|PROGRAM
cmStdString EnvironmentPath; // LIB,INCLUDE cmStdString EnvironmentPath; // LIB,INCLUDE

View File

@ -17,6 +17,7 @@
cmFindLibraryCommand::cmFindLibraryCommand() cmFindLibraryCommand::cmFindLibraryCommand()
{ {
this->EnvironmentPath = "LIB"; this->EnvironmentPath = "LIB";
this->NamesPerDirAllowed = true;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -44,6 +45,9 @@ void cmFindLibraryCommand::GenerateDocumentation()
"SEARCH_XXX", "library"); "SEARCH_XXX", "library");
cmSystemTools::ReplaceString(this->GenericDocumentation, cmSystemTools::ReplaceString(this->GenericDocumentation,
"XXX_SUBDIR", "lib"); "XXX_SUBDIR", "lib");
cmSystemTools::ReplaceString(this->GenericDocumentation,
"NAMES name1 [name2 ...]",
"NAMES name1 [name2 ...] [NAMES_PER_DIR]");
cmSystemTools::ReplaceString( cmSystemTools::ReplaceString(
this->GenericDocumentation, this->GenericDocumentation,
"XXX_EXTRA_PREFIX_ENTRY", "XXX_EXTRA_PREFIX_ENTRY",
@ -52,6 +56,12 @@ void cmFindLibraryCommand::GenerateDocumentation()
"CMAKE_FIND_ROOT_PATH_MODE_XXX", "CMAKE_FIND_ROOT_PATH_MODE_XXX",
"CMAKE_FIND_ROOT_PATH_MODE_LIBRARY"); "CMAKE_FIND_ROOT_PATH_MODE_LIBRARY");
this->GenericDocumentation += this->GenericDocumentation +=
"\n"
"When more than one value is given to the NAMES option this command "
"by default will consider one name at a time and search every directory "
"for it. "
"The NAMES_PER_DIR option tells this command to consider one directory "
"at a time and search for all names in it."
"\n" "\n"
"If the library found is a framework, then VAR will be set to " "If the library found is a framework, then VAR will be set to "
"the full path to the framework <fullPath>/A.framework. " "the full path to the framework <fullPath>/A.framework. "
@ -220,18 +230,19 @@ struct cmFindLibraryHelper
// Keep track of the best library file found so far. // Keep track of the best library file found so far.
typedef std::vector<std::string>::size_type size_type; typedef std::vector<std::string>::size_type size_type;
std::string BestPath; std::string BestPath;
size_type BestPrefix;
size_type BestSuffix;
// Support for OpenBSD shared library naming: lib<name>.so.<major>.<minor> // Support for OpenBSD shared library naming: lib<name>.so.<major>.<minor>
bool OpenBSD; bool OpenBSD;
unsigned int BestMajor;
unsigned int BestMinor;
// Current name under consideration. // Current names under consideration.
cmsys::RegularExpression NameRegex; struct Name
bool TryRawName; {
std::string RawName; bool TryRaw;
std::string Raw;
cmsys::RegularExpression Regex;
Name(): TryRaw(false) {}
};
std::vector<Name> Names;
// Current full path under consideration. // Current full path under consideration.
std::string TestPath; std::string TestPath;
@ -249,8 +260,9 @@ struct cmFindLibraryHelper
suffix) - this->Suffixes.begin(); suffix) - this->Suffixes.begin();
} }
bool HasValidSuffix(std::string const& name); bool HasValidSuffix(std::string const& name);
void SetName(std::string const& name); void AddName(std::string const& name);
bool CheckDirectory(std::string const& path); bool CheckDirectory(std::string const& path);
bool CheckDirectoryForName(std::string const& path, Name& name);
}; };
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -273,14 +285,6 @@ cmFindLibraryHelper::cmFindLibraryHelper(cmMakefile* mf):
this->OpenBSD = this->OpenBSD =
this->Makefile->GetCMakeInstance() this->Makefile->GetCMakeInstance()
->GetPropertyAsBool("FIND_LIBRARY_USE_OPENBSD_VERSIONING"); ->GetPropertyAsBool("FIND_LIBRARY_USE_OPENBSD_VERSIONING");
this->TryRawName = false;
// No library file has yet been found.
this->BestPrefix = this->Prefixes.size();
this->BestSuffix = this->Suffixes.size();
this->BestMajor = 0;
this->BestMinor = 0;
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -353,11 +357,13 @@ bool cmFindLibraryHelper::HasValidSuffix(std::string const& name)
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void cmFindLibraryHelper::SetName(std::string const& name) void cmFindLibraryHelper::AddName(std::string const& name)
{ {
Name entry;
// Consider checking the raw name too. // Consider checking the raw name too.
this->TryRawName = this->HasValidSuffix(name); entry.TryRaw = this->HasValidSuffix(name);
this->RawName = name; entry.Raw = name;
// Build a regular expression to match library names. // Build a regular expression to match library names.
std::string regex = "^"; std::string regex = "^";
@ -369,21 +375,37 @@ void cmFindLibraryHelper::SetName(std::string const& name)
regex += "(\\.[0-9]+\\.[0-9]+)?"; regex += "(\\.[0-9]+\\.[0-9]+)?";
} }
regex += "$"; regex += "$";
this->NameRegex.compile(regex.c_str()); entry.Regex.compile(regex.c_str());
this->Names.push_back(entry);
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
bool cmFindLibraryHelper::CheckDirectory(std::string const& path) bool cmFindLibraryHelper::CheckDirectory(std::string const& path)
{
for(std::vector<Name>::iterator i = this->Names.begin();
i != this->Names.end(); ++i)
{
if(this->CheckDirectoryForName(path, *i))
{
return true;
}
}
return false;
}
//----------------------------------------------------------------------------
bool cmFindLibraryHelper::CheckDirectoryForName(std::string const& path,
Name& name)
{ {
// If the original library name provided by the user matches one of // If the original library name provided by the user matches one of
// the suffixes, try it first. This allows users to search // the suffixes, try it first. This allows users to search
// specifically for a static library on some platforms (on MS tools // specifically for a static library on some platforms (on MS tools
// one cannot tell just from the library name whether it is a static // one cannot tell just from the library name whether it is a static
// library or an import library). // library or an import library).
if(this->TryRawName) if(name.TryRaw)
{ {
this->TestPath = path; this->TestPath = path;
this->TestPath += this->RawName; this->TestPath += name.Raw;
if(cmSystemTools::FileExists(this->TestPath.c_str(), true)) if(cmSystemTools::FileExists(this->TestPath.c_str(), true))
{ {
this->BestPath = this->BestPath =
@ -393,6 +415,12 @@ bool cmFindLibraryHelper::CheckDirectory(std::string const& path)
} }
} }
// No library file has yet been found.
size_type bestPrefix = this->Prefixes.size();
size_type bestSuffix = this->Suffixes.size();
unsigned int bestMajor = 0;
unsigned int bestMinor = 0;
// Search for a file matching the library name regex. // Search for a file matching the library name regex.
std::string dir = path; std::string dir = path;
cmSystemTools::ConvertToUnixSlashes(dir); cmSystemTools::ConvertToUnixSlashes(dir);
@ -406,7 +434,7 @@ bool cmFindLibraryHelper::CheckDirectory(std::string const& path)
#else #else
std::string const& testName = origName; std::string const& testName = origName;
#endif #endif
if(this->NameRegex.find(testName)) if(name.Regex.find(testName))
{ {
this->TestPath = path; this->TestPath = path;
this->TestPath += origName; this->TestPath += origName;
@ -416,25 +444,25 @@ bool cmFindLibraryHelper::CheckDirectory(std::string const& path)
// best name found so far. Earlier prefixes are preferred, // best name found so far. Earlier prefixes are preferred,
// followed by earlier suffixes. For OpenBSD, shared library // followed by earlier suffixes. For OpenBSD, shared library
// version extensions are compared. // version extensions are compared.
size_type prefix = this->GetPrefixIndex(this->NameRegex.match(1)); size_type prefix = this->GetPrefixIndex(name.Regex.match(1));
size_type suffix = this->GetSuffixIndex(this->NameRegex.match(2)); size_type suffix = this->GetSuffixIndex(name.Regex.match(2));
unsigned int major = 0; unsigned int major = 0;
unsigned int minor = 0; unsigned int minor = 0;
if(this->OpenBSD) if(this->OpenBSD)
{ {
sscanf(this->NameRegex.match(3).c_str(), ".%u.%u", &major, &minor); sscanf(name.Regex.match(3).c_str(), ".%u.%u", &major, &minor);
} }
if(this->BestPath.empty() || prefix < this->BestPrefix || if(this->BestPath.empty() || prefix < bestPrefix ||
(prefix == this->BestPrefix && suffix < this->BestSuffix) || (prefix == bestPrefix && suffix < bestSuffix) ||
(prefix == this->BestPrefix && suffix == this->BestSuffix && (prefix == bestPrefix && suffix == bestSuffix &&
(major > this->BestMajor || (major > bestMajor ||
(major == this->BestMajor && minor > this->BestMinor)))) (major == bestMajor && minor > bestMinor))))
{ {
this->BestPath = this->TestPath; this->BestPath = this->TestPath;
this->BestPrefix = prefix; bestPrefix = prefix;
this->BestSuffix = suffix; bestSuffix = suffix;
this->BestMajor = major; bestMajor = major;
this->BestMinor = minor; bestMinor = minor;
} }
} }
} }
@ -446,6 +474,42 @@ bool cmFindLibraryHelper::CheckDirectory(std::string const& path)
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
std::string cmFindLibraryCommand::FindNormalLibrary() std::string cmFindLibraryCommand::FindNormalLibrary()
{
if(this->NamesPerDir)
{
return this->FindNormalLibraryNamesPerDir();
}
else
{
return this->FindNormalLibraryDirsPerName();
}
}
//----------------------------------------------------------------------------
std::string cmFindLibraryCommand::FindNormalLibraryNamesPerDir()
{
// Search for all names in each directory.
cmFindLibraryHelper helper(this->Makefile);
for(std::vector<std::string>::const_iterator ni = this->Names.begin();
ni != this->Names.end() ; ++ni)
{
helper.AddName(*ni);
}
// Search every directory.
for(std::vector<std::string>::const_iterator
p = this->SearchPaths.begin(); p != this->SearchPaths.end(); ++p)
{
if(helper.CheckDirectory(*p))
{
return helper.BestPath;
}
}
// Couldn't find the library.
return "";
}
//----------------------------------------------------------------------------
std::string cmFindLibraryCommand::FindNormalLibraryDirsPerName()
{ {
// Search the entire path for each name. // Search the entire path for each name.
cmFindLibraryHelper helper(this->Makefile); cmFindLibraryHelper helper(this->Makefile);
@ -454,7 +518,7 @@ std::string cmFindLibraryCommand::FindNormalLibrary()
{ {
// Switch to searching for this name. // Switch to searching for this name.
std::string const& name = *ni; std::string const& name = *ni;
helper.SetName(name); helper.AddName(name);
// Search every directory. // Search every directory.
for(std::vector<std::string>::const_iterator for(std::vector<std::string>::const_iterator
@ -474,19 +538,60 @@ std::string cmFindLibraryCommand::FindNormalLibrary()
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
std::string cmFindLibraryCommand::FindFrameworkLibrary() std::string cmFindLibraryCommand::FindFrameworkLibrary()
{ {
// Search for a framework of each name in the entire search path. if(this->NamesPerDir)
{
return this->FindFrameworkLibraryNamesPerDir();
}
else
{
return this->FindFrameworkLibraryDirsPerName();
}
}
//----------------------------------------------------------------------------
std::string cmFindLibraryCommand::FindFrameworkLibraryNamesPerDir()
{
std::string fwPath;
// Search for all names in each search path.
for(std::vector<std::string>::const_iterator di = this->SearchPaths.begin();
di != this->SearchPaths.end(); ++di)
{
for(std::vector<std::string>::const_iterator ni = this->Names.begin(); for(std::vector<std::string>::const_iterator ni = this->Names.begin();
ni != this->Names.end() ; ++ni) ni != this->Names.end() ; ++ni)
{ {
// Search the paths for a framework with this name. fwPath = *di;
std::string fwName = *ni; fwPath += *ni;
fwName += ".framework"; fwPath += ".framework";
std::string fwPath = cmSystemTools::FindDirectory(fwName.c_str(), if(cmSystemTools::FileIsDirectory(fwPath.c_str()))
this->SearchPaths,
true);
if(!fwPath.empty())
{ {
return fwPath; return cmSystemTools::CollapseFullPath(fwPath.c_str());
}
}
}
// No framework found.
return "";
}
//----------------------------------------------------------------------------
std::string cmFindLibraryCommand::FindFrameworkLibraryDirsPerName()
{
std::string fwPath;
// Search for each name in all search paths.
for(std::vector<std::string>::const_iterator ni = this->Names.begin();
ni != this->Names.end() ; ++ni)
{
for(std::vector<std::string>::const_iterator
di = this->SearchPaths.begin();
di != this->SearchPaths.end(); ++di)
{
fwPath = *di;
fwPath += *ni;
fwPath += ".framework";
if(cmSystemTools::FileIsDirectory(fwPath.c_str()))
{
return cmSystemTools::CollapseFullPath(fwPath.c_str());
}
} }
} }

View File

@ -70,7 +70,11 @@ protected:
virtual void GenerateDocumentation(); virtual void GenerateDocumentation();
private: private:
std::string FindNormalLibrary(); std::string FindNormalLibrary();
std::string FindNormalLibraryNamesPerDir();
std::string FindNormalLibraryDirsPerName();
std::string FindFrameworkLibrary(); std::string FindFrameworkLibrary();
std::string FindFrameworkLibraryNamesPerDir();
std::string FindFrameworkLibraryDirsPerName();
}; };

View File

@ -3,34 +3,34 @@ project(FindLibraryTest NONE)
set(CMAKE_FIND_DEBUG_MODE 1) set(CMAKE_FIND_DEBUG_MODE 1)
macro(test_find_library expected) macro(test_find_library desc expected)
get_filename_component(dir ${expected} PATH)
get_filename_component(name ${expected} NAME)
string(REGEX REPLACE "lib/?64" "lib" dir "${dir}")
unset(LIB CACHE) unset(LIB CACHE)
find_library(LIB find_library(LIB ${ARGN} NO_DEFAULT_PATH)
NAMES ${name}
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${dir}
NO_DEFAULT_PATH
)
if(LIB) if(LIB)
# Convert to relative path for comparison to expected location. # Convert to relative path for comparison to expected location.
file(RELATIVE_PATH REL_LIB "${CMAKE_CURRENT_SOURCE_DIR}" "${LIB}") file(RELATIVE_PATH REL_LIB "${CMAKE_CURRENT_SOURCE_DIR}" "${LIB}")
# Debugging output.
if(CMAKE_FIND_DEBUG_MODE)
message(STATUS "Library ${expected} searched as ${dir}, found as [${REL_LIB}].")
endif()
# Check and report failure. # Check and report failure.
if(NOT "${REL_LIB}" STREQUAL "${expected}") if(NOT "${REL_LIB}" STREQUAL "${expected}")
message(SEND_ERROR "Library ${l} should have been [${expected}] but was [${REL_LIB}]") message(SEND_ERROR "Library ${expected} found as [${REL_LIB}]${desc}")
elseif(CMAKE_FIND_DEBUG_MODE)
message(STATUS "Library ${expected} found as [${REL_LIB}]${desc}")
endif() endif()
else() else()
message(SEND_ERROR "Library ${expected} searched as ${dir}, NOT FOUND!") message(SEND_ERROR "Library ${expected} NOT FOUND${desc}")
endif() endif()
endmacro() endmacro()
macro(test_find_library_subst expected)
get_filename_component(dir ${expected} PATH)
get_filename_component(name ${expected} NAME)
string(REGEX REPLACE "lib/?64" "lib" dir "${dir}")
test_find_library(", searched as ${dir}" "${expected}"
NAMES ${name}
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${dir}
)
endmacro()
set(CMAKE_FIND_LIBRARY_PREFIXES "lib") set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS TRUE) set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS TRUE)
@ -44,7 +44,7 @@ foreach(lib
lib/libtest3.a lib/libtest3.a
lib/libtest3.a lib/libtest3.a
) )
test_find_library(${lib}) test_find_library_subst(${lib})
endforeach() endforeach()
set(CMAKE_SIZEOF_VOID_P 8) set(CMAKE_SIZEOF_VOID_P 8)
@ -57,5 +57,18 @@ foreach(lib64
lib64/A/libtest1.a lib64/A/libtest1.a
lib64/libtest1.a lib64/libtest1.a
) )
test_find_library(${lib64}) test_find_library_subst(${lib64})
endforeach() endforeach()
test_find_library("" A/libtestA.a
NAMES testA testB
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/A ${CMAKE_CURRENT_SOURCE_DIR}/B
)
test_find_library("" B/libtestB.a
NAMES testB testA
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/A ${CMAKE_CURRENT_SOURCE_DIR}/B
)
test_find_library("" A/libtestA.a
NAMES testB testA NAMES_PER_DIR
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/A ${CMAKE_CURRENT_SOURCE_DIR}/B
)