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

Eric Noulard eric.noulard at gmail.com
Sun Jun 16 15:42:30 EDT 2019


Le dim. 16 juin 2019 à 18:26, Paul Smith <paul at mad-scientist.net> a écrit :

> Let me just mention up-front that I spent about 2 weeks earlier this
> year completely converting our circa-2011 cmake environment to ultra-
> modern cmake: switching completely to TLL, interfaces, removing
> virtually all if-statements and converting them into generator
> expressions, etc.  So I'm very familiar with CMake's model for PRIVATE,
> PUBLIC, and INTERFACE and how inheritance works.
>
> And, I see the paradigm you're operating under where a shared library
> provides a single "interface" that is public.
>
> But, that's not the only way to use shared libraries.  I'm trying to
> collect a number of static libraries with different interfaces into a
> single shared library that can be linked with executables (in my case I
> have 220 unit test programs which, when linked statically, not only
> take a very long time and a lot of memory, but use about 45G of disk
> space per build--I am collecting these into a shared library that can
> be linked with our unit tests.  In my testing this reduces the size of
> a sample unit test executable from 400M down to about 8M).
>

Correct me if I'm wrong but I guess that if your goal is to "collect" all
those static libs *into* a shared
lib then what you need is to make your STATIC libs,  OBJECT libs and then I
think you'll get what you expect.
I.e. in your CMakeLists.txt
replace
add_library(foo STATIC foo.c)
with
add_library(foo OBJECT foo.c)

Otherwise (at least in the way CMake currently works) any symbols defined
in foo.a STATIC lib will *stay* in it. So in the end when you link an
executable
using bar.so SHARED lib only (which is using foo.a) then you won't have the
symbol
you need from foo unless foo.a is added to the link line ? Am I right ?


> So: I need my shared library to export a combination of ALL the public
> interfaces of the static libraries it was built from, but not,
> obviously, export the static libraries themselves.
>

But how can you do that without either:

1) adding the static lib to any link line (including the one using bar)
2) *merging* foo.a *into* bar.so which should be what you achieve by
    making foo an OBJECT lib.



> On Sat, 2019-06-15 at 23:10 -0700, Craig Scott wrote:
> > 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.
>
> That simply does not make sense, from the point of view of how a
> program and a linker work (I understand it's how CMake works).
>
> Let me work backwards, starting with a fact that hopefully we can all
> agree on:
>
>    It is NEVER appropriate to put a static library into the
>    INTERFACE_LINK_LIBRARIES of a shared library.
>
> I'd be interested to hear counter-arguments, but even if there are any
> reasons for it my position is that in those very rare cases you should
> be listing the static library in the TLL of the executable directly.
>

Correct me if I'm wrong but you are saying that TLL(bar.so foo.a)  should
merge foo.a into bar.so ?
But TLL(myexe foo.a) should add foo.a in the link line of myexe?


> If we can agree on that, then using the current rules of CMake
> inheritance this implies that we can NEVER add a static library as a
> PUBLIC TLL for a shared library.
>

Exactly my point. I understand what you say, but if ever CMake was doing
that
you simply couldn't switch (GLOBALLY) from SHARED to STATIC
using https://cmake.org/cmake/help/v3.14/variable/BUILD_SHARED_LIBS.html
is a single SHARED lib was explicitely specified.

My opinion is that CMake may handle TLL(SHARED STATIC) differently than
TLL(SHARED SHARED) but forbidding the first would be a major headache when
you want to go from STATIC to SHARED lib one step after another (I have a
concrete
example in mind in a legacy project).

Even if I agree that this is a very bad idea
"to put a static library into the INTERFACE_LINK_LIBRARIES of a shared
library"

it currently works with CMake a may be saving a lot of time to many people
switching
gradually from a legacy build system doing just that.


> Which seems, to me, quite ridiculous because why shouldn't you want to
> allow INTERFACE_COMPILE_DEFINITIONS, INTERFACE_COMPILE_OPTIONS, and
> INTERFACE_COMPILE_DIRECTORIES of the static library to be inherited by
> the shared library into its PUBLIC interface?  That seems like a quite
> reasonable thing to want to do.
>

I don't follow, it seems to be that case when the shared lib TLL publicly
to the static lib?
I really think think the behavior you are expecting already works if you
replace your static lib with object lib.
https://cmake.org/cmake/help/v3.14/command/target_link_libraries.html#linking-object-libraries

But may be I missed something?

-- 
Eric
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://cmake.org/pipermail/cmake/attachments/20190616/db6c77c4/attachment.html>


More information about the CMake mailing list