Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to embed copies of static library?

Here is structure of my solution:

enter image description here

A.lib defines:

int a(void) { return 1; }

B.lib defines:

int b(void) { return a(); }

C.lib defines:

int c(void) { return a() * 2; }

SharedStaticLibsTest.exe defines:

int main(void) { std::cout << b() + c() << std::endl; return 0;}

I decided to check (via DumpBin) code embeded to result application. It turns out that B and C libraries use the only instance of A library. Is there any way (for educational purposes) to use two different instances of A inside B and C? Maybe there is specific option of linker for this stuff? I understand, that such behavior may have unexpected side effects, which depend on logic of A library.

P.S. I replaced references to project by direct including .lib file within properties of project. Now B, C projects have a copy of A project. But final project still has the only copy of A library. I have no idea how does linker solve this issue.

like image 228
LmTinyToon Avatar asked Jan 17 '20 12:01

LmTinyToon


People also ask

How do I link a static library?

You should #include "libstatic. h" , i.e. use the appropriate header file in your code (that's why your code doesn't compile) and include the path to your libstatic. a in the linker options as one of your input libraries. This webpage has some examples on linking to a static library, e.g.

Can a DLL link to static library?

DLLs are executables. A statically linked app has its own copy of the library. A DLL can be used simultaneously by many apps. Static-link libraries can have code and data.

What happens when you link a static library?

Static Linking and Static Libraries is the result of the linker making copy of all used library functions to the executable file. Static Linking creates larger binary files, and need more space on disk and main memory.


1 Answers

First of all, if you ever end up with two instances of A in the build, all exported identifiers from A need to follow the One-Definition-Rule.

That is, even if you can technically have two different versions of A, unless they are for all intents and purposes identical, your program is invalid and neither the compiler nor the linker is obliged to tell you (the C++ standard calls this ill-formed, no diagnostic required). In practice this means you will have very weird bugs in your program and no clue where they come from.

That being said, technically there's nothing that stops you from constructing situations like the one you ask for. Normally static dependencies are only being processed at the linking stage. So a static library B depending on another static library A will not cause the one to export symbols from the other - B will not contain any symbols from A.

Instead your build system will track that dependency and as soon as you arrive at a linker stage (eg. by building an executable that depends on B), the build system will take care that both libraries get linked. That also means that if you don't have a build system, or configure your build incorrectly, you will get a linker errors for missing the symbols from the A library, even though you link against B and C explicitly.

So the canonical, portable way of duplicating symbols requires pulling them in through dynamic libraries, because those pass through the linker. If you change B and C to be dynamic libraries, they will both link against A and contain their own separate versions of the used functions from A. If you changed A between building B and C, they will contain different definitions. Hopefully your build system will try to prevent that from happening. Note that the C++ standard does not have a whole lot to say about dynamic libraries, so for the technicalities of how symbols get resolved here and what the effect of duplicated symbols is going to be, refer to your operating system's manual.

With MSVC, there is the additional possibility to do this for static libraries as well. In the project properties for B or C, head to Librarian -> General and set the Link Library Dependencies option to Yes. Now if you rebuild and look at the dumps for the B.lib and C.lib again, they should contain the symbols from A as well. Of course when building the resulting executable, the linker will pick either the version from B or from C (or also from A directly, depending on how you're linking) for each of A's symbols that is being used. Please don't do this in production.

like image 190
ComicSansMS Avatar answered Oct 25 '22 10:10

ComicSansMS