Embed All External References When Creating a Static Library

Embed all external references when creating a static library

On Linux, shared libraries can be made by also linking other shared libraries inside them. So you could

  1. Compile all source code (including the C wrapping code) with -fPIC into *.pic.o files
  2. Merge all these files into a shared library linking needed libraries, e.g.

    g++ -shared *.pic.o -o libmy.so -lQt -lrt -lstdc++

Then you can use simply your libmy.so as gcc main.o -L. -lmy and this will link the other libraries.

Look for example at Parma Polyhedra Library, it has a libppl_c.so in C wrapping a libppl.so in C++. Use ldd to list the dependent libraries:

 % ldd /usr/lib/x86_64-linux-gnu/libppl_c.so.4
linux-vdso.so.1 => (0x00007fffa17cf000)
libppl.so.9 => /usr/local/lib/libppl.so.9 (0x00007fcfec5f1000)
libpwl.so.5 => /usr/local/lib/libpwl.so.5 (0x00007fcfec3ed000)
libgmpxx.so.4 => /usr/lib/x86_64-linux-gnu/libgmpxx.so.4 (0x00007fcfec1c5000)
libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007fcfebf56000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fcfebc4f000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fcfeb9cc000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fcfeb645000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fcfeb42f000)
libgmp.so.3 => /usr/lib/libgmp.so.3 (0x00007fcfeb1d2000)
/lib64/ld-linux-x86-64.so.2 (0x00007fcfecf11000)

This is on Debian/Sid/AMD64

A general advice is to avoid building static libraries (using ar and possibly ranlib). Build shared libraries instead.

You cannot do equivalent things on static libraries because a static library is simply a sequence of object files, nothing more. (there is no metadata space for the dependency information you dream about).

Linking static libraries to other static libraries

Static libraries do not link with other static libraries. The only way to do this is to use your librarian/archiver tool (for example ar on Linux) to create a single new static library by concatenating the multiple libraries.

Edit: In response to your update, the only way I know to select only the symbols that are required is to manually create the library from the subset of the .o files that contain them. This is difficult, time consuming and error prone. I'm not aware of any tools to help do this (not to say they don't exist), but it would make quite an interesting project to produce one.

undefined references when linking own static library that itself depends on static libraries

Your executable needs to link against all the relevant libraries, including the ones it directly depends on, plus the ones it indirectly depends on. When you link a static library you typically do not embed other static libraries within it.

How to embed copies of static library?

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.

linking library for creating static library

First of all, all libraries are normally named something like libxyz.a where xyz is the name of the library.

Secondly, you try to create a program using only the object file you used for the library, and also linking it with itself. This will of course not work, since the library have no main function which is needed for normal programs. You have to create another program, and link that one with the library.

Like

gcc myotherprogram.c -o myotherprogram -L/some/path -lxyz

As you can see in my command line above, I placed the library last on the command line. It's needed because the linker look for dependencies in kind of reversed order.

Edit: Linking your static library with other libraries: You don't. A static library is completely standalone, and if it needs other libraries itself to work then they have to be present on the command line when compiling the actual program.

For example, lets say that library xyz depends on the standard math library (i.e. the m library). You can't "link" with it when creating the xyz library as you don't actually link static libraries, you just put a collection of object files together in an archive (ar and the .a extension is for archive). When you build the actual application that needs the xyz library you also needs to link with whatever libraries that xyz needs:

gcc myotherprogram.c -o myotherprogram -L/some/path -lxyz -lm

Proper way to link static libraries with dll

Static libraries should not contain any __declspec or __attribute((dll...)) things. They are nothing more than multiple object files (usually *.obj or *.o), composed into one, single file.

All you need to do in order to use such library (either in .exe or .dll) is to include proper headers and link them - with Visual Studio it's pretty easy.

First of all, you need to know 1) where your static libraries are placed and 2) their exact names. Go to project properties and then General. Target name contains name for the output file, while Output directory indicates in which folder your .lib will be placed.

Note: This path may be different for every project! For multi-project solution, I always set this to a common path to avoid configuration problems.

Now, go to properties of project, that will consume this library (link with it). Go to Linker -> Input and then add name of your .lib to Additional dependencies (entries are separated with semicolon):

Linker input

You need to add all libraries you want have linked in. Also, folder, in which these libraries are placed, must added to Linker -> General -> Additional library directories. If all .libs are placed in the same place - good, otherwise copy them into shared location or add multiple entries to Additional library directories list.

And the last thing - remember, that you also need to include headers with declarations of functions and objects, that you want to use. Basic thing, I know, but has to be mentioned.


UPDATE

unresolved external when trying to use dll library in an external prodjects

Your problem is not related to linking at all. The thing is, that you misunderstood what, linking a static library exactly does.

I am guessing, that functions reported as unresolved are not used by your DLL, right? But you expect them to be inside it, right?

When your DLL refers to an external content (like function or variable), it is resolved at linking time - together with all dependencies. But that's all. If your static library has a function named print_sample_string(), but your DLL does not use it, it won't be attached to DLL image. Think about this carefully - why should it be?

Even more - functions, that are not dllexported explicitly won't be visible anyway. Functions have by default external storage - so basically, they are private DLL's content.

So to answer your question directly - if you need to use functions/variables from static_lib1.lib, attach it to client application - just like you are attaching it now to dynamic_lib. There is no other way. (*)


(*) Truly speaking - there is. You can create intermediate function in DLL, that is exported and call desired function inside:

Somewhere in dynamic_lib:

DLL_EXP_IMP long CallFunctionFromA_Lib()
{
return some_function(); //this function is from static_lib1.lib
}

Somewhere in .exe:

long result = CallFunctionFromA_Lib(); //internally this will call function from static_lib1.lib

I can't imagine, however, why would you want to do this and not simply link A.lib and use it directly.

Static library included, but symbols unresolved

Why not:

prog_LDADD = libmy.a libthird.a

you should also omit:

libmy_a_LIBADD = libthird.a

in this case because libmy.a is a static convenience library, so there's no real point to further linking it.



Related Topics



Leave a reply



Submit