[cmake-developers] How to handle package Config.cmake files with dependencies ?

Alexander Neundorf neundorf at kde.org
Sat Mar 10 08:10:31 EST 2012


Hi,

...some comments inline, but the main point comes at the end.

On Wednesday 07 March 2012, Michael Hertling wrote:
> On 02/27/2012 09:15 PM, Alexander Neundorf wrote:
> > Hi,
> > 
> > I think find_package in Config mode might still need some more work.
> > 
> > When the FooConfig.cmake has been found, Foo_FOUND is set to TRUE:
> >  // Set a variable marking whether the package was found.
> >  
> >   std::string foundVar = this->Name;
> >   foundVar += "_FOUND";
> > 
> > This means it is true in all cases that the Config.cmake file has been
> > found (and the version was compatible).
> > 
> > Now I have to questions:
> > 
> > 
> > * how to handle COMPONENTS ?
> > 
> > 
> > If a package is requested with COMPONENTS, these should be considered for
> > setting Foo_FOUND:
> > find_package(Foo REQUIRED COMPONENTS A B C)
> > should only succeed if A, B and C are found.
> > 
> > This is how I would expect COMPONENTS to be handled in a FindFoo.cmake:
> > (a) all components are searched by the Find-module, and each
> > per-component X_Y_FOUND is set accordingly
> > 
> > (b) there is a package-specific default subset of these components which
> > have to be found to make the package found, i.e. FOO_FOUND=TRUE
> > 
> > (c) by adding COMPONENTS to the find_package() call, these components are
> > added to the set of components which have to be found to make
> > FOO_FOUND=TRUE
> > 
> > (d) if REQUIRED is used and FOO_FOUND is false, it errors out
> 
> Sorry for chiming in so late, but I haven't got an answer on the
> users' mailing list, so I retry here. Some objections and remarks:
> 
> (1) Foo might have a non-(de)selectable unnamed core component and
> an ordinary selectable component X. FIND_PACKAGE(Foo COMPONENTS X)
> returning Foo_FOUND==FALSE and Foo_X_FOUND!=TRUE does not allow to
> determine if the core component is available. Potential candidates
> for packages like that are Qt, GTK and - most notably - SDL.

It can be checked.
E.g. for Qt there should then also be a QT_QtCore_FOUND variable (I didn't 
check, maybe there is). I know there is a QT_QTCORE_LIBRARY variable which can 
be checked.

> (2) FIND_PACKAGE(Foo COMPONENTS ...) returns Foo_FOUND==FALSE if a
> config file has not been found - crystal. Who sets the components'
> FOUND variables in this case? 

They just stay as they were.
If they were not yet found before, they are still not found.
Ok, if they were found before, one can probably construct cases why they won't 
be found later on.

> FIND_PACKAGE() on its own behalf? If
> so, note [1] and think of the same uncertainty w.r.t. components:

Since the components are not wide spread handled yet, I think we don't have to 
take them into consideration for this.
The "Component" part of the _FOUND variable should be exact case, once we 
introduce/define a standard way how to handle components. 

> FIND_PACKAGE() on its own might return with Foo_bar_FOUND whereas
> the config file sets Foo_Bar_FOUND. Leaving the components' FOUND
> variables untouched? Note [2]. IMO, Brad is absolutely right *not*
> to assume that Foo_FOUND was undefined before FIND_PACKAGE() ran.
> So, concerning Foo_Bar_FOUND, one should also not rely on that
> assumption, but your approach can't guarantee this, AFAICS.
> 
> (3) Suppose a component Y is added to Foo in a later release. Run
> against such a release, FIND_PACKAGE(Foo COMPONENTS Y) is perfect,
> but would face an older FooConfig.cmake with an unknown component
> Y. 

Yes, a Config file must not fail when presented an unknown component.

A normal Find-module, i.e. one which is not simply a wrapper around a 
find_package(NO_MODULE) call, should probably simply set the found variable 
for the unknown component to FALSE.

> Thus, "all components are searched" should read "all requested
> components are searched", the known ones are enabled, and for the
> unknown ones, just the respective FOUND variable is set to FALSE.
> 
> Personally, my favored approach for {FindFoo,FooConfig}.cmake is:
> 
> - Set a FOUND variable for each requested component, known or not.
> - Foo_FOUND==FALSE: Foo totally unavailable, don't use it in any
>   manner. In particular, do not use any further Foo_* variables.
> - Foo_FOUND==TRUE: Foo basically available, but no information
>   about components. Check their availability by the respective
>   FOUND variable, e.g. IF(Foo_FOUND AND Foo_Bar_FOUND).
> 
> For the user, this means:
> 
> - Request all components that will be used.

...and check each of them whether it has been found.

> - Use only components that have been requested.
> 
> IMO, this approach is robust, versatile and anything but difficult
> to implement, and it does not require any change in FIND_PACKAGE().

What it does is it requires a lot of manual checking in the users 
CMakeLists.txt (because they have to check for each requested component 
individually).

How about 

find_package(Foo COMPONENTS Bar Blub OPTIONAL_COMPONENTS Zot Zat ) ?

COMPONENTS: Foo_FOUND is only TRUE if all listed components have been found

OPTIONAL_COMPONENTS: they are not considered for setting Foo_FOUND

The result variables for each component will be fully ExactCase:
Foo_Bar_FOUND etc.

The library and include dir variables from all listed and found components 
should be added to Foo_LIBRARIES and Foo_INCLUDE_DIRS.

If any components are given, it is recommended to search only the listed 
components. AFAICS only in corner cases bad things can happen if all 
components are searched.

How does that sound ?

Alex



More information about the cmake-developers mailing list