[CMake] Why do executables link static libs that shared libs were built from?

Craig Scott craig.scott at crascit.com
Sun Jun 16 02:10:07 EDT 2019


On Sat, Jun 15, 2019 at 5:01 PM Paul Smith <paul at mad-scientist.net> wrote:

> I have a situation where I create a number of static libraries, then I
> create a shared library from them, then I create an executable from the
> shared library.
>
> This seems straightforward, but I can't get it do work as I want.  The
> behavior of STATIC -> SHARED for target property inheritance seems
> incorrect to me.
>
> I'm using CMake 3.14.5 on GNU/Linux for this test.
>
> I need the compile properties of the static library (include
> directories etc.) to be public for all users of the shared library as
> well.  But obviously I don't want users of the shared library to also
> link the static library!!  That defeats the whole purpose of the shared
> library.
>
> If I set up like this:
>
>   $ touch foo.c bar.c
>   $ echo 'int main() { return 0; }' > run.c
>
> then write my CMakeFiles.txt like this:
>
>   cmake_minimum_required(VERSION 3.13)
>   project(Test C)
>
>   add_library(foo STATIC foo.c)
>   target_include_directories(foo PUBLIC /tmp)
>
>   add_library(bar SHARED bar.c)
>   target_link_libraries(bar PUBLIC foo)
>
>   add_executable(run run.c)
>   target_link_libraries(run PUBLIC bar)
>
> Then, I DO get the -I/tmp forwarded up to run.c:
>
>   cc -I/tmp -o CMakeFiles/run.dir/run.c.o -c run.c
>      ^^^^^^
>
> But libfoo.a is ALSO added to my link line, which is really wrong!
>
>   cc CMakeFiles/run.dir/run.c.o  -o run -Wl,-rpath,. libbar.so libfoo.a
>                                                                ^^^^^^^^
>
> On the other hand if I change the link of foo to be PRIVATE instead of
> PUBLIC:
>
>   target_link_libraries(bar PRIVATE foo)
>
> then the link doesn't include libfoo.a, which is good, but I also don't
> have the -I/tmp when I compile run.c, which is wrong:
>
>   cc -o CMakeFiles/run.dir/run.c.o -c run.c
>   cc CMakeFiles/run.dir/run.c.o -o run -Wl,-rpath,. libbar.so
>
> Does this seem wrong to anyone else?  Is there some trick to it?
>

The behaviour is correct according to what you are telling CMake to do. If
you use PUBLC in a target_link_libraries() call, you are saying that
anything that links to your shared library should also link to the static
library. PRIVATE would mean that the shared library uses the static library
internally but doesn't expose anything from the static library in the
shared library's interface or header files. If your executable needs to
know about the static library in any way (which means it includes any of
the static library's headers directly or any of the shared library's
headers pull them in), then the static library is no longer a private
dependency and has to be PUBLIC.



> Or do I have to resort to by-hand forwarding of build properties rather
> than relying on a straightforward target_link_libraries() line?
>

Look at your interfaces and header files carefully. Can you avoid referring
to anything from the static library in any of the shared library's public
headers (or any headers that those public headers pull in)? If so, then do
that and you can use target_link_libraries(bar PRIVATE foo). None of the
transitive properties of foo should be needed then either, so you'd have
nothing left to forward on. If you can't avoid it, then the static library
really is a public dependency and anything linking to bar should rightly
also be linking to foo.


-- 
Craig Scott
Melbourne, Australia
https://crascit.com

Get the hand-book for every CMake user: Professional CMake: A Practical
Guide <https://crascit.com/professional-cmake/>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://cmake.org/pipermail/cmake/attachments/20190615/b507ad45/attachment.html>


More information about the CMake mailing list