[CMake] ${PROJECT}-config.cmake

Brad King brad.king at kitware.com
Tue Jun 15 09:19:25 EDT 2010


Michael Hertling wrote:
> On 06/14/2010 12:09 PM, Biddiscombe, John A. wrote:
>> I've modified the project so that it generates an hdf5-config.cmake
>> file, which checks for If(NOT target blah blah) and then loads the
>> hdf5-targets.cmake file.
[snip]
> To make things more convenient, would it be possible to
> automatically protect the imported targets' definitions in the targets
> file generated by INSTALL(EXPORT ...) using IF(NOT TARGET ...) along
> with the associated properties in the configuration-specific files?

The targets.cmake files are supposed to be included through a
<pkg>-config.cmake file as discussed in this thread.  The outer
config file would need blockers for its settings to handle the
use case under discussion, so doing it in the targets file is
redundant.

I want to keep the targets file as simple as possible, providing
only information that developers cannot get reliably.  This means
there should be minimal logic.  Using "if(NOT TARGET)" could cause
silent failure when one of the targets accidentally conflicts with
a target defined by the including project.  One might end up with
some of the imported targets configured properly and others confused
by target name collisions.

> Currently, as far as I can see, a parent
> directory and its subdirectories have no possibility to load the same
> package involving imported targets independently.

It works if the subdirectory is added before the parent directory
loads the targets:

  ...
  add_subdirectory(dir-using-Foo)
  find_package(Foo)
  ...

The add_subdirectory command initializes processing in the subdirectory
with the state of the parent directory, including currently imported
targets.

However, in a single project the inner directory should know that the
targets were imported by an ancestor and not bother loading the package.
The trouble comes when the inner directory is a project that can also
build stand-alone.  In this case it is probably a third-party dependency
which should be configured before the rest of the project anyway.

> to ask if it would be feasible to make imported targets really scoped,
> i.e. the latest definition hides - but doesn't touch - the previous
> one and remains valid until hidden by a descendant's definition.

This would be cool, but I do not think it would work well.  First,
it can cause mixing of targets from different versions of imported
package.  For example:

  # finds version 1, but parent already loaded version 2
  find_package(Foo)
  if(TARGET target_from_version_2)
    # ... uses target from wrong Foo
  endif()

Second, the lazy evaluation of link dependencies makes the scope hard
to define.  The names passed to target_link_libraries() are not
processed until generation time.  This allows code like

  # lib_from_Foo not yet defined
  target_link_libraries(mylib1 lib_from_Foo)
  find_package(Foo) # loads lib_from_Foo
  target_link_libraries(mylib2 lib_from_Foo)

to work.  (The delayed evaluation allows things like circular
dependencies among static libraries to work.)  Now consider the scoped
replacement case:

  # ...parent already loaded package Foo
  target_link_libraries(mylib1 lib_from_Foo)
  # ...finds different Foo than parent
  find_package(Foo)
  target_link_libraries(mylib2 lib_from_Foo)

By the time CMake looks for an imported target "lib_from_Foo" to
link to mylib1, it has been replaced by the one from a different
version of Foo.  This may be what the author intended, or it may
not.

-Brad



More information about the CMake mailing list