[cmake-developers] Multiple dependent install(EXPORT) sets

Alexander Neundorf neundorf at kde.org
Tue Nov 22 13:49:45 EST 2011


On Tuesday 22 November 2011, Stephen Kelly wrote:
> Alexander Neundorf wrote:
> > On Tuesday 22 November 2011, Brad King wrote:
> >> On 11/22/2011 10:03 AM, Stephen Kelly wrote:
> >> > Brad King wrote:
> >> >> We will have to require that the install(EXPORT)
> >> >> commands be invoked in dependency order (ex. A before B).  That way
> >> >> when the command installing ExportB is writing library B's dependency
> >> >> on A, it can transform the name using the options that had been given
> >> >> to the install command for ExportA, such as its NAMESPACE.
> >> 
> >> This is required because ExportB will create an imported target for
> >> library B and that imported target will list its dependency on an
> >> imported target
> >> for library A.  What is that imported target called?  Where is it
> >> defined?
> >> 
> >>  Only ExportA knows, and then only after its install(EXPORT) has been
> >> 
> >> called.
> > 
> > Yes.
> > 
> > Where/why is it actually necessary to split libraries installed from one
> > package into multiple Config.cmake files ?
> > This is now to install separate libraries from a big kdelibs, right ?
> > Maybe we (KDE) simply shouldn't do this, and just start with it once the
> > big modules are broken into separate parts.
> 
> Maybe. Should nobody install multiple 'modular pieces' from one top level
> CMakeLists.txt? It's sort of superbuild without superbuild, but with the
> advantage that the sources are in the source directory.

Yes, maybe, but this was not initially the goal, so that doesn't work right 
now.
The motivation for exporting multiple sets of targets from one project was (at 
least among others) to be able to export libraries and executables separately.
This way when crosscompiling, the crosscompiled project can import the 
executable targets from a native build, and do e.g. 
get_target_property(LOCATION ) on the imported executable target the same way 
it can do that in the native build where it has really built the executable. 
Also executable targets are recognized as commands in add_custom_command() and 
add_custom_executable(), so you can simply use the target name there and don't 
have to care whether it is an imported executable target from a native build 
or whether you are natively building.

For that purpose splitting the libraries into multiple dependend sets was not 
necessary (which doesn't mean it would be a bad thing).


> > Then each of the smaller parts can install a Config.cmake file for all
> > its libraries. If e.g. libkgui depends on libkcore, currently those two
> > targets would exist in one project, but installed as two export sets.
> > Once they are separated into two projects, then libkgui depends already
> > on the imported target KDE::kcore (or how it is named), and referencing
> > this in its Targets.cmake file works fine.
> 
> Does a target know its imported target name or is it really just the export
> mechanism? 

It's only in the export sets. You can also put a target into multiple export 
sets, with different "namespaces" etc. if you want to.
With that, one exported target doesn't know which of the potentially multiple 
names of the exported target it depends on it should use.

> Would it be possible for the export mechanism to inform the
> targets of their imported target name and location so that that information
> can be retrieved by dependents?
> 
> Consider this:
> 
> add_library(bar)
> add_library(foo)
> target_link_libraries(foo bar)
> 
> install(TARGETS bar EXPORT barTargets ...)
> install(TARGETS foo EXPORT fooTargets ...)
> 
> install(EXPORTS barTargets NAMESPACE myNS) # sets a property on bar that its 
>                                            # imported name is myNS::bar

install(EXPORTS barTargets NAMESPACE myNS2)  #didn't test but I think it works

> install(EXPORTS fooTargets NAMESPACE otherNS) # Maps from the LINK_LIBRARIES
>                                               # information 'bar' to
>                                               # 'myNS::bar' to populate the
>                                               # dependency information
                                              # or myNS2 ?

...
> This also removes the need for explicit dependencies between
> install(EXPORTS) invocations, which is already implicitly specified by the
> (public) link interface of targets build in the same build system.
> 
> > We do this already with Qt4.
> 
> You mean in FindQt4.cmake? I'm not sure it's the same situation.

I was talking about the following:

FindQt4.cmake creates imported targets. In kdelibs we link against them. The 
names of the imported targets from Qt4 appear again in the Targets.cmake file 
for kdelibs:

# Import target "KDE4__kdecore" for configuration "RelWithDebInfo"
...
SET_TARGET_PROPERTIES(KDE4__kdecore PROPERTIES
  IMPORTED_LINK_INTERFACE_LIBRARIES_RELWITHDEBINFO "Qt4::QtDBus;Qt4::QtCore;-
lpthread"
  IMPORTED_LOCATION_RELWITHDEBINFO 
"/home/alex/Dashboards/installs/2.8.1/kdelibs/lib/libkdecore.so.5.5.0"
  IMPORTED_SONAME_RELWITHDEBINFO "libkdecore.so.5"
  )


In FindKDE4Internal.cmake we do find_package(Qt4), which creates the imported 
targets and sets their locations as they are currently on the system during 
cmake-time of the kdelibs-using package (which can differ from what they were 
at build-time of kdelibs), and then the Targets.cmake file is loaded, which 
can happily reference the imported Qt targets.


> >> >> Furthermore, the targets file
> >> >> generated for ExportB will need to include() the file generated for
> >> >> ExportA using the DESTINATION given to the latter to make its targets
> >> >> available.
> >> > 
> >> > And its FILE presumably, but why? This ties in to the question of
> >> > whether
> >> 
> >> > find_package(B) should find the dependencies of B:
> >> We could leave this part out and leave it up to the Config.cmake file
> >> author to ensure ExportA's targets file is loaded when ExportB's targets
> >> file is loaded.
> 
> Why the Config file author? Why not the consumer of the config files? You
> mean that the author of BConfig.cmake should ensure that ExportA's targets
> file is loaded? How would it do that without a find_package(A)?

It does find_package(A) I'd say.
That B needs A is/can be an implementation detail of B, so the user of B 
should not have to care about it.
E.g. you can also do
find_package(PNG)
and don't have to know that it internally searches zlib.

Alex


More information about the cmake-developers mailing list