[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