ENH: Implement version support in the find_package command module mode. Version numbers provided to the command are converted to variable settings to tell the FindXXX.cmake module what version is requested. This addresses issue #1645.

This commit is contained in:
Brad King 2008-01-21 08:48:33 -05:00
parent 9198a92af9
commit f41b1e8e91
7 changed files with 124 additions and 5 deletions

View File

@ -18,6 +18,10 @@ XXX_FOUND Set to false, or undefined, if we haven't found, or don'
XXX_RUNTIME_LIBRARY_DIRS Optionally, the runtime library search path for use when running an executable linked to shared libraries.
The list should be used by user code to create the PATH on windows or LD_LIBRARY_PATH on unix.
This should not be a cache entry.
XXX_VERSION_STRING A human-readable string containing the version of the package found, if any.
XXX_VERSION_MAJOR The major version of the package found, if any.
XXX_VERSION_MINOR The minor version of the package found, if any.
XXX_VERSION_PATCH The patch version of the package found, if any.
You do not have to provide all of the above variables. You should provide XXX_FOUND under most circumstances. If XXX is a library, then XXX_LIBRARIES, should also be defined, and XXX_INCLUDE_DIRS should usually be defined (I guess libm.a might be an exception)
@ -63,7 +67,19 @@ line.
A FindXXX.cmake module will typically be loaded by the command
FIND_PACKAGE(XXX [QUIET] [REQUIRED [components...]])
FIND_PACKAGE(XXX [major[.minor[.patch]]]
[QUIET] [REQUIRED [components...]])
If any version numbers are given to the command it will set the
variable XXX_FIND_VERSION to contain the whole version. The variables
XXX_FIND_VERSION_MAJOR, XXX_FIND_VERSION_MINOR, and
XXX_FIND_VERSION_PATCH will be set to contain the corresponding
portions of the version number. If the find module supports
versioning it should locate a version of the package that is
compatible with the version requested. If a compatible version of the
package cannot be found the module should not report success. The
version of the package found should be stored in the version variables
named above.
If the QUIET option is given to the command it will set the variable
XXX_FIND_QUIETLY to true before loading the FindXXX.cmake module. If

View File

@ -63,8 +63,12 @@ cmFindPackageCommand::cmFindPackageCommand()
this->NoBuilds = false;
this->NoModule = false;
this->DebugMode = false;
this->VersionMajor = 0;
this->VersionMinor = 0;
this->VersionPatch = 0;
this->VersionCount = 0;
this->CommandDocumentation =
" find_package(<package> [major.minor] [QUIET] [NO_MODULE]\n"
" find_package(<package> [major[.minor[.patch]]] [QUIET] [NO_MODULE]\n"
" [[REQUIRED|COMPONENTS] [components...]]\n"
" [NAMES name1 [name2 ...]]\n"
" [CONFIGS config1 [config2 ...]]\n"
@ -84,13 +88,15 @@ cmFindPackageCommand::cmFindPackageCommand()
"can be used when <package>_FOUND is true are package-specific. "
"A package-specific list of components may be listed after the "
"REQUIRED option, or after the COMPONENTS option if no REQUIRED "
"option is given. The \"major.minor\" version argument is currently "
"a placeholder for future use and is ignored. "
"option is given. The \"[major[.minor[.patch]]]\" version argument "
"specifies a desired version with which the package found should be "
"compatible. Version support is currently provided only on a "
"package-by-package basis and is not enforced by the command. "
"The command has two modes by which it searches for packages: "
"\"Module\" mode and \"Config\" mode."
"\n"
"Module mode has a reduced signature:\n"
" find_package(<package> [major.minor] [QUIET]\n"
" find_package(<package> [major[.minor[.patch]]] [QUIET]\n"
" [[REQUIRED|COMPONENTS] [components...]])\n"
"CMake searches for a file called \"Find<package>.cmake\" in "
"the CMAKE_MODULE_PATH followed by the CMake installation. "
@ -104,6 +110,7 @@ cmFindPackageCommand::cmFindPackageCommand()
"Config mode attempts to locate a configuration file provided by the "
"package to be found. A cache entry called <package>_DIR is created to "
"hold the directory containing the file. "
"Currently versioning is not implemented by Config mode. "
"By default the command searches for a package with the name <package>. "
"If the NAMES option is given the names following it are used instead "
"of <package>. "
@ -338,6 +345,7 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
else if(!haveVersion && version.find(args[i].c_str()))
{
haveVersion = true;
this->Version = args[i];
}
else
{
@ -348,6 +356,24 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args)
}
}
if(!this->Version.empty())
{
// Try to parse the version number and store the results that were
// successfully parsed.
unsigned int parsed_major;
unsigned int parsed_minor;
unsigned int parsed_patch;
this->VersionCount = sscanf(this->Version.c_str(), "%u.%u.%u",
&parsed_major, &parsed_minor, &parsed_patch);
switch(this->VersionCount)
{
case 3: this->VersionPatch = parsed_patch; // no break!
case 2: this->VersionMinor = parsed_minor; // no break!
case 1: this->VersionMajor = parsed_major; // no break!
default: break;
}
}
// Store the list of components.
std::string components_var = Name + "_FIND_COMPONENTS";
this->Makefile->AddDefinition(components_var.c_str(), components.c_str());
@ -428,6 +454,35 @@ bool cmFindPackageCommand::FindModule(bool& found)
this->Makefile->AddDefinition(req.c_str(), "1");
}
if(!this->Version.empty())
{
// Tell the module that is about to be read what version of the
// package has been requested.
std::string ver = this->Name;
ver += "_FIND_VERSION";
this->Makefile->AddDefinition(ver.c_str(), this->Version.c_str());
char buf[64];
switch(this->VersionCount)
{
case 3:
{
snprintf(buf, 64, "%u", this->VersionPatch);
this->Makefile->AddDefinition((ver+"_PATCH").c_str(), buf);
} // no break
case 2:
{
snprintf(buf, 64, "%u", this->VersionMinor);
this->Makefile->AddDefinition((ver+"_MINOR").c_str(), buf);
} // no break
case 1:
{
snprintf(buf, 64, "%u", this->VersionMajor);
this->Makefile->AddDefinition((ver+"_MAJOR").c_str(), buf);
} // no break
default: break;
}
}
// Load the module we found.
found = true;
return this->ReadListFile(mfile.c_str());

View File

@ -94,6 +94,11 @@ private:
std::string CommandDocumentation;
cmStdString Name;
cmStdString Variable;
cmStdString Version;
unsigned int VersionMajor;
unsigned int VersionMinor;
unsigned int VersionPatch;
unsigned int VersionCount;
cmStdString FileFound;
bool Quiet;
bool Required;

View File

@ -22,6 +22,13 @@ IF(NOT FOO_DIR)
CMAKE_PREFIX_PATH = ${CMAKE_PREFIX_PATH}")
ENDIF(NOT FOO_DIR)
LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
FIND_PACKAGE(VersionTestA 1)
FIND_PACKAGE(VersionTestB 1.2)
FIND_PACKAGE(VersionTestC 1.2.3)
#-----------------------------------------------------------------------------
#SET(CMAKE_FIND_DEBUG_MODE 1)
# For purposes of the test wipe out previous find results.

View File

@ -0,0 +1,12 @@
IF(NOT "${VersionTestA_FIND_VERSION}" STREQUAL "1")
MESSAGE(SEND_ERROR "VersionTestA_FIND_VERSION=${VersionTestA_FIND_VERSION} is not 1")
ENDIF(NOT "${VersionTestA_FIND_VERSION}" STREQUAL "1")
IF(NOT "${VersionTestA_FIND_VERSION_MAJOR}" STREQUAL "1")
MESSAGE(SEND_ERROR "VersionTestA_FIND_VERSION_MAJOR=${VersionTestA_FIND_VERSION_MAJOR} is not 1")
ENDIF(NOT "${VersionTestA_FIND_VERSION_MAJOR}" STREQUAL "1")
IF(DEFINED VersionTestA_FIND_VERSION_MINOR)
MESSAGE(SEND_ERROR "VersionTestA_FIND_VERSION_MINOR should not be defined")
ENDIF(DEFINED VersionTestA_FIND_VERSION_MINOR)
IF(DEFINED VersionTestA_FIND_VERSION_PATCH)
MESSAGE(SEND_ERROR "VersionTestA_FIND_VERSION_PATCH should not be defined")
ENDIF(DEFINED VersionTestA_FIND_VERSION_PATCH)

View File

@ -0,0 +1,12 @@
IF(NOT "${VersionTestB_FIND_VERSION}" STREQUAL "1.2")
MESSAGE(SEND_ERROR "VersionTestB_FIND_VERSION=${VersionTestB_FIND_VERSION} is not 1.2")
ENDIF(NOT "${VersionTestB_FIND_VERSION}" STREQUAL "1.2")
IF(NOT "${VersionTestB_FIND_VERSION_MAJOR}" STREQUAL "1")
MESSAGE(SEND_ERROR "VersionTestB_FIND_VERSION_MAJOR=${VersionTestB_FIND_VERSION_MAJOR} is not 1")
ENDIF(NOT "${VersionTestB_FIND_VERSION_MAJOR}" STREQUAL "1")
IF(NOT "${VersionTestB_FIND_VERSION_MINOR}" STREQUAL "2")
MESSAGE(SEND_ERROR "VersionTestB_FIND_VERSION_MINOR=${VersionTestB_FIND_VERSION_MINOR} is not 2")
ENDIF(NOT "${VersionTestB_FIND_VERSION_MINOR}" STREQUAL "2")
IF(DEFINED VersionTestB_FIND_VERSION_PATCH)
MESSAGE(SEND_ERROR "VersionTestB_FIND_VERSION_PATCH should not be defined")
ENDIF(DEFINED VersionTestB_FIND_VERSION_PATCH)

View File

@ -0,0 +1,12 @@
IF(NOT "${VersionTestC_FIND_VERSION}" STREQUAL "1.2.3")
MESSAGE(SEND_ERROR "VersionTestC_FIND_VERSION=${VersionTestC_FIND_VERSION} is not 1.2.3")
ENDIF(NOT "${VersionTestC_FIND_VERSION}" STREQUAL "1.2.3")
IF(NOT "${VersionTestC_FIND_VERSION_MAJOR}" STREQUAL "1")
MESSAGE(SEND_ERROR "VersionTestC_FIND_VERSION_MAJOR=${VersionTestC_FIND_VERSION_MAJOR} is not 1")
ENDIF(NOT "${VersionTestC_FIND_VERSION_MAJOR}" STREQUAL "1")
IF(NOT "${VersionTestC_FIND_VERSION_MINOR}" STREQUAL "2")
MESSAGE(SEND_ERROR "VersionTestC_FIND_VERSION_MINOR=${VersionTestC_FIND_VERSION_MINOR} is not 2")
ENDIF(NOT "${VersionTestC_FIND_VERSION_MINOR}" STREQUAL "2")
IF(NOT "${VersionTestC_FIND_VERSION_PATCH}" STREQUAL "3")
MESSAGE(SEND_ERROR "VersionTestC_FIND_VERSION_PATCH=${VersionTestC_FIND_VERSION_PATCH} is not 3")
ENDIF(NOT "${VersionTestC_FIND_VERSION_PATCH}" STREQUAL "3")