[CMake] Apply FIND_PACKAGE_HANDLE_STANDARD_ARGS() on COMPONENTS

Michael Hertling mhertling at online.de
Fri Apr 23 17:37:26 EDT 2010


On 04/22/2010 01:50 PM, S Roderick wrote:
> On Apr 22, 2010, at 06:21 , Michael Hertling wrote:
> 
>> On 04/21/2010 09:29 PM, S Roderick wrote:
>>> On Apr 21, 2010, at 15:13 , Alexander Neundorf wrote:
>>>
>>>> On Tuesday 20 April 2010, Michael Hertling wrote:
>>>>> Dear CMake community, dear CMake developers,
>>>>>
>>>> ...
>>>>> 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.
>>>>
>>>> I think I don't agree here.
>>>> If I say
>>>> find_package(XXX COMPONENTS YY1 YY2 REQUIRED)
>>>> I think it makes a lot of sense to interpret this as "search package XXX, and 
>>>> I need YY1 and YY2 from it".
>>>> What other reason would I have to give YY1 and YY2 there otherwise ?
>>>> If it still succeeds if they are not found, why should I list them then ?
>>>
>>>
>>> +1
>>>
>>> find_package(XXX COMPONENTS YY1 YY2 REQUIRED)
>>>
>>> means to me, I _require_ both YY1 and YY2 from XXX. Any other YYx I don't care about.
>>
>> Yes, of course, the REQUIRED option is definitive; it's
>> COMPONENTS without REQUIRED which raises the questions.
>>
>>> The first version above translates to me to be
>>>
>>> find_package(XXX COMPONENTS YY1 REQUIRED)
>>>
>>> I only _require_ YY1.
>>
>> As I have replied recently to AN, I sometimes dislike FIND_PACKAGE() to
>> look for unrequested components, so I need to request them even if they
>> are optional, but this is just my personal preference and, also, not my
>> concern here.
>>
>> My concern is that FIND_PACKAGE(XXX COMPONENTS YY) will always return
>> XXX_FOUND=TRUE if it's driven by XXXConfig.cmake, regardless if YY is
>> found or not, while the same command could return XXX_FOUND=FALSE if
>> driven by FindXXX.cmake since the latter has XXX_FOUND in its hands.
>> Thus, IMHO, it should be reconsidered how XXX_FOUND is interpreted
>> w.r.t. components because I would expect both variants - XXXConfig
>> and FindXXX - to behave the same.
> 
> That seems to make sense. YY isn't listed as required, therefore it is optional. [...]

Sometimes, this decision between required and optional isn't that easy.
Imagine some of a package's components are required and some are
optional. How would you do the FIND_PACKAGE()?

1) Call it with REQUIRED? This means a missing optional component is
   capable to terminate the whole configuration process: Bad.
2) Call it without REQUIRED? This means you must handle the absence of
   a required component by yourself, as well as you have to handle the
   presence of an optional component: My personal favourite - flexible,
   clean and quite safe.
3) Call it with REQUIRED and mention the required components only? This
   means to rely on the find module to search the unmentioned optional
   components without being requested to do so. Is this guaranteed or,
   at least, recommended behaviour? E.g., FindQt4 behaves differently:
   If you want SQL or the like you have to say it.
4) Call it twice, with and without REQUIRED and with a different set of
   components each time? Which impact would this have on the affected
   variables in the current scope, the cache, efficiency etc.?

For method 2 to be bullet-proof, it's necessary that XXX_FOUND isn't set
to false just because any requested components aren't detected. If this
would be the case you even simply could not request optional components
with FIND_PACKAGE() in a secure manner: XXX_FOUND=FALSE possibly means
that XXX actually hasn't been found at all; therefore, you may not rely
on any XXX_YY_FOUND having a defined value. Consequently, the right way
to check for YY is IF(XXX_FOUND AND XXX_YY_FOUND)...ENDIF(), and this
wouldn't work if XXX_YY_FOUND=TRUE while XXX_FOUND=FALSE due to some
other XXX_ZZ_FOUND=FALSE.

> [...] Having XXX_FOUND=TRUE seems reasonable if CMake found some portion of XXX, regardless of whether it did, or did not, find YY. [...]

Yes, that's exactly the way I think XXX_FOUND should be interpreted.

> [...] If we required YY, then we should have added REQUIRED.

Even this is no guarantee that you can get rid of explicitly checking a
component's availability: FIND_PACKAGE(Qt4 REQUIRED QtCore QtGui QtXml)
survives with QT4_FOUND=TRUE and QT_QTXML_FOUND=FALSE if QtXml can't be
detected. For me, such peculiarities of find modules are another reason
to prefer the above-mentioned method 2.

> Now the fact that COMPONENTS and REQUIRED are mutually exclusive is not right IMHO. I'd love to hear Kitware's take on why it was done this way.

As Alexander Neundorf mentioned recently, the COMPONENTS option hasn't
been intensively discussed, so far. Perhaps, this thread contributes.

Best regards,

Michael


More information about the CMake mailing list