[CMake] Second post: find_package with config file always set xyz_FOUND to true?

Michael Hertling mhertling at online.de
Mon Sep 26 00:01:58 EDT 2011


On 09/19/2011 10:01 PM, Anton Deguet wrote:
> Hi Michael,
> 
> Sorry, I mistakenly trashed your previous answer, thank you for both replies.
> 
> It looks like I am not the first one to raise that question.  If I understand well, the primary issue is to agree on the semantic of:
> 
> find_package (xyz COMPONENTS c1 c2)
> if (xyz_FOUND) …

Exactly.

> 
> xyz_FOUND can mean:
> - xyz has been found and since you asked for components c1 and c2, please check the variables xyz_c1_FOUND and xyz_c2_FOUND to see if these components are available
> - xyz has been found along with c1 and c2
> 
> I would personally prefer the second approach as it makes it easy to test if everything has been found as required. [...]

Suppose c2 is missing but optional, i.e. you can successfully configure
your project without it. What's the meaning of xyz_FOUND==FALSE/TRUE?

xyz_FOUND==FALSE *because* c2 is requested but missing?
xyz_FOUND==TRUE *although* c2 is missing but optional?

IMO, both alternatives might be considered as justified, so the only
unambiguous and caprice-free interpretation of xyz_FOUND for a multi-
component package is the one finally agreed on in [1], i.e. xyz_FOUND
must not comprise any of xyz's components. Note that the handling of
optional components - along with required ones - must be dealt with
for multi-component packages, but it doesn't raise issues in the
single-component case.

> [...]  Maybe there is yet another variable to indicate that all components have been found, say xyz_FOUND_AS_REQUIRED.  That would allow users to write simpler code:
> 
> if (xyz_FOUND AND xyz_c1_FOUND AND xyz_c2_FOUND)
> 
> would become:
> 
> if (xyz_FOUND_AS_REQUIRED)
> 
> Ultimately I will stick to the recommended approach.

The same could be quite easily achieved with a supplementary function,
say CHECK_PACKAGE_COMPONENTS(RESULT PACKAGE CMPNT1 CMPNT2 CMPNT3 ...):

FIND_PACKAGE(xyz COMPONENTS c1 c2)
CHECK_PACKAGE_COMPONENTS(xyz_c1_c2_FOUND xyz c1 c2)
IF(xyz_c1_c2_FOUND)
...

Basically, CHECK_PACKAGE_COMPONENTS() ANDs ${PACKAGE}_FOUND and
${PACKAGE}_${CMPNTi}_FOUND together and returns the result. This
would also render a collective handling of required and optional
components elegant and systematic:

FIND_PACKAGE(xyz COMPONENTS req1 req2 req3 opt1 opt2 opt3)
CHECK_PACKAGE_COMPONENTS(xyz_req_FOUND xyz req1 req2 req3)
IF(NOT xyz_req_FOUND)
    MESSAGE(FATAL_ERROR ...)
ELSE()
    FOREACH(i IN ITEMS opt1 opt2 opt3)
        CHECK_PACKAGE_COMPONENTS(xyz_opt${i}_FOUND xyz opt${i})
        IF(xyz_opt${i}_FOUND)
            ...  # enable optional component opt${i}
        ENDIF()
    ENDFOREACH()
ENDIF()

> The second aspect of the issue (and this is what I initially encountered) is the different behavior of find_package for either a module find or a config file.  I wrote a CMake file/scripts that sets xyz_FOUND and used it for both cases, i.e. installed it as either Findxyz.cmake or xyz-config.cmake.  It was a bit disconcerting to have my xyz_FOUND variable overwritten in one case and not the other. [...]

The bare essentials are that FIND_PACKAGE(xyz ...) must not behave
differently w.r.t. module mode and config mode, i.e. the meaning of
xyz_FOUND must be the same in both modes. Its meaning in config mode
is clear and forced by FIND_PACKAGE(): Config file found ==> package
found, i.e. xyz_FOUND==TRUE. The config file can not declare its own
package as absent; this would not make any sense. While that's quite
evident for single-component packages, it's the multi-component case
which is complicating things, but the proper interpretation is quite
clear, too: Config mode forces xyz_FOUND==TRUE if the config file is
found, regardless which components are actually present, and module
mode must follow, i.e. xyz_FOUND==FALSE if the package is not found
at all, but else, don't rely on any component being present because
of xyz_FOUND==TRUE. In other words: xyz_FOUND must not comprise
components, that's the only interpretation which is consistent
in all cases, IMO.

> [...] I understand that this is strongly tied to the defined/accepted meaning of xyz_FOUND and I was apparently mis-using it.  But ... maybe … the find_package could be slightly modified:
> - send a warning to the user (developer message) if the variable xyz_FOUND is modified/set by the file xyz-config.cmake
> - more subtle and might have implications I don't foresee, if after loading the file xyz-config.cmake find_package realizes that xyz_FOUND has been set, let it as is.  That would allow me to keep using xyz_FOUND incorrectly :-)

What I'd really like to see rather than a modification of the - well
designed - FIND_PACKAGE() function is a broad discussion about multi-
component packages and their find modules and config files, ideally
resulting in a reasonable consensus and official recommendations in
Modules/readme.txt. Multi-component packages raise several issues
that are unknown to single-component ones, and although there has
been some discussions about this topic yet, cf. [2], the agreement
on how to handle things properly seems to be quite weak within the
CMake community. IMO, this is regrettable because many of the non-
trivial packages are multi-component in nature; e.g., even a simple
library package could be considered as consisting of the components
"static" and "shared", which would terminate the regularly upcoming
question how to find the static library instead of the usually pre-
ferred shared one.

> Again, thank you for your answer.
> 
> Anton

Regards,

Michael

[1] http://www.mail-archive.com/cmake@cmake.org/msg28431.html
[2] http://www.mail-archive.com/cmake@cmake.org/msg32836.html

> On Sep 19, 2011, at 2:21 PM, Michael Hertling wrote:
> 
>> On 09/19/2011 07:09 PM, Anton Deguet wrote:
>>> Hello,
>>>
>>> I haven't heard anything following my previous post.  Is there any chance someone could provide some guidance?
>>>
>>> Sincerely,
>>>
>>> Anton
>>>
>>> On Aug 29, 2011, at 6:02 PM, Anton Deguet wrote:
>>>
>>>> Hello,
>>>>
>>>> I am trying to use the following syntax:
>>>> find_package (xyz REQUIRED xyz1 xyz2) using a config file, i.e. NOT Findxyz.cmake.
>>>>
>>>> I have a file named xyz-config.cmake that contains some code to check if the required components are available or not (based on how xyz was compiled).  Ideally I would like the find_package command to set xyz_FOUND to false if:
>>>> - xyz-config.cmake file is not found (that's working by default)
>>>> OR
>>>> - xyz-config.cmake file is found BUT one or more component is missing
>>>>
>>>> In my xyz-config.cmake, I tried:
>>>> - set (xyz_FOUND FALSE)  # overall package not found as required
>>>> - set (xyz2_FOUND FALSE)  # component not found, hoping find_package would compare this to the list xyz_FIND_COMPONENTS
>>>>
>>>> But in all cases, it seems that find_package resets xyz_FOUND to 1 as long as the file xyz-config.cmake is found.  Is there a way to set xyz_FOUND to 0 within xyz-config.cmake?
>>>>
>>>> Anton
>>
>> Second try: http://www.mail-archive.com/cmake@cmake.org/msg37840.html
>>
>> Regards,
>>
>> Michael


More information about the CMake mailing list