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->AlreadyInCacheWithoutMetaInfo = false;
this->NamesPerDir = false;
this->NamesPerDirAllowed = false;
}
//----------------------------------------------------------------------------
@ -213,6 +215,19 @@ bool cmFindBase::ParseArguments(std::vector<std::string> const& argsIn)
compatibility = false;
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")
{
doing = DoingNone;

View File

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

View File

@ -17,6 +17,7 @@
cmFindLibraryCommand::cmFindLibraryCommand()
{
this->EnvironmentPath = "LIB";
this->NamesPerDirAllowed = true;
}
//----------------------------------------------------------------------------
@ -44,6 +45,9 @@ void cmFindLibraryCommand::GenerateDocumentation()
"SEARCH_XXX", "library");
cmSystemTools::ReplaceString(this->GenericDocumentation,
"XXX_SUBDIR", "lib");
cmSystemTools::ReplaceString(this->GenericDocumentation,
"NAMES name1 [name2 ...]",
"NAMES name1 [name2 ...] [NAMES_PER_DIR]");
cmSystemTools::ReplaceString(
this->GenericDocumentation,
"XXX_EXTRA_PREFIX_ENTRY",
@ -52,6 +56,12 @@ void cmFindLibraryCommand::GenerateDocumentation()
"CMAKE_FIND_ROOT_PATH_MODE_XXX",
"CMAKE_FIND_ROOT_PATH_MODE_LIBRARY");
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"
"If the library found is a framework, then VAR will be set to "
"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.
typedef std::vector<std::string>::size_type size_type;
std::string BestPath;
size_type BestPrefix;
size_type BestSuffix;
// Support for OpenBSD shared library naming: lib<name>.so.<major>.<minor>
bool OpenBSD;
unsigned int BestMajor;
unsigned int BestMinor;
// Current name under consideration.
cmsys::RegularExpression NameRegex;
bool TryRawName;
std::string RawName;
// Current names under consideration.
struct Name
{
bool TryRaw;
std::string Raw;
cmsys::RegularExpression Regex;
Name(): TryRaw(false) {}
};
std::vector<Name> Names;
// Current full path under consideration.
std::string TestPath;
@ -249,8 +260,9 @@ struct cmFindLibraryHelper
suffix) - this->Suffixes.begin();
}
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 CheckDirectoryForName(std::string const& path, Name& name);
};
//----------------------------------------------------------------------------
@ -273,14 +285,6 @@ cmFindLibraryHelper::cmFindLibraryHelper(cmMakefile* mf):
this->OpenBSD =
this->Makefile->GetCMakeInstance()
->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.
this->TryRawName = this->HasValidSuffix(name);
this->RawName = name;
entry.TryRaw = this->HasValidSuffix(name);
entry.Raw = name;
// Build a regular expression to match library names.
std::string regex = "^";
@ -369,21 +375,37 @@ void cmFindLibraryHelper::SetName(std::string const& name)
regex += "(\\.[0-9]+\\.[0-9]+)?";
}
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)
{
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
// the suffixes, try it first. This allows users to search
// specifically for a static library on some platforms (on MS tools
// one cannot tell just from the library name whether it is a static
// library or an import library).
if(this->TryRawName)
if(name.TryRaw)
{
this->TestPath = path;
this->TestPath += this->RawName;
this->TestPath += name.Raw;
if(cmSystemTools::FileExists(this->TestPath.c_str(), true))
{
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.
std::string dir = path;
cmSystemTools::ConvertToUnixSlashes(dir);
@ -406,7 +434,7 @@ bool cmFindLibraryHelper::CheckDirectory(std::string const& path)
#else
std::string const& testName = origName;
#endif
if(this->NameRegex.find(testName))
if(name.Regex.find(testName))
{
this->TestPath = path;
this->TestPath += origName;
@ -416,25 +444,25 @@ bool cmFindLibraryHelper::CheckDirectory(std::string const& path)
// best name found so far. Earlier prefixes are preferred,
// followed by earlier suffixes. For OpenBSD, shared library
// version extensions are compared.
size_type prefix = this->GetPrefixIndex(this->NameRegex.match(1));
size_type suffix = this->GetSuffixIndex(this->NameRegex.match(2));
size_type prefix = this->GetPrefixIndex(name.Regex.match(1));
size_type suffix = this->GetSuffixIndex(name.Regex.match(2));
unsigned int major = 0;
unsigned int minor = 0;
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 ||
(prefix == this->BestPrefix && suffix < this->BestSuffix) ||
(prefix == this->BestPrefix && suffix == this->BestSuffix &&
(major > this->BestMajor ||
(major == this->BestMajor && minor > this->BestMinor))))
if(this->BestPath.empty() || prefix < bestPrefix ||
(prefix == bestPrefix && suffix < bestSuffix) ||
(prefix == bestPrefix && suffix == bestSuffix &&
(major > bestMajor ||
(major == bestMajor && minor > bestMinor))))
{
this->BestPath = this->TestPath;
this->BestPrefix = prefix;
this->BestSuffix = suffix;
this->BestMajor = major;
this->BestMinor = minor;
bestPrefix = prefix;
bestSuffix = suffix;
bestMajor = major;
bestMinor = minor;
}
}
}
@ -446,6 +474,42 @@ bool cmFindLibraryHelper::CheckDirectory(std::string const& path)
//----------------------------------------------------------------------------
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.
cmFindLibraryHelper helper(this->Makefile);
@ -454,7 +518,7 @@ std::string cmFindLibraryCommand::FindNormalLibrary()
{
// Switch to searching for this name.
std::string const& name = *ni;
helper.SetName(name);
helper.AddName(name);
// Search every directory.
for(std::vector<std::string>::const_iterator
@ -474,19 +538,60 @@ std::string cmFindLibraryCommand::FindNormalLibrary()
//----------------------------------------------------------------------------
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();
ni != this->Names.end() ; ++ni)
{
// Search the paths for a framework with this name.
std::string fwName = *ni;
fwName += ".framework";
std::string fwPath = cmSystemTools::FindDirectory(fwName.c_str(),
this->SearchPaths,
true);
if(!fwPath.empty())
fwPath = *di;
fwPath += *ni;
fwPath += ".framework";
if(cmSystemTools::FileIsDirectory(fwPath.c_str()))
{
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();
private:
std::string FindNormalLibrary();
std::string FindNormalLibraryNamesPerDir();
std::string FindNormalLibraryDirsPerName();
std::string FindFrameworkLibrary();
std::string FindFrameworkLibraryNamesPerDir();
std::string FindFrameworkLibraryDirsPerName();
};

View File

@ -3,34 +3,34 @@ project(FindLibraryTest NONE)
set(CMAKE_FIND_DEBUG_MODE 1)
macro(test_find_library expected)
get_filename_component(dir ${expected} PATH)
get_filename_component(name ${expected} NAME)
string(REGEX REPLACE "lib/?64" "lib" dir "${dir}")
macro(test_find_library desc expected)
unset(LIB CACHE)
find_library(LIB
NAMES ${name}
PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${dir}
NO_DEFAULT_PATH
)
find_library(LIB ${ARGN} NO_DEFAULT_PATH)
if(LIB)
# Convert to relative path for comparison to expected location.
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.
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()
else()
message(SEND_ERROR "Library ${expected} searched as ${dir}, NOT FOUND!")
message(SEND_ERROR "Library ${expected} NOT FOUND${desc}")
endif()
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_SUFFIXES ".a")
set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS TRUE)
@ -44,7 +44,7 @@ foreach(lib
lib/libtest3.a
lib/libtest3.a
)
test_find_library(${lib})
test_find_library_subst(${lib})
endforeach()
set(CMAKE_SIZEOF_VOID_P 8)
@ -57,5 +57,18 @@ foreach(lib64
lib64/A/libtest1.a
lib64/libtest1.a
)
test_find_library(${lib64})
test_find_library_subst(${lib64})
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
)