33

I have a C++ application that I inherited, which consists of:

  • My main app
  • Several app-specific libraries (libapp1, libapp2, etc...)
  • Several "third party" libraries (most "third partis are just other teams in the company") linked from both the main app, from the app-specific libappX libraries, and from other 3rd part libraries - e.g. libext1, libext2, etc...

In other words, my code looks like this:

// main.C
#include <app1/a1l1.H>
#include <app2/a2l1.H>
#include <ext1/e1l1.H>

// app1/a1l1.H
#include <app1/a1l2.H>
#include <ext2/e2l1.H>

// app2/a2l1.H
#include <ext2/e2l2.H>

// ext1/e1l1.H
#include <ext3/e3l1.H>

// ext3/e3l1.H
#include <ext4/e4l1.H>

QUESTIONs:

1) How can I tell which libraries have been linked into the final executable? This must include statically linked ones

In other words, I want an answer of "app1, app2, ext1, ext2, ext3, ext4"

Ideally, the answer would be available from the executable itself (I have a debug version of it built in case it makes it more possible). If that's impossible, i'd like to know if there's a simple code analysis tool (iedeally something within gcc itself) to provide that analysis.

Please note that the object files for external libraries are already built, so looking at the build logs to see what was linked, I'm worried that "ext4" won't show up in the log since we won't be building "ext3" library that is already pre-built.

NOTE: running "nmake" with DEPS set to yes to rebuild all the is NOT an option. But i DO have access to the full source code for external libraries.

2) A slightly separate and less important question, how can i tell a list of all the include files used in the entire source tree I'm building. Again, ideally frm already-built executable, which i have a debug version of.

=================

UPDATE: Just to clarify, our libraries are linked statically, so ldd (List Synamic Dependencies) does not work.

Also, the answer can be either for Solaris or Linux - doesn't matter.

I tried using nm but that doesn't list the libraries

DVK
  • 126,886
  • 32
  • 213
  • 327

6 Answers6

44

I had similar problem and found solution: add -Wl,--verbose option when linking. It will switch linker to verbose mode:

gcc -o test main.o -ltest -L. -Wl,--verbose

Here is example output:

GNU ld (GNU Binutils) 2.23.52.20130604
  Supported emulations:
   i386pep
   i386pe
using internal linker script:
==================================================
/* Default linker script, for normal executables */
[many lines here]
==================================================
attempt to open /usr/lib/gcc/x86_64-pc-cygwin/4.8.2/../../../../lib/crt0.o succeeded
/usr/lib/gcc/x86_64-pc-cygwin/4.8.2/../../../../lib/crt0.o
attempt to open /usr/lib/gcc/x86_64-pc-cygwin/4.8.2/crtbegin.o succeeded
/usr/lib/gcc/x86_64-pc-cygwin/4.8.2/crtbegin.o
attempt to open main.o succeeded
main.o
attempt to open ./libtest.dll.a failed
attempt to open ./test.dll.a failed
attempt to open ./libtest.a succeeded
(./libtest.a)test.o
[more lines here]
attempt to open /usr/lib/gcc/x86_64-pc-cygwin/4.8.2/crtend.o succeeded
/usr/lib/gcc/x86_64-pc-cygwin/4.8.2/crtend.o

Update: You can also use -Wl,--trace option instead of -Wl,--verbose. It will also give you list of libraries, but is less verbose.

Update 2: -Wl,--trace does not display libraries included indirectly. Example: you link with libA, and libA was linked with libB. If you want to see that libB is needed too, you must use -Wl,--verbose.

Daniel Frużyński
  • 2,091
  • 19
  • 28
  • 2
    As a note for followers, the ".o" files `ld` lists for a library (i.e. those listed after it says `attempt to open libXX succeeded`) will not be "all" the .o files in a library, only the ones it requires to satisfy dependencies at that point. The rest are in essence discarded, even though present in the .a file. ref: http://stackoverflow.com/q/14091669/32453 – rogerdpack Jan 08 '16 at 01:21
  • Is there an easy way to do this in Visual Studio 2017? – Yuriy F Dec 01 '18 at 22:17
  • @YuriyF: I tried to google for this and found that MSVC has /VERBOSE option: https://learn.microsoft.com/en-us/cpp/build/reference/verbose-print-progress-messages?view=vs-2017 . Please check if it will work for you, I do not have MSVC to test it. – Daniel Frużyński Dec 03 '18 at 09:14
  • Visual studio is a broken piece of beep. – Martin Mar 29 '19 at 06:59
17

For direct dependencies;

ldd <app>

Indirect/All dependencies;

ldd -r <app>
ismail
  • 46,010
  • 9
  • 86
  • 95
3

As far as I know, not much information about static libraries is preserved when linking (since the linker just sees that library as a collection of *.o objects anyway).

If you find the make command that links the final executable and add a -v flag, g++ will show you exactly how it calls the ld command. This should include all necessary static libraries, including libraries used by other libraries, or otherwise the link step would fail. But it might also include extra libraries that aren't actually used.

Another possibly useful thing is that, at least on Linux, objects and executables usually store names of the source code files from which they were created. (Filename only, no path.) Try

objdump -t executable | grep '*ABS*'
aschepler
  • 70,891
  • 9
  • 107
  • 161
  • objdump seems to produce output very similar to `nm` and deosn't realy produce library lists. Can I pass "-v" via a command line switch to nmake? Thx – DVK Feb 07 '11 at 19:10
  • @DVK: AT&T nmake? Microsoft nmake? In any case, probably no. You want to find the last `g++` command which the make process did or would call, then add -v to that. – aschepler Feb 07 '11 at 19:20
  • gotcha. I think it already does that by default since I think I see a list of all .a files in g++ command line – DVK Feb 07 '11 at 19:21
0

I'll answer your second question first. You can simply use the -H or -M flag to see all (including system) headers processed in the compilation. gcc -H main.c should do the trick. Seeing which headers are included will actually get you on the right track to finding which static libraries were linked in.

You could use objdump on your final object (or readelf on your final binary) to get the names of all the functions in there. You'd then have to go find the libraries from which the functions were pulled in, but that's a bit cumbersome. You'd definitely have to make a script to minimize the pain.

Someone else mentioned using gcc <stuff> -Wl,-verbose which simply passes the -verbose flag to the linker. That's a perfect way to get a list of shared libraries (.so files), but you said yours are static, so that isn't the way to go in this case.

Good luck!

s g
  • 5,289
  • 10
  • 49
  • 82
0

Try to use ldd + your filename, this will list the libs.

kohlehydrat
  • 503
  • 1
  • 3
  • 19
  • 1
    Sorry for not clarifying this earlier, the libraries are linked statically. `ldd` doesn't list those. – DVK Feb 07 '11 at 18:47
0

Here's what I use to generate link-time dependencies:

-include .deps/TARGET.d

$(TARGET): $(OBJECTS)
    @echo " LINK $(TARGET)"
    @echo '$$(TARGET): \' > .deps/TARGET.d
    @$(CXX) -o $(TARGET) $(OBJECTS) $(LDLIBS) -Wl,--trace | sed -r -e "s#.*\(($(MY_LIB_DIR)).*)\).*#\t\\1 \\\\#p;d" | sort | uniq >> .deps/TARGET.d

it generates a .deps/TARGET.d file that looks like this:

$(TARGET): \
    /home/user/project/lib/lib1.a \
    /home/user/project/lib/lib2.a \
    /home/user/project2/bin/lib3.so \

Spongman
  • 9,665
  • 8
  • 39
  • 58