0

I'm studying how the C++ linker (gnu linker here) resolves dependencies
between static libraries and shared libraries and stuck in a question as below for a while

There are 3 files as below

  • main.cpp (which depends on foo.cpp)
  • foo.cpp (which depends on boo.cpp)
  • boo.cpp
// main.cpp
#include <iostream>

extern int foo();

int main()
{
  std::cout << foo() << std::endl;
}

// foo.cpp
extern int boo();

int foo()
{
  return boo();
}

// boo.cpp
int boo()
{
  return 10;
}

If I make foo.cpp and boo.cpp as libraries and link them with main.cpp to make an executable
Then the result varies in four different cases as below
Why only the first one fails, and others succeed?
Making a static library from static libraries can't resolve the dependency by itself?

(1) build fail

# static library boo
$ g++ -static -c -o boo.o boo.cpp
$ ar rcs libboo.a libboo.o

# static library foo
$ g++ -static -c -o foo.o foo.cpp -lboo -L.
$ ar rcs libfoo.a foo.o

# pass libfoo.a only for the executable
$ g++ -o a.out main.cpp -lfoo -L.

/usr/bin/ld: ./libfoo.a(libfoo.o): in function `foo()':
foo.cpp:(.text+0x9): undefined reference to `boo()'
collect2: error: ld returned 1 exit status

(2) build success

# static library boo
$ g++ -static -c -o boo.o boo.cpp
$ ar rcs libboo.a libboo.o

# static library foo
$ g++ -static -c -o foo.o foo.cpp -lboo -L.
$ ar rcs libfoo.a foo.o

# pass libfoo.a and libboo.a for the executable
$ g++ -o a.out main.cpp -lfoo -lboo -L.

(3) build success

# static library boo
$ g++ -static -c -o libboo.o boo.cpp
$ ar rcs libboo.a libboo.o

# shared library foo
$ g++ -shared -fpic -o libfoo.so foo.cpp -lboo -L.

# pass libfoo.so only for the executable
$ g++ -o a.out main.cpp -lfoo -L.

(4) build success

# shared library boo
$ g++ -shared -fpic -o libboo.so boo.cpp

# shared library foo
$ g++ -shared -fpic -o libfoo.so foo.cpp -lboo -L.

# pass libfoo.so only for the executable
$ g++ -o a.out main.cpp -lfoo -L.
hyuk myeong
  • 197
  • 1
  • 13

1 Answers1

1

When compiling (-c option is present), -static -L -l<lib> options have no effect. Static libraries cannot carry dependencies on other libraries.

To fix your build error correct commands are:

# static library boo
$ g++ -c -o boo.o boo.cpp
$ ar rcs libboo.a libboo.o

# static library foo
$ g++ -c -o foo.o foo.cpp
$ ar rcs libfoo.a foo.o

# link both libfoo.a and libboo.a
$ g++ -o a.out main.cpp -lfoo -lboo -L.
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • First of all, thank you for your answer, And so does it mean that all static libraries which have dependencies each other have to be on command line for the executable, right? – hyuk myeong Jan 05 '21 at 10:42
  • @hyukmyeong You are right. Normally, a build system maintains a list of dependencies for a static library, so that when you link it it also links in all its dependencies. – Maxim Egorushkin Jan 05 '21 at 11:00
  • Thank you, It is clear now! So static libraries cannot be merged by the compiler and it can be only done by other tools as describe https://stackoverflow.com/questions/3821916/how-to-merge-two-ar-static-libraries-into-one – hyuk myeong Jan 06 '21 at 14:45
  • @hyukmyeong Static libraries are just multiple object files in one with a special linker handling. Unlike ELF executables and shared libraries (one file can be both) which can refer to other ELF files they need. – Maxim Egorushkin Jan 06 '21 at 14:53
  • Yeap, I was aware of that part, thank you very much – hyuk myeong Jan 06 '21 at 14:56