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

Paul Smith paul at mad-scientist.net
Sun Jun 16 19:15:45 EDT 2019


On Sun, 2019-06-16 at 21:42 +0200, Eric Noulard wrote:
> Le dim. 16 juin 2019 à 18:26, Paul Smith <paul at mad-scientist.net> a
> écrit :
> > 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. 
> 
> 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.

Yep, I'm familiar with OBJECT libs and if I could use them they would
give the correct behavior, you're right.  Unfortunately it's not the
case that OBJECT libraries are completely "drop-in" replaceable for
STATIC libraries, and they cannot be substituted in my environment.

See, for one example:
https://gitlab.kitware.com/cmake/cmake/issues/19388

I am not able to rework my system comprehensively enough to remove all
mutual references between all my current libraries.  And there are
other issues where OBJECT libraries aren't the equivalent of STATIC
libraries.

> 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?

No, that's not right.

The visibility of symbols depends on how your code is compiled and has
nothing to do with cmake and whether cmake links into a shared or
static library.

On POSIX systems (gcc and clang), all symbols are public by default
regardless of whether you are compiling them for a static or shared
library.

On Windows it's all more complicated, but in my situation I've added
the WINDOWS_EXPORT_ALL_SYMBOLS property to my libraries.

> 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.

I'm not sure what you mean by "merging foo.a into bar.so": you can't
merge something into a shared library any more than you can merge
something into an executable.  By putting "foo" into the TLL of "bar",
I've added the static library to the creation of the shared library:

  cc -shared -o bar.so bar.o libfoo.a

Now when bar.so is created it will have the required contents of
libfoo.a in it.
 
> > 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.

I wasn't familiar with that option, but I don't think it makes a
difference whether the libraries are made SHARED via this option or
whether they are made SHARED via direct specification: the behavior is
the same.

> 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).

I didn't say it should be forbidden!!

I said that as cmake is currently implemented it doesn't make sense to
do it, implying that cmake might want to change its behavior in this
area to be more useful.


However, after more investigation I see that I was wrong about how
linkers resolve symbols at least in POSIX systems (I'm not sure about
DLLs on Windows... I haven't gotten there yet).

For some reason I remembered that a linker would prefer symbols found
in static libraries over those found in shared libraries, but in fact
the linker will always choose the implementation of the symbol in the
first library it's defined in regardless of the type of library.

So, as long as the shared library appears first on the link line it
shouldn't matter that the static library also appears there.

I still think it's incorrect to add the static library to the link
line, but (at least for linkers with semantics as above) it probably
doesn't actually hurt anything.



More information about the CMake mailing list