[CMake] providing library information, what's the cmake way

Johannes Zarl johannes.zarl at jku.at
Thu Dec 9 11:44:18 EST 2010


At this point of the discussion, I think that we need someone else to 
join. We both have made strong points for our viewpoints, and neither of 
us has a "perfect" solution. 

On Sunday 05 December 2010 12:48:49 Michael Hertling wrote:
> On 12/01/2010 05:57 PM, Johannes Zarl wrote:
> > On 12/01/2010 at 16:06, Michael Hertling <mhertling at online.de> 
wrote:
> > These variables are well-known and officially recommended for
> > component- less packages only. Nobody bothered to write
> > recommendations for component-packages yet.
> 
> ${CMAKE_ROOT}/Modules/readme.txt mentions the XXX_YYY_EXECUTABLE and
> XXX_YY_{LIBRARY,INCLUDE_DIR} variables explicitly, and IMO, wordings
> as "YYY tool that comes with XXX" or "YY library that is part of the
> XXX system" allow the general terms "tool" and "part" to be applied
> smoothly to the components of a package. Furthermore, the component-
> specific variables like XXX_FIND_COMPONENTS are handled also, so I
> do believe that this file is relevant for multi-component packages,
> too, including the XXX_{LIBRARIES,INCLUDE_DIRS} variables. However,
> variables like XXX_YYY_{LIBRARIES,INCLUDE_DIRS} are not mentioned
> at all, i.e. there're completely new and should be well founded.

IMO the wording is ambiguous. When I read it, it was obvious to me that 
the XXX_YYY_LIBRARIES etc. are to be defined. To quote readme.txt:

> XXX_EXECUTABLE     Where to find the XXX tool.
> XXX_YYY_EXECUTABLE Where to find the YYY tool that comes with XXX.

I assumed XXX_YYY_EXECUTABLE as an example, so that not every variable 
has to be mentioned a second time in its component-specific form.
Now that I heard your interpretation and reread readme.txt, it fits the 
description just as well.

> Anyway, the ${CMAKE_ROOT}/Modules/readme.txt doesn't handle multi-
> component packages thouroughly, so I would greatly appreciate any
> improvements to decrease ambiguities/uncertainties and to reach a
> consensus. For this reason, I regret that we haven't seen further
> opinions on this topic, in particular because pretty much every
> non-trivial package could make good use of a components-aware
> find module or config file.

As I have written above, I totally agree.

> > The problem is that FPHSA simply wasn't created with components in
> > mind. As worthwhile as code-reuse is, it's not a goal in itself.
> > Rather than jump through hoops in order to reuse the existing
> > interface, IMO one should create a good interface for the more
> > complex use-case at hand.
> 
> To apply FPHSA to a component and, thus, re-use existing code, I just
> need to define two variables; this is not "jumping through hoops".

Setting a specific variable for its side-effects before calling a 
function makes a truly bad interface-style for me. Regardless of the 
outcome of this discussion, I'll create a patch for the FPHSA module 
introducing the component-keyword (once, I have time, whenever that is; 
a totally different topic is whether the patch will be included to 
cmake).

 
> Suppose you have components YYY and ZZZ with ZZZ depending on YYY.
> When handling ZZZ in the find module, there's a certain probability
> that you must access the YYY stuff, so one would like to have the
> XXX_YYY_FOUND variable already defined at this time. 

This is a sensible assumption, and should be supported by a component-
aware FPHSA...

> With the
> FPCHSA, the components' FOUND variables are defined in one go at the
> module's end; hence, one has to check YYY's availability by oneself
> when it's needed for ZZZ, and FPCHSA will do the same work once more
> later. 

Well, there currently does not exist a single line of code for a 
component-aware FPHSA. If it were to be implemented like this, There 
wouldn't be much incentive to use it.

> Instead, IMO, it's convenient to check a component's presence
> right after the relevant variables have received their values, and
> for this purpose, FPHSA is entirely sufficient.

Apart from the whole defining-variables-for-side-effect thing, yes. 
Still this would benefit from component-awareness:

...
FPHSA(XXX XXX_LIBRARIES XXX_INCLUDE_DIRS)
#detect component YYY
FPHSA(XXX COMPONENT YYY XXX_YYY_FOO XXX_YYY_BAR)
...

> > find_package( XXX COMPONENTS YYY)
> > target_link_libraries(foo ${YYY_LIBRARIES})
> > find_package( XXX COMPONENTS ZZZ)
> > target_link_libraries(bar ${ZZZ_LIBRARIES})
> > 
> > At this point, I just realised that I was being inconsistent. After
> > all, the components do depend on the whole package. So
> > YYY_LIBRARIES should also contain XXX_LIBRARIES.
> 
> If I understand correctly, you intend to populate XXX_YYY_LIBRARIES,
> e.g., with its own value XXX_YYY_LIBRARY *and all* its prerequisite
> components' values, too? If so, you will end up with many repeatedly
> mentioned libraries on the link command line unless there're hardly
> any inter-component dependencies. Suppose ZZZ depends on YYY, so
> 


I have to admit that I didn't encounter a use-case with inter-component 
dependencies before this discussion, so my thoughts on this might be 
called "developing". Still, you misquoted me there:

My current use case (and the use case I used at the beginning of this 
discussion) assumes multiple components, but no dependencies. Thus the 
example:

> FIND_PACKAGE(XXX COMPONENTS YYY ZZZ)
> ...
> TARGET_LINK_LINK_LIBRARIES(...
>     ${XXX_LIBRARIES} ${XXX_YYY_LIBRARIES} ${XXX_ZZZ_LIBRARIES}
> )

does not repeat anything in my original use case. When you brought up 
dependencies, I tried to adopt my approach, which eventually ended up 
with the following link-line for the above example:

TARGET_LINK_LINK_LIBRARIES(... ${XXX_ZZZ_LIBRARIES})

So again, no duplicates. However, my approach still was shortsighted: If 
you have a target depend on two components which are not dependent upon 
each other, but in turn depend on (some of) the same components. You 
actually do end up with duplicates in your link-lines. 

A bad situation, but not as bad as your O(n^2) assumption -- the 
duplicated entries grow linearly. Unless you really have packages with a 
lot of components with many inter-component dependencies, I doubt this 
will become perceptible even for a large project.

> In general, from a user's perspective, I don't want to wonder if ZZZ
> depends on YYY so I could possibly drop the latter from the list of
> components although I need to use it. Furthermore, while the effect
> of unnecessarily mentioned libraries during link phases is mostly
> negligible, I'd bear it in mind. Finally, overlinking due to any
> overstuffed XXX_LIBRARIES variable can be easily avoided by an
> additional FIND_PACKAGE() call which is cheap to have.

So, basically the user doesn't want to wonder whether some component can 
be dropped or not, and when writing programs the user is already aware 
of dependencies. That brings us back to my original use case without 
dependencies-support. The user just adds all components that are needed, 
and XXX*LIBRARIES contains exactly the correct entries.

I'll come back to the overlinking issue later on...

> In order not to be misunderstood: I see your intention, and I see the
> advantages you want to achieve, but I think the disadvantages
> prevail:
> 
> - More work for the user due to component-specific sets of variables.

Yes, that's the price of my approach.

> - Unnecessary repetition of libraries on the link command line.

My original approach doesn't have this problem, as dependencies are not 
handled. 

> - Inconvenient centralization of the FOUND variables' setup.

That's not true. First of all, the side-discussion about FPHSA is valid 
for both your and my approach. Secondly, as I outlined above, you can 
have a better FPHSA that is component-aware and still use it exactly 
like you do in your approach.

> In addition, when looking at FPHSA's current implementation, I've
> doubts whether a component-related extension should be added to this
> somewhat non-trivial function, in particular since it's already
> applicable to components, but of course, feel free to specify and
> implement an improved version and bring it up for discussion.

As written above, I'll do that ;-)

One thing important to me slipped through in this discussion: component-
aware XXXConfig.cmake packages. I bring them up again, because they are 
to be functionally equivalent to the FindXXX.cmake modules.

Config-mode packages differ substantially to modules in what is possible 
to do with them: In a config-mode script you can not make any assumption 
about the cmake version in use, or which other packages are available. 

This means, that if you need to do any sort of processing to your 
variables, you essentially have to include your code in each 
XXXConfig.cmake script. 

If you move the responsibility for merging all relevant variables into 
the find_package call, you end up with massive code-duplication inside 
the config-mode scripts.


Let's make a clear cut here, and summarise both of our viewpoints and 
their advantages. That should make it easier for someone else to join 
the discussion. Also I'd like to stick to the "big-picture" and not get 
tangled too much in technicalities.

Viewpoint: Johannes' position

Use case: 
 - Multi-component packages, little or no inter-component dependencies
 - Only explicit inter-component dependencies, known to the user
 - multiple targets inside one list file linking against different 
   libraries/components.

Advantages:
 - Only explicit behaviour (value of XXX_LIBRARIES etc. is not 
   context-sensitive).
 - XXXConfig.cmake files don't need to do any computations.
 - No overlinking possible.
 - No need to backup any variables.

Example (normal case):
  FIND_PACKAGE(XXX COMPONENTS YYY ZZZ)
  TARGET_LINK_LIBRARIES(... ${XXX_LIBRARIES} ${XXX_YYY_LIBRARIES})
  TARGET_LINK_LIBRARIES(... ${XXX_LIBRARIES} ${XXX_ZZZ_LIBRARIES})
Example (worst case):
  FIND_PACKAGE(XXX COMPONENTS YYY ZZZ AAA BBB)
  TARGET_LINK_LIBRARIES(... ${XXX_LIBRARIES} ${XXX_YYY_LIBRARIES}
    ${XXX_AAA_LIBRARIES} ${XXX_AAA_LIBRARIES})



Viewpoint: Michaels position

Use case:
 - Multi-component packages, complicate inter-component dependencies
 - Implicit inter-component dependencies, maybe unknown to the user
 - Mostly just one target per file

Advantages:
 - User only needs to know leaves of dependency tree.
 - Normally short notation, user can write compact list files.

Example (normal case):
  FIND_PACKAGE(XXX COMPONENTS YYY ZZZ)
  TARGET_LINK_LIBRARIES(... ${XXX_LIBRARIES}
Example (worst case):
  FIND_PACKAGE(XXX COMPONENTS YYY )
  SET(TARGET_A_LIBRARIES ${XXX_LIBRARIES})
  TARGET_LINK_LIBRARIES(... ${TARGET_A_LIBRARIES})
  FIND_PACKAGE(XXX COMPONENTS ZZZ )
  SET(TARGET_B_LIBRARIES ${XXX_LIBRARIES})
  TARGET_LINK_LIBRARIES(... ${TARGET_B_LIBRARIES})


Currently, I'm tired, so I'm sure there are advantages that I didn't 
mention. Please add them! 


> Regards,
> 
> Michael
> 
> PS: Could you prevent your signature from sometimes appearing midway
>     through your posts? This confuses my mail client when replying.

Sorry! A quotation-level >= 4 (more concisely, a line beginning with 
">>>>") confuses my mail-client at work. I'll try to keep an eye on this 
in the future...


More information about the CMake mailing list