[CMake] Apply FIND_PACKAGE_HANDLE_STANDARD_ARGS() on COMPONENTS
Michael Hertling
mhertling at online.de
Mon Apr 19 21:23:21 EDT 2010
Dear CMake community, dear CMake developers,
until recently, there has been some considerations w.r.t. the
applicability of FIND_PACKAGE_HANDLE_STANDARD_ARGS() to components
requested by FIND_PACKAGE() with the COMPONENTS|REQUIRED option, see
<http://www.cmake.org/Bug/view.php?id=5920> and the initial discussion
at <http://www.cmake.org/pipermail/cmake/2007-October/017068.html>. To
this, I would like to make the following proposal:
Given a package XXX with a component YY being requested by
FIND_PACKAGE(XXX ... COMPONENTS ... YY ...) or
FIND_PACKAGE(XXX ... REQUIRED ... YY ...), and
imagine FIND_PACKAGE() would provide the following new variables to
FindXXX.cmake or XXXConfig.cmake or xxx-config.cmake, respectively:
XXX_YY_FIND_REQUESTED: True if component YY of package XXX is
requested, either by COMPONENTS or as REQUIRED
XXX_YY_FIND_REQUIRED: True *only* if XXX is requested as REQUIRED
XXX_YY_FIND_QUIETLY: True if XXX is requested as QUIET
Having these variables availabe, one could handle a requested component
YY of package XXX, e.g. a library, as follows - just a simple example:
IF(XXX_YY_FIND_REQUESTED)
# Component YY of package XX was requested with COMPONENTS or
# REQUIRED option; in either case, we'll do our very best:
FIND_LIBRARY(XXX_YY_LIBRARY xxxyy ...)
FIND_PATH(XXX_YY_INCLUDE_DIR xxx/yy.h ...)
# Now, due to the suitably named variables XXX_YY_FIND_REQUIRED and
# XXX_YY_FIND_QUIETLY, FIND_PACKAGE_HANDLE_STANDARD_ARGS() can be
# applied to YY in an immediate manner:
FIND_PACKAGE_HANDLE_STANDARD_ARGS(
XXX_YY
DEFAULT_MSG|<custom message>
XXX_YY_LIBRARY
XXX_YY_INCLUDE_DIR
)
# Additionally, FIND_PACKAGE_HANDLE_STANDARD_ARGS() has set
# XXX_YY_FOUND as being demanded by Modules/readme.txt if
# YY is considered a "part" of XXX, like the readme says.
# Now, we can extend the officially recommended variables
# for libraries and include directories with the results:
IF(XXX_YY_LIBRARY)
LIST(APPEND XXX_LIBRARIES ${XXX_YY_LIBRARY})
ENDIF()
IF(XXX_YY_INCLUDE_DIR)
LIST(APPEND XXX_INCLUDE_DIRS ${XXX_YY_INCLUDE_DIR})
ENDIF()
# Finally, remove YY from the list of requested components to
# preserve the option to handle unknown components at the end:
LIST(REMOVE_ITEM XXX_FIND_COMPONENTS YY)
ENDIF()
The availability of XXX_YY_FIND_REQUIRED and XXX_YY_FIND_QUIETLY,
although just copies of XXX_FIND_REQUIRED and XXX_FIND_QUIETLY, would
enable FIND_PACKAGE_HANDLE_STANDARD_ARGS() to handle the REQUIRED and
QUIET options w.r.t. the component YY in a correct manner and without
any modification; in particular, there would be no impact on backward
compatibility. The variable XXX_YY_FIND_REQUESTED is just the same as
XXX_FIND_REQUIRED_YY, but, IMHO, the latter is somewhat misnamed since
it is set to TRUE even if the concerned component wasn't requested as
REQUIRED. Of course, one could define these three variables within a
find module or config file, but having them defined by FIND_PACKAGE()
itself would be much more elegant. In summary, this turns out to be an
adaption of variables provided by FIND_PACKAGE() to requirements of
FIND_PACKAGE_HANDLE_STANDARD_ARGS() when it comes to components.
Alternatively, it could perhaps be worth considering to provide a
slightly modified copy of FIND_PACKAGE_HANDLE_STANDARD_ARGS(), say
FIND_COMPONENT_HANDLE_STANDARD_ARGS(), with the following signature:
FIND_COMPONENT_...(_PACKAGE _COMPONENT _MESSAGE _VAR1)
Basically, this function would do the same as FIND_PACKAGE_...(), but
takes ${_PACKAGE}_FIND_QUIETLY and ${_PACKAGE}_FIND_REQUIRED as QUIET
and REQUIRED flags, and sets up ${_PACKAGE}_${_COMPONENT}_FOUND at the
end. Again, this would mean no harm to backward compatibility.
There's another aspect related to this I'd like to comment on: During
the abovementioned considerations on the bug tracker and the mailing
list, the question has arisen if it's reasonable to set XXX_FOUND to
FALSE if any of the requested components aren't found. As for myself,
I'd say: No, it isn't. Let's have a look at the following scenario:
Package XXX normally provides components YY1 and YY2, but for some
reason, only YY1 is installed. Moreover, XXX provides a config file
XXXConfig.cmake. Now, a project's CMake script requests both YY1/2 by
FIND_PACKAGE(XXX COMPONENTS YY1 YY2). As Brad King has pointed out in
<http://www.mail-archive.com/cmake@cmake.org/msg15952.html>, finding a
config file results in XXX_FOUND to be set to TRUE automatically. Thus,
the absence of YY2 does not mean the absence of XXX as a whole in any
case, and, notwithstanding, the requesting CMake script should have a
chance to proceed even if YY2 isn't available, i.e. the following seems
reasonable: XXX_YY1_FOUND=TRUE, XXX_YY2_FOUND=FALSE *but* XXX_FOUND=TRUE.
More information about the CMake
mailing list