2

With GCC on Linux, is it possible to link a .a into another .a and then only link the resultant .a to my application? Or must my application know of the dependence between one archive and another and link them both?

My understanding is that I must know of the dependencies and link all archives at the end, not in an intermediary step, which seems a little ugly.

This is slightly different than How to merge two "ar" static libraries into one as I'm after a clear description that this is only possible by working around the problem and that linking the two archives together in the naive way is incorrect and will not work, along with the reason as to why.

Joe
  • 7,378
  • 4
  • 37
  • 54
  • 1
    Possible duplicate of [How to merge two "ar" static libraries into one](https://stackoverflow.com/questions/3821916/how-to-merge-two-ar-static-libraries-into-one) – Mike Kinghan Jun 13 '17 at 09:18
  • Your added explanation of why this question is not a duplicate is very unclear. What is "linking the two archives together the naive way"? – Mike Kinghan Jun 13 '17 at 10:38
  • I'm probably being a language lawyer, but an archive is not linked to an archive. The final program or shared object is linked, and the source objects can be object files (like `foo.o`), collections of object files (`libbar.a` with `bar.o` and `baz.o` as members), or a shared object (like `baz.so`). Keep in mind an archive (`*.a`) is just a collection of object files `*.o`). There's nothing special about them, and you could link against every `*.o` individually to achieve the same effect. – jww Jun 13 '17 at 14:11
  • 1
    @MikeKinghan By saying "the naive way" I think he means without needing to extract and then combine again archives. Just "regular" compilation. – SHG Jun 13 '17 at 15:05
  • Correct. I can work around the issue in a variety of ways, but it seems like a natural thing to want to do. Hence I wanted to be sure my understanding was correct and would like to understand why it is the case. So I'm more after why than how. The possible dup question is a how not a why. – Joe Jun 13 '17 at 15:09
  • I added a more "why" explanation. Hope it's clearer now. – SHG Jun 13 '17 at 15:49

2 Answers2

1

Let libx.a and liby.a be the modules you want to combine. You can try:-

mkdir tmp                 # create temporary directory for extracting 
cd tmp
ar x ../libx.a            # extract libx.a
cp ../liby.a ../libxy.a
ar -q ../libxy.a *        # add extracted files to libxy.a
cd ..
rm -rf tmp

libxy.a thus created contains .o files from both .a files

Meet Taraviya
  • 869
  • 1
  • 8
  • 27
1

Yes, your application has to know the dependencies between your different static libraries.

  • Let's say you have two static libraries a and b.
  • a has a function void print_a(), and b has a function void print_b() that is calling to print_a(). So, b depends on a.
  • Their binaries will look like liba.a and libb.a.

Let's say that library b has a reference to a function defined in library a - void print_b(void). When compiling library b only its symbols are defined in the binary's code section while the others are still undefined:

host$ nm libb.a | grep print
                 U _print_a          <--- Undefined
0000000000000000 T _print_b          <--- Defined, in code section
0000000000000068 S _print_b.eh
                 U _printf

Therefore, when compiling the application that wants to use both of the libraries, linking only to libb.a won't be enough. You'll have to link your application to both libraries. Each library will provide its own symbols addresses in the code section and then your application will be able to link to both.

Something like:

gcc -o main main.c libb.a liba.a

BTW: When compiling library b that uses a, you can but it's not necessary to link to a. The result will be just the same.


Why is this the behavior

When compiling + linking the application that uses static libraries, the symbols in the application source files have to be defined somewhere (with the exception of dynamic linking, but this is done only with dynamic libraries/shared objects. Here we deal with static ones).

Now, remember that a static library is just an archive of objects. When it's created there's no linking phase. Just:

  1. Compiling source code (*.c) to objects (*.o)
  2. Archiving them together in a libXXXX.a file.

It means that if this library (library b in my example) uses some function (void print_a(void)) that is defined in another library (a), this symbol won't be resolved (not as a compilation error, but as the normal behavior). It will be set as Undefined symbol (as we see in the output of nm command) after the library creation, and it will wait to be linked later to its definition. And it's OK because a static library is not executable.

Now returning to application - the linking phase of the application needs to find all the definitions of all the symbols. If you just gave it libb.a as an argument, it wouldn't be able to find the definition to print_a(), because it's not there, it's still undefined. It exists only in liba.a.

Therefore, you must provide both of the libraries.

SHG
  • 2,516
  • 1
  • 14
  • 20
  • So what is the point of being able to link one .a to another? I kind of imagined it as just a tarfile of the contents of both archives, which strikes me as a cheap way of avoiding linking each file separately. – Joe Jun 13 '17 at 15:55
  • @Joe There's no point in linking them one to another. As I wrote in the BTW comment - the result will be just the same and the symbols will be defined/undefined in the same way. – SHG Jun 13 '17 at 16:07