[CMake] Using target_link_libraries INTERFACE with static libraries

Mario Werner mario.werner at iaik.tugraz.at
Thu Jun 1 07:53:29 EDT 2017


Hi Luis,

as you correctly concluded, if 'Foo' is not part of the public interface
of 'Bar', then the PRIVATE is the correct specifier.

However, you don't have to add 'Foo' to the consumers of 'Bar' (e.g.,
'MyApp'). If everything works as expected, CMake automatically tracks
the link dependency from 'Bar' to 'Foo' and adds it to the link command
of the consuming artifact when 'Bar' is a static library.

I did a quick experiment based on the code layout you outlined and for
me everything worked out of the box. If it does not for you, it would be
great if you can provide an actual minimal working example which shows
the issue.

Maybe the very detailed explanation [1] provided by Craig Scott is also
interesting in this context.

HTH,
Mario

[1] https://cmake.org/pipermail/cmake/2016-May/063400.html

On 2017-06-01 13:11, Luis Caro Campos wrote:
> I have the following scenario where I have 2 static libraries, where one
> uses symbols from the other, and the executable needs to link against both
> in order to build properly.
> 
> Library 'Bar' uses symbols from library 'Foo' internally, but 'Foo' is not
> part of the "interface" of Bar, i.e., the calling library/application only
> needs to include headers from 'Bar', and use symbols from Bar.
> 
> ---
> #static libraries, assuming BUILD_SHARED_LIBS is off
> add_library(Foo)
> add_library(Bar)
> target_include_directories(Foo PRIVATE ... )
> target_include_directories(Foo INTERFACE ...)
> target_include_directories(Bar PRIVATE ...)
> target_include_directories(Bar INTERFACE ..)
> 
> # this will expose Bar to Foo's interface include directories
> target_link_libraries(Bar PUBLIC|PRIVATE Foo)
> 
> 
> add_executable(MyApp)
> target_link_libraries(MyApp PRIVATE Bar)
> 
> ---
> 
> In order to for the executable "MyApp" to build successfully, which uses
> static library Bar, "Foo" also needs be in the link statement otherwise
> I'll get missing symbols. If 'Bar' doesn't include this information in the
> target link interface, I'll have to explicitly link against "Foo" for MyApp.
> 
> My question is, in this case, which is the correct keyword for use when
> calling "target_link_libraries" between Bar and Foo?
> 
> Technically, 'Foo' is not part of Bar's public interface, so it would be
> PRIVATE. However, this would force me to have to expressly link against Foo
> in MyApp.
> The other alternative is PUBLIC, as that would take care of the dependency.
> I think strictly speaking, it is an "interface link dependency", but not an
> "interface" dependency. I know that there are LINK_PUBLIC and LINK_PRIVATE
> keywords for target_link_libraries, however the documentation says they are
> for compatibility only and the other ones should be favoured.
> 
> So in this scenario, I guess "PUBLIC" would be the best case, as that takes
> care of the linking of MyApp.
> 
> Question (1): does this not have the downside of adding Foo's interface
> include directories to MyApp's include path?
> 
> The second scenario would be if Foo was static and Bar was shared. In that
> case, it would be crystal clear, the target_link_libraries call between Foo
> and Bar should use the PRIVATE keyword.
> However, what about if BUILD_SHARED_LIBS was set to on?
> Both would be shared libraries, but MyApp doesn't need to link against
> "Foo" anymore, however it is needed at runtime.
> 
> Question (2): toggling the BUILD_SHARED_LIBS flag then seems to require
> altering the semantics of calls to target_link_libraries? What about the
> "needed at runtime" but "no part of the interface case?
> 
> My conclusion is that I should perhaps explicitly declare those libraries
> as static (foo and bar), and use the "PUBLIC" keyword when linking them.
> Although I see two downsides:
> 1) Foo's interface include path is added to MyApp's include path (and it is
> not needed)
> 2) Bar is now dependant on "Foo", so Foo needs to be built before. However,
> from a compiler point of view, the binaries of Foo are not needed to
> produce bar.
> 
> Any help would be appreciated, in case there are better ways to express
> these dependencies that I'm ignoring.
> 
> 
> 
> Thanks,
> Luis
> 
> 
> 




More information about the CMake mailing list