10

I have the following setup:

  1. A static library
  2. A dynamic library that links to (1.)
  3. An executable that links to (1.) and (2.)

The code from the from the static library is now duplicated and present in the dynamic library and the executable.

Questions:

Is the Data (global variables, static class members) also duplicated and does the executable and the dll see the same data?

Is there a difference between Linux and Windows?

How would you solve this?

Edit:

Thanks for the answers, I can now explain what happened in my case exactly.

The static library had no export/import flags. The dynamic library had export on its own symbols.

Windows:

The dynamic library had a copy of the text+data segement of the static library. The executeable couldn't know, that the dynamic library had linked the static library, because non of the static-library symbols are visible from the outside.

Linux:

The dynamic library had a copy of the text data segment of the static library and included all symbols (text and data) from the static library in its own symbol table. -> The executable sees, that the dynamic library has already defined all symbols of the static library and does not redefine them.

This is bad because you usually want the same behavior on linux and on windows.

  1. Share symbols (default on linux)
  • Add a dll export command on all symbols from the static library when linking it to the shared library. __attribute__ ((dllexport))
  • Add a dll import command when linking the static library to the executable. __attribute__ ((dllimport))
  • The code and data resides only in the shared library and is linkable from the outside
  1. Reduntant symbols (default on windows)
  • You need to make sure that the symbols of the static library are not included in the symbol table of the shared library
  • __attribute__ ((visibility ("hidden"))) on gcc
  • When linking the executable the symbols from the static library can't be found anywhere, so they are included again.
samlaf
  • 425
  • 4
  • 9
dari
  • 2,255
  • 14
  • 21
  • 1
    yes, the data is duplicated. You would solve it by using a dynamic library. – UmNyobe Jul 03 '15 at 15:01
  • @UmNyobe: there's already a DLL; creating another would be of no help as it won't share global data with the first. –  Jul 03 '15 at 16:00
  • Are the libraries precompiled or available as source code ? –  Jul 03 '15 at 16:18

2 Answers2

8

As far as I know, it depends on the operating system (because C++ language doesn't say much about how libraries should work).

On windows, you'll get twice the code and data, and worse of that all twice the global variables declared in that library (!)

This issue shows up when linking statically the standard library in a program and a library using that, when you get two default allocators and if you call new on a library and delete on the other, the object will leak on the new side and the heap is likely to become corrupted on the delete side.

I do not know the details about other operating systems, but I expect similar issues may arise

pqnet
  • 6,070
  • 1
  • 30
  • 51
  • 1
    +1 for the new/delete trick: I suffered this in the past and quickly learned to avoid using heterogeneous builds. –  Jul 03 '15 at 15:59
  • If all the library calls are _functional_ (that is, they do not observe or modify any global status) it is ok to use static linking, because the code may be more efficient/small (only the symbols you are using are included), in all other cases I suggest against it – pqnet Jul 03 '15 at 16:06
  • It seems like that on Linux somehow the data is not copied. http://stackoverflow.com/questions/4925233/global-variable-has-multiple-copies-on-windows-and-a-single-on-linux-when-compil – dari Jul 03 '15 at 16:09
  • 1
    @dari I just tested this, and if you configure the linker not to export the symbols from the static library (which I could do with not so small effort at https://gist.github.com/pqnet/7cb2a61c9c88f607bb63 ) you get a similar effect in linux and mac os. – pqnet Jul 03 '15 at 17:14
  • 1
    One way to spot this kind of issues is with valgrind. It will report an "Invalid free", followed by the code location that allocated the variable (e.g. the global), and two code locations that tried to free it. If you look at the two frees, they'll very likely point at two different libraries, which is the giveaway that the same code is there twice, and running incorrectly. – javs Oct 22 '19 at 21:35
0

IMO this is a nasty situation, as there are two executables (the exe and the dll) each with their instance of the code and global data. They are built independently and cannot share their memory mapping.

An option could be to let the dll expose the required members of the static library so that the exe can link to them directly.

  • Did i understand your answer correct: Re-declare all variables and functions from the static library in the dll, so that the executable doesn't have to link to the static library. – dari Jul 03 '15 at 16:07
  • Yep, that's what I mean, hoping that the linker will agree. The header of the library would exist in three versions: standard for compiling the static, export to build the dll and import for the exe. –  Jul 03 '15 at 16:20