12

Let's say I have library (A) implementing the singleton pattern (it has a static variable in its implementation).

(A) library is compiled as a static library.

Now, let's say I have in my probject:

  • (B), another static library linking statically with (A).
  • (C), another static library linking statically with (A).
  • (D), a top level program linking with (B) and (C).

In the end, is my singleton really a singleton (and my variable really static)? Are (B) and (C) seing the same static variable from (A) (is it unic)? Or does the fact that (A) was statically linked twice embedded (A)'s code twice ending up with my static variable from (A) appearing twice in the final binary code? Then if (B) modifies the static variable value, (C) would not see the change?

Note: I experienced that when changing the libraries of project to be linked statically instead of dynamically. I'm just wondering if I did something wrong, or if that's a normal known behaviour.

jpo38
  • 20,821
  • 10
  • 70
  • 151
  • 5
    A static library is basically only an archive of object files, which gets linked into the output file like any other object file. – Some programmer dude Apr 28 '16 at 08:21
  • (D) would have to link against (A) also if it requires symbols from (A). (B) and (C) do not contain (A's) code. It would be different if (B) and (C) were dlls/sos instead. – Mohamad Elghawi Apr 28 '16 at 08:24
  • Your first two steps don't make sense. Static libraries are collections of object code modules; they're not "linked" to other static libraries. They're simply "there". When building (D), I don't see how linking only (B) and (C) will result in a final production. When pulling in a static lib that requires another static lib, it is the responsibility of the puller (the linking of the executable) to fill in the blanks (in this case, also link in (A)), which should tell you something about how many (A)'s are in your final production. – WhozCraig Apr 28 '16 at 08:25
  • @WhozCraig: To solve this problem, I ended with `(D)` linking to `(A)`, `(B)` and `(C)`. But I remember experiencing a situtation where `(B)` and `(C)` was not seeing the same value of `(A)`'s static variable (`(B)` would write a value here, and `(C)` would not see the value changed). As far as I remember, I experienced that when `(A)` was linked by both `(B)` and `(C)`....but it's difficult for me to reproduce that now. – jpo38 Apr 28 '16 at 08:30
  • @jpo38 that would happen if (B) and (C) were *dynamic* modules (DLL, .so, whatever) and (A) was a *static* lib. Said-same configuration would also allow your stated (D) links only to (B) and (C), so long as (D) didn't directly use resources solely in (A). – WhozCraig Apr 28 '16 at 08:32
  • @WhozCraig: Everything was static by then (I had troubles linking dynamic libraries, it was under iOS). See TarmoPikaro answer, for him you could end up with `static` variable being "cloned" in final binary...is that wrong? – jpo38 Apr 28 '16 at 08:34
  • @jpo38 What he's describing is replicating *source code* inclusion in multiple static libraries, which was *not* part of your question. And regarding your comment, "(A) was linked by both (B) and (C)" - no, it wasn't; not if everything is *really* static-libs. The only "linking" is done by the final production of the module if it is as you say, and everything else is static. A,B,C are all just packed up object code archives; making it more convenient than toting around stacks of .o files. – WhozCraig Apr 28 '16 at 08:37
  • @WhozCraig: OK, thanks for the clarification. When you say `no, it wasn't`, is this really impossible? I was compiling with QtCreator, and I had `LIB += A.a` in both B.pro and C.pro files. Now I don't know how this was handled by g++ in the end. – jpo38 Apr 28 '16 at 08:48
  • @jpo38 turn on verbosity in your make system and see what commands are actually executed. I'm betting `LIB` is never even *used* when building static libs B and C (or if it is, it has no effect) as building the static libs should just be ganging together the object code of the respective modules for each lib). Btw, Mohamad has a valid case where *header file* declaration of statics *can* lead to rampant duplication. Worth thinking about. – WhozCraig Apr 28 '16 at 08:52

3 Answers3

8

First of all:

(B) and (C) do NOT link against (A). Static libs are compiled, not linked. When building (B) and (C) the compiler might need to see certain definitions from (A) but do not confuse this with linking. (A's) code is not copied into (B) or (C).

Secondly:

(D) will have to link against (A), (B) and (C). That means you get only one copy of (A's) code in (D).

Dynamic-link Library/Shared Object:

This of course would be different if (B) and (C) were dlls/sos instead. Dlls are linked and so if you build (B) and (C) as dlls and link them against (A) then you would have a separate copy of (A's) code in both (B) and (C).

Are (B) and (C) seing the same static variable from (A)

This depends on if your variable has external or internal linkage. The following header file contains a static int variable with interal linkage. This means that every translation unit that includes this file will get it's own copy of myVariable.

//MyHeader.h
#pragma once
static int myVariable = 0;
Mohamad Elghawi
  • 2,071
  • 10
  • 14
  • Thanks Mohamad, it makes sense. – jpo38 Apr 28 '16 at 09:00
  • Do you know how to give external linkage to a static member variable in a static lib under Msvc? Or if not possible to force D to use a function of A that has already been included in B or C? – S. Paris May 21 '17 at 18:55
3

static linked library, and static variables are not related.

A static variable, is not visible outside the current compilation scope (no symbol name is created in the .o file, so no other .o files can find that variable via the symbol name).

This means that the variable

static int foo; can exist in every compilation scope, and each one will be uniqe

Stian Skjelstad
  • 2,277
  • 1
  • 9
  • 19
0

Your static variable is really static. I suspect that even if (B) links (A), (B) does not pick up it's own copy of (A) - instead it contains information that (A) should be linked.

It's however possible to compile same source code with static variable in two libraries - for example:

test.cpp:

int g_myGlobal = 23;

and compile it in (A) and (B) static libraries, but then when linking whole application or dll - you will get linker error about double defined static variable.

If you however declare variable with static keyword:

test.cpp:

static int g_myGlobal = 23;

Then if same source code is linked from (A) and (B) - it will be compiled and linked ok, but as a result you will have two instances of g_myGlobal variable (which can be even different).

TarmoPikaro
  • 4,723
  • 2
  • 50
  • 62