[CMake] Proposal: extra option PRIVATE for target_link_libraries

Marcel Loose loose at astron.nl
Wed Dec 23 10:04:14 EST 2009


On Wed, 2009-12-23 at 15:19 +0100, Michael Wild wrote:
> On 23. Dec, 2009, at 15:14 , Marcel Loose wrote:
> 
> > On Wed, 2009-12-23 at 14:12 +0100, Michael Wild wrote:
> >> On 23. Dec, 2009, at 13:28 , Marcel Loose wrote:
> >> 
> >>> On Wed, 2009-12-23 at 13:09 +0100, Michael Wild wrote:
> >>>> On 23. Dec, 2009, at 12:08 , Marcel Loose wrote:
> >>>> 
> >>>>> Hi all,
> >>>>> 
> >>>>> I suggested this in the quite long thread "third party library
> >>>>> dependencies", but it may have been overlooked. Hence, I started a new
> >>>>> thread.
> >>>>> 
> >>>>> Upon (re)reading the Mandriva page
> >>>>> http://wiki.mandriva.com/en/Overlinking, I was thinking: maybe the issue
> >>>>> of overlinking can be solved more or less the same way as pkg-config
> >>>>> does: i.e. by defining private dependencies. This could be an extra
> >>>>> option to target_link_libraries. 
> >>>>> Something like:
> >>>>> 
> >>>>> target_link_libraries(mylib public1 public2 PRIVATE private1 private2)
> >>>>> 
> >>>>> This would tell CMake that mylib directly depends on public1 and public2
> >>>>> and should only link in these two libraries when these are shared
> >>>>> object libraries; otherwise private1 and private2 would also need to be
> >>>>> added on the link line.
> >>>>> 
> >>>>> The big hurdle to take, of course, is to detect in a
> >>>>> platform-independent way whether the given library is shared or static.
> >>>>> However, a lot of this knowledge is already available in the diverse
> >>>>> Modules/Platform macros, so my feeling is that this should be feasible.
> >>>>> 
> >>>>> Best regards,
> >>>>> Marcel Loose.
> >>>>> 
> >>>> 
> >>>> You would also need a PUBLIC keyword, and then require that all FindXXX.cmake modules prefix their libraries with PUBLIC and PRIVATE. If only the PRIVATE libraries where prefixed, the following would not work if A_LIBRARIES contains PRIVATE:
> >>>> 
> >>>> find_package(A)
> >>>> find_package(B)
> >>>> add_library(C source.c)
> >>>> target_link_libraries(C ${A_LIBRARIES} ${B_LIBRARIES})
> >>>> 
> >>>> Because then all the B_LIBRARIES would be considered to be private "details" of the public A_LIBRARIES... Also, there's no way to tell CMake which of the private libraries belongs to which of the public libraries.
> >>>> 
> >>>> I think it would be better if a FindXXX.cmake module marked the private libraries as a property of the public libraries and then let CMake take it from there (although as of now I wouldn't know on what to set the property, except if the module created an IMPORTED target for each of the public libraries, but that bears the possibility of target name collisions with the importing project).
> >>>> 
> >>>> Michael
> >>> 
> >>> Hi Michael,
> >>> 
> >>> I don't think you'll need to prefix the library names with either
> >>> PRIVATE_ or PUBLIC_. CMake could figure out whether "public1" and
> >>> "public2" are shared or static libraries. If they are shared libraries,
> >>> then the libraries marked as private ("private1" and "private2") do not
> >>> have to be linked in as well. Otherwise they must also be linked in. I
> >>> assume that CMake keeps a list internally, of all dependent targets; the
> >>> private libs should only be added to that internal list if the public
> >>> libs are static libs.
> >>> 
> >>> I don't completely understand your example. Are you suggesting that
> >>> you'll run into trouble if you have a library named "PRIVATE"? I think
> >>> name clashes will currently occur as well if I name my library "debug",
> >>> "optimized", or "general".
> >>> 
> >>> Maybe, it would be better if the FindXXX modules would handle this. On
> >>> the other hand, you then depend on third parties to properly update
> >>> their FindXXX modules, or have to rewrite them yourselves :-(
> >>> 
> >>> Best regards,
> >>> Marcel Loose.
> >>> 
> >> 
> >> 
> >> No, it won't work. For example, if FindA.cmake does
> >> 
> >>  set(A_LIBRARIES /some/path/libA.so
> >>      PRIVATE /some/other/path/libX.a /some/other/path/libY.a)
> >> 
> >> and FindB.cmake contains
> >> 
> >>  # notice that this is a static library!
> >>  set(B_LIBRARIES /some/path/libB.a)
> >> 
> >> 
> >> then the call
> >> 
> >>  target_link_libraries(C ${A_LIBRARIES} ${B_LIBRARIES})
> >> 
> >> expands to (wrapped for legibility
> >> 
> >>  target_link_libraries(C
> >>      /some/path/libA.so
> >>      PRIVATE /some/other/path/libX.a
> >>      /some/other/path/libY.a
> >>      /some/path/libB.a)
> >> 
> >> which is different in meaning from
> >> 
> >>  target_link_libraries(C ${B_LIBRARIES} ${A_LIBRARIES})
> >> 
> >> which becomes
> >> 
> >>  target_link_libraries(C
> >>      /some/path/libB.a
> >>      /some/path/libA.so
> >>      PRIVATE
> >>      /some/other/path/libX.a
> >>      /some/other/path/libY.a)
> >> 
> >> In the first case libB.a becomes marked as PRIVATE of libA.so! Not very nice if you ask me ;-)
> >> 
> >> Michael
> > 
> > Hi Michael,
> > 
> > I never suggested that A_LIBRARIES should be set to contain "PRIVATE". I
> > suggested to add a keyword "PRIVATE" to the target_link_libraries
> > command.
> > 
> 
> Ok, but then how does FindA.cmake communicate that libA.a needs some private libraries? Does the user then have to do
> 
> target_link_libraries(C ${A_LIBRARIES} ${B_LIBRARIES}
>     PRIVATE ${A_PRIVATE_LIBRARIES} ${B_PRIVATE_LIBRARIES})
> 
> How, then, does CMake know that it should link ${B_PRIVATE_LIBRARIES} but NOT ${A_PRIVATE_LIBRARIES} if ${A_LIBRARIES} is a shared library and ${B_LIBRARIES} is a static library?
> 
> 
> Michael

Hi Michael,

I think that FindA.cmake should set A_LIBRARIES differently when libA is
static or shared. If libA is shared, then A_LIBRARIES only has to
contain the path to libA. If libA is static then FindA should list all
its dependent libraries in A_LIBRARIES too. It doesn't really matter if
these libs are private or not, because the user of libA will still have
to link against libA's private libs in that case.

What I wanted to avoid is that, if I have another library, say D, that
depends on C, that D is only linked against C, and not A and B, if C is
a *shared* library. That's the message I was trying to convey with the
PRIVATE keyword.

On the other hand, maybe Alex is right when he says that, what I
proposed as a new feature, can already be achieved using
LINK_INTERFACE_LIBRARIES. I'm not sure; it feels as if I'm entering
uncharted territory. I have to study this more carefully.

Best regards,
Marcel Loose.




More information about the CMake mailing list