what's difference between --start-group and --whole-archive in ld - linker

To be honest, I think this question should be easy by staring at man ld. However, by reading manpage and read the code done by others, I find people use them interchangeably or at the same time when they think there might be an issue with the order of the libraries passed to the linker.
I'm wondering what's the difference between these two options and what's the best practice when using them.
Thanks!
Related links:
What are the --start-group and --end-group command line options?

At the time of writing, the Stackoverflow tag wiki on static libraries
tells us:
A static library is an archive of object files. Used as a linker input, the linker extracts the object files it needs to carry on the linkage.
The needed object files are those that provide the linker with definitions for symbols that it finds are used, without definition, in other input files.
The needed object files, and no others, are extracted from the archive and input to the linkage exactly as if they were individual input files in the
linkage command and the static library was not mentioned at all.
...
A linker will normally support an option (GNU ld: --whole-archive, MS link: /WHOLEARCHIVE) to override the
default processing of static libraries and instead link all the contained object files, whether they are needed or not.
A static library contributes nothing to a linkage except the object files that are extracted from it, which may be vary in different linkages.
It is to be contrasted with a shared library, another kind of file altogether with a very different role in linkage.
That should make it clear what --whole-archive does. The scope of --whole-archive continues until the end of
the linker commandline or until --no-whole-archive appears1.
By default, the linker will examine a static library only at each point where that library occurs in the commandline sequence of linker inputs.
It will not go backwards to rexamine a static library for the sake of resolving symbol references it discovers in later inputs.
The --start-group ... --end-group pair of options changes that default behaviour. It directs the linker to examine the static libraries
mentioned in ... repeatedly, in that order, for as long doing so yields any new resolutions of new symbol references. --start-group ... --end-group has no effect on
the linker's default selection of object files from the static libraries in .... It will extract and link only the object files that it needs, unless --whole-archive is also
in effect.
Summing that up:-
--start-group lib0.a ... libN.a --end-group tells the linker: Keep searching through lib0.a ... libN.a for object files you need until you don't find any more.
--whole-archive lib0.a ... libN.a --no-whole-archive tells the linker: Forget about what you need. Just link all the object files in all of lib0.a ... libN.a.
You can see then that any linkage you can make succeed with --start-group lib0.a ... libN.a --end-group will also succeed with --whole-archive lib0.a ... libN.a --no-whole-archive,
because the latter will link all of the necessary object files and all the unnecessary ones, without bothering to tell the difference.
But the converse isn't true. Here is a trivial example:
x.c
#include <stdio.h>
void x(void)
{
puts(__func__);
}
y.c
#include <stdio.h>
void y(void)
{
puts(__func__);
}
main.c
extern void x(void);
int main(void)
{
x();
return 0;
}
Compile all source files:
$ gcc -Wall -c x.c y.c main.c
Make a static library, archiving x.o and y.o:
ar rcs libxy.a x.o y.o
Attempt to link a program with main.o and libxy.a in the wrong order:
$ gcc -o prog libxy.a main.o
main.o: In function `main':
main.c:(.text+0x5): undefined reference to `x'
collect2: error: ld returned 1 exit status
That failed because the reference to x in main.o was only discovered
by the linker too late to find the definition of x in libxy.a(x.o). It reached libxy.a
first and found no object files that it needed. At that point, it hadn't yet linked
any object files at all into the program, so there were 0 symbol references it needed to resolve. Having
considered libxy.a and found no use for it, it does not consider it again.
The correct linkage, of course, is:
$ gcc -o prog main.o libxy.a
but if you don't realise that you simply have the linkage order back-to-front, you can
get the linkage to succeed with --whole-archive:
$ gcc -o prog -Wl,--whole-archive libxy.a -Wl,--no-whole-archive main.o
$ ./prog
x
Obviously, you can't get it to succeed with
$ gcc -o prog -Wl,--start-group libxy.a -Wl,--end-group main.o
main.o: In function `main':
main.c:(.text+0x5): undefined reference to `x'
collect2: error: ld returned 1 exit status
because that is no different from:
$ gcc -o prog libxy.a main.o
Now here's an example of a linkage that fails with the default behaviour, but can be
made to succeed with --start-group ... --end-group.
a.c
#include <stdio.h>
void a(void)
{
puts(__func__);
}
b.c
#include <stdio.h>
void b(void)
{
puts(__func__);
}
ab.c
extern void b(void);
void ab(void)
{
b();
}
ba.c
extern void a(void);
void ba(void)
{
a();
}
abba.c
extern void ab(void);
extern void ba(void);
void abba(void)
{
ab();
ba();
}
main2.c
extern void abba(void);
int main(void)
{
abba();
return 0;
}
Compile all sources:-
$ gcc -Wall a.c b.c ab.c ba.c abba.c main2.c
Then make the following static libaries:
$ ar rcs libbab.a ba.o b.o x.o
$ ar rcs libaba.a ab.o a.o y.o
$ ar rcs libabba.a abba.o
(Notice that those old object files x.o and y.o are archived here again).
Here, libabba.a is dependent on both libbab.a and libaba.a. Specifically,
libabba.a(abba.o) makes a reference to ab, which is defined in libaba.a(ab.o);
and it also makes a reference to ba, which is defined in libbab.a(ba.o).
So in the linkage order, libabba.a must occur before either libbab.a and libaba.a
And libbab.a is dependent on libaba.a. Specifically, libbab.a(ba.o) makes a
reference to a, which is defined in libaba(a.o).
But libaba.a is also dependent on libbab.a. libaba(ab.o) makes a reference
to b, which is defined in libbab(b.o). There is a circular dependency between
libbab.a and libaba.a. So whichever one of them we place first in a default linkage, it
will fail with undefined reference errors. Either this way:
$ gcc -o prog2 main2.o libabba.a libaba.a libbab.a
libbab.a(ba.o): In function `ba':
ba.c:(.text+0x5): undefined reference to `a'
collect2: error: ld returned 1 exit status
Or that way:
$ gcc -o prog2 main2.o libabba.a libbab.a libaba.a
libaba.a(ab.o): In function `ab':
ab.c:(.text+0x5): undefined reference to `b'
collect2: error: ld returned 1 exit status
A circular dependency is a problem to which --start-group ... --end-group is the solution:
$ gcc -o prog2 main2.o libabba.a -Wl,--start-group libbab.a libaba.a -Wl,--end-group
$ ./prog2
b
a
Therefore --whole-archive ... --no-whole-archive is also a solution:
$ gcc -o prog2 main2.o libabba.a -Wl,--whole-archive libbab.a libaba.a -Wl,--no-whole-archive
$ ./prog2
b
a
But it is a bad solution. Let's trace which of our object files are actually linked
into the program in each case.
With --start-group ... --end-group:
$ gcc -o prog2 main2.o libabba.a -Wl,--start-group libbab.a libaba.a -Wl,--end-group -Wl,--trace
/usr/bin/x86_64-linux-gnu-ld: mode elf_x86_64
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o
/usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o
main2.o
(libabba.a)abba.o
(libbab.a)ba.o
(libaba.a)ab.o
(libaba.a)a.o
(libbab.a)b.o
libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
/lib/x86_64-linux-gnu/libc.so.6
(/usr/lib/x86_64-linux-gnu/libc_nonshared.a)elf-init.oS
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
/usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o
they are:
main2.o
(libabba.a)abba.o
(libbab.a)ba.o
(libaba.a)ab.o
(libaba.a)a.o
(libbab.a)b.o
which are exactly the ones that are needed in the program.
With --whole-archive ... --no-whole-archive:
$ gcc -o prog2 main2.o libabba.a -Wl,--whole-archive libbab.a libaba.a -Wl,--no-whole-archive -Wl,-trace
/usr/bin/x86_64-linux-gnu-ld: mode elf_x86_64
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o
/usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o
main2.o
(libabba.a)abba.o
(libbab.a)ba.o
(libbab.a)b.o
(libbab.a)x.o
(libaba.a)ab.o
(libaba.a)a.o
(libaba.a)y.o
libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
/lib/x86_64-linux-gnu/libc.so.6
(/usr/lib/x86_64-linux-gnu/libc_nonshared.a)elf-init.oS
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
libgcc_s.so.1 (/usr/lib/gcc/x86_64-linux-gnu/7/libgcc_s.so.1)
/usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o
they are:
main2.o
(libabba.a)abba.o
(libbab.a)ba.o
(libbab.a)b.o
(libbab.a)x.o
(libaba.a)ab.o
(libaba.a)a.o
(libaba.a)y.o
The same as before, plus:
(libbab.a)x.o
(libaba.a)y.o
which are dead code (and there could have been more of it, without limit). The redundant functions x() and y() are defined in the image:
$ nm prog2 | egrep 'T (x|y)'
000000000000067a T x
00000000000006ac T y
Takeaway
Use default linkage, putting your inputs in dependency order, if you can.
Use --start-group ... --end-group to surmount circular dependencies between
libraries, when you can't fix the libraries. Be aware that linkage speed will take a hit.
Use --whole-archive ... --no-whole-archive only if you actually need to link
all the object files in all the static libraries in .... Otherwise, do one of
the previous two things.
[1] And be aware that the linker's commandline, when the linker is invoked
by GCC, is actually much longer than the linkage options you explicitly pass in
the GCC commandline, with boiler-plate options silently appended. Therefore
always close --whole-archive with --no-whole-archive, and close --start-group
with --end-group.

Related

Hiding symbols from a DSO with DT_FILTER

I was recently trying to hide some symbols from 3rd party DSO and came across "--filter" LD option for creating "filter DSO". From the ld manpage, I have an impression that the dynamic linker will only take into account symbols which are present in filter DSO's dynsym:
"The dynamic linker will resolve symbols according to the symbol
table of the filter object as usual, but it will actually link to the
definitions found in the shared object name."
So it looks just what I need: a way to select which symbols from a DSO take part in dynamic linkage. Unfortunately, it does not work as I expect (this example can also be cloned from github)
Makefile:
lib1.so: lib1.c
gcc -shared -fPIC $^ -o $#
lib2.so: lib2.c
gcc -shared -fPIC $^ -o $#
lib2f.so: lib2f.c
gcc -shared -fPIC -Wl,--filter,lib2.so $^ -o $#
main: lib1.so lib2.so lib2f.so main.c
gcc main.c -L. -l2f -l1 -o $#
clean:
rm *.o *.so main
lib1.c
#include <stdio.h>
void func1()
{
printf("func1#lib1\n");
}
void func2()
{
printf("func2#lib1\n");
}
lib2.c
#include <stdio.h>
void func1()
{
printf("func1#lib2\n");
}
void func3()
{
printf("func3#lib2\n");
}
lib2f.c (filter for lib2.so):
void func3() {}
Executable
void func1();
void func2();
void func3();
int main()
{
func1();
func2();
func3();
return 0;
}
When I run that test program, I get following output:
> LD_LIBRARY_PATH=. ./main
func1#lib2
func2#lib1
func3#lib2
One can see that a symbol from lib2 is actually referenced despite the attempt to "filter" it with lib2f.so. What I would like the output to look like is
> LD_LIBRARY_PATH=. ./main
func1#lib1 // use func1 from lib1
func2#lib1
func3#lib2
Is it at all possible to achieve my goal (hiding some symbols from a DSO) with ld --filter option (aka DT_FILTER)?
If not, what is wrong in my expectations/reading of man pages?
Described behavior occurs on glibc 2.34 and 2.17.
According to https://sourceware.org/bugzilla/show_bug.cgi?id=27977:
DT_NEEDED puts the referenced object after the current object in the search scope. DT_FILTER puts it before it. I believe this is the only difference in the current glibc implementation. There is simply no filtering. It has been this way since basically forever
I'm trying to achieve the same thing. Looks like this is sensitive to the link order. I moved the -l1 before -l2f, i.e., change your link line in the Makefile to
main: lib1.so lib2.so lib2f.so main.c
gcc main.c -L. -l1 -l2f -o $#
With that I get:
$ ./main
func1#lib1
func2#lib1
func3#lib2

What's the difference between `-rpath-link` and `-L`?

The man for gold states:
-L DIR, --library-path DIR
Add directory to search path
--rpath-link DIR
Add DIR to link time shared library search path
The man for bfd ld makes it sort of sound like -rpath-link is used for recursively included sos.
ld.lld doesn't even list it as an argument.
Could somebody clarify this situation for me?
Here is a demo, for GNU ld, of the difference between -L and -rpath-link -
and for good measure, the difference between -rpath-link and -rpath.
foo.c
#include <stdio.h>
void foo(void)
{
puts(__func__);
}
bar.c
#include <stdio.h>
void bar(void)
{
puts(__func__);
}
foobar.c
extern void foo(void);
extern void bar(void);
void foobar(void)
{
foo();
bar();
}
main.c
extern void foobar(void);
int main(void)
{
foobar();
return 0;
}
Make two shared libraries, libfoo.so and libbar.so:
$ gcc -c -Wall -fPIC foo.c bar.c
$ gcc -shared -o libfoo.so foo.o
$ gcc -shared -o libbar.so bar.o
Make a third shared library, libfoobar.so that depends on the first two;
$ gcc -c -Wall -fPIC foobar.c
$ gcc -shared -o libfoobar.so foobar.o -lfoo -lbar
/usr/bin/ld: cannot find -lfoo
/usr/bin/ld: cannot find -lbar
collect2: error: ld returned 1 exit status
Oops. The linker doesn't know where to look to resolve -lfoo or -lbar.
The -L option fixes that.
$ gcc -shared -o libfoobar.so foobar.o -L. -lfoo -lbar
The -Ldir option tells the linker that dir is one of the directories to
search for libraries that resolve the -lname options it is given. It searches
the -L directories first, in their commandline order; then it searches its
configured default directories, in their configured order.
Now make a program that depends on libfoobar.so:
$ gcc -c -Wall main.c
$ gcc -o prog main.o -L. -lfoobar
/usr/bin/ld: warning: libfoo.so, needed by ./libfoobar.so, not found (try using -rpath or -rpath-link)
/usr/bin/ld: warning: libbar.so, needed by ./libfoobar.so, not found (try using -rpath or -rpath-link)
./libfoobar.so: undefined reference to `bar'
./libfoobar.so: undefined reference to `foo'
collect2: error: ld returned 1 exit status
Oops again. The linker detects the dynamic dependencies requested by libfoobar.so
but can't satisfy them. Let's resist its advice - try using -rpath or -rpath-link -
for a bit and see what we can do with -L and -l:
$ gcc -o prog main.o -L. -lfoobar -lfoo -lbar
So far so good. But:
$ ./prog
./prog: error while loading shared libraries: libfoobar.so: cannot open shared object file: No such file or directory
at runtime, the loader can't find libfoobar.so.
What about the linker's advice then? With -rpath-link, we can do:
$ gcc -o prog main.o -L. -lfoobar -Wl,-rpath-link=$(pwd)
and that linkage also succeeds. ($(pwd) means "Print Working Directory" and just "copies" the current path.)
The -rpath-link=dir option tells the linker that when it encounters an input file that
requests dynamic dependencies - like libfoobar.so - it should search directory dir to
resolve them. So we don't need to specify those dependencies with -lfoo -lbar and don't
even need to know what they are. What they are is information already written in the
dynamic section of libfoobar.so:-
$ readelf -d libfoobar.so
Dynamic section at offset 0xdf8 contains 26 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libfoo.so]
0x0000000000000001 (NEEDED) Shared library: [libbar.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
...
...
We just need to know a directory where they can be found, whatever they are.
But does that give us a runnable prog?
$ ./prog
./prog: error while loading shared libraries: libfoobar.so: cannot open shared object file: No such file or directory
No. Same as story as before. That's because -rpath-link=dir gives the linker the information
that the loader would need to resolve some of the dynamic dependencies of prog
at runtime - assuming it remained true at runtime - but it doesn't write that information into the dynamic section of prog.
It just lets the linkage succeed, without our needing to spell out all the recursive dynamic
dependencies of the linkage with -l options.
At runtime, libfoo.so, libbar.so - and indeed libfoobar.so -
might well not be where they are now - $(pwd) - but the loader might be able to locate them
by other means: through the ldconfig cache or a setting
of the LD_LIBRARY_PATH environment variable, e.g:
$ export LD_LIBRARY_PATH=.; ./prog
foo
bar
rpath=dir provides the linker with the same information as rpath-link=dir
and instructs the linker to bake that information into the dynamic section of
the output file. Let's try that:
$ export LD_LIBRARY_PATH=
$ gcc -o prog main.o -L. -lfoobar -Wl,-rpath=$(pwd)
$ ./prog
foo
bar
All good. Because now, prog contains the information that $(pwd) is a runtime search
path for shared libraries that it depends on, as we can see:
$ readelf -d prog
Dynamic section at offset 0xe08 contains 26 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libfoobar.so]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000000f (RPATH) Library rpath: [/home/imk/develop/so/scrap]
... ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
That search path will be tried after the directories listed in LD_LIBRARY_PATH, if any are set, and before the system defaults - the ldconfig-ed directories, plus /lib and /usr/lib.
The --rpath-link option is used by bfd ld to add to the search path used for finding DT_NEEDED shared libraries when doing link-time symbol resolution. It's basically telling the linker what to use as the runtime search path when attempting to mimic what the dynamic linker would do when resolving symbols (as set by --rpath options or the LD_LIBRARY_PATH environment variable).
Gold does not follow DT_NEEDED entries when resolving symbols in shared libraries, so the --rpath-link option is ignored. This was a deliberate design decision; indirect dependencies do not need to be present or in their runtime locations during the link process.

ld would not link the static library because of it consider the library is not needed, but I need this library [duplicate]

I have a program and a static library:
// main.cpp
int main() {}
// mylib.cpp
#include <iostream>
struct S {
S() { std::cout << "Hello World\n";}
};
S s;
I want to link the static library (libmylib.a) to the program object (main.o), although the latter does not use any symbol of the former directly.
The following commands do not seem to the job with g++ 4.7. They will run without any errors or warnings, but apparently libmylib.a will not be linked:
g++ -o program main.o -Wl,--no-as-needed /path/to/libmylib.a
or
g++ -o program main.o -L/path/to/ -Wl,--no-as-needed -lmylib
Do you have any better ideas?
Use --whole-archive linker option.
Libraries that come after it in the command line will not have unreferenced symbols discarded. You can resume normal linking behaviour by adding --no-whole-archive after these libraries.
In your example, the command will be:
g++ -o program main.o -Wl,--whole-archive /path/to/libmylib.a
In general, it will be:
g++ -o program main.o \
-Wl,--whole-archive -lmylib \
-Wl,--no-whole-archive -llib1 -llib2
The original suggestion was "close":
How to force gcc to link unreferenced, static C++ objects from a library
Try this: -Wl,--whole-archive -lyourlib
I like the other answers better, but here is another "solution".
Use the ar command to extract all the .o files from the archive.
cd mylib ; ar x /path/to/libmylib.a
Then add all those .o files to the linker command
g++ -o program main.o mylib/*.o
If there is a specific function in the static library that is stripped by the linker as unused, but you really need it (one common example is JNI_OnLoad() function), you can force the linker to keep it (and naturally, all code that is called from this function). Add -u JNI_OnLoad to your link command.

Linking static lib into shared lib,are there a better way to make pre declaration? [duplicate]

When compiling our project, we create several archives (static libraries), say liby.a and libz.a that each contains an object file defining a function y_function() and z_function(). Then, these archives are joined in a shared object, say libyz.so, that is one of our main distributable target.
g++ -fPIC -c -o y.o y.cpp
ar cr liby.a y.o
g++ -fPIC -c -o z.o z.cpp
ar cr libz.a z.o
g++ -shared -L. -ly -lz -o libyz.so
When using this shared object into the example program, say x.c, the link fails because of an undefined references to functions y_function() and z_function().
g++ x.o -L. -lyz -o xyz
It works however when I link the final executable directly with the archives (static libraries).
g++ x.o -L. -ly -lz -o xyz
My guess is that the object files contained in the archives are not linked into the shared library because they are not used in it. How to force inclusion?
Edit:
Inclusion can be forced using --whole-archive ld option. But if results in compilation errors:
g++ -shared '-Wl,--whole-archive' -L. -ly -lz -o libyz.so
/usr/lib/libc_nonshared.a(elf-init.oS): In function `__libc_csu_init':
(.text+0x1d): undefined reference to `__init_array_end'
/usr/bin/ld: /usr/lib/libc_nonshared.a(elf-init.oS): relocation R_X86_64_PC32 against undefined hidden symbol `__init_array_end' can not be used when making a shared object
/usr/bin/ld: final link failed: Bad value
Any idea where this comes from?
You could try (ld(2)):
--whole-archive
For each archive mentioned on the command line after the --whole-archive option, include every object file in the
archive in the link, rather than searching the archive for the required object files. This is normally used to turn
an archive file into a shared library, forcing every object to be included in the resulting shared library. This
option may be used more than once.
(gcc -Wl,--whole-archive)
Plus, you should put -Wl,--no-whole-archive at the end of the library list. (as said by Dmitry Yudakov in the comment below)

Strange linking behaviour and undefined symbols

I am linking an external library (via wierd process, mpicc + Cython + etc),
but I have a weird behaviour of a linking procedure.
There are two .o files, libpetsc4py.o and PETSc.o
they are linked into a .so file PETSc.so
One contains an undefined symbol __pyx_tp_new_8petsc4py_5PETSc_Object
[zheltkov#compiler-2 src]$ nm libpetsc4py.o | grep __pyx_tp_new_8petsc4py_5PETSc_Object
U __pyx_tp_new_8petsc4py_5PETSc_Object
It is defined in another .o file:
[zheltkov#compiler-2 src]$ nm PETSc.o | grep __pyx_tp_new_8petsc4py_5PETSc_Object
00000000001b92f0 t __pyx_tp_new_8petsc4py_5PETSc_Object
Then, then linking is done (the compile line is weird, sorry)
mpicc -pthread -fPIC -wd1572 -g -shared -fno-strict-aliasing -g -O2 -DNDEBUG -O2 -g
build/temp.linux-x86_64-2.7/arch-linux2-c-debug/src/PETSc.o build/temp.linux-x86_64-
2.7/arch- linux2-c-debug/src/libpetsc4py.o -L/home/users/zheltkov/tmp/petsc-3.3/arch
-linux2-c-debug/lib -L/home/users/zheltkov/ivan/soft/epd7.2/lib
-Wl,rpath,/home/users/zheltkov/tmp/petsc-3.3/arch-linux2-c-debug/lib
-Wl,-rpath,/home/users/zheltkov/ivan/soft/epd7.2/lib -lpetsc -lpython2.7 -o
build/lib.linux-x86_64-2.7/petsc4py/lib/a rch-linux2-c-debug/PETSc.so -lX11 -Wl,
-rpath,/home/users/zheltkov/tmp/petsc-3.3/arch-linux2-c-debug/lib
-L/home/users/zheltkov/tmp/petsc-3.3/arch-linux2-c-debug/lib -lfftw3_mpi -lfftw3 -lHYPRE
-Wl,-rpath,/opt/intel/impi/4.1.0.030/intel64/lib
-L/opt/intel/impi/4.1.0.030/intel64/lib -Wl,
-rpath,/opt/intel/composer_xe_2013.2.146/mkl/lib/intel64
-L/opt/intel/composer_xe_2013.2.146/mkl/lib/intel64
-Wl,-rpath,/opt/intel/composer_xe_2013.2.146/compiler/lib/intel64
-L/opt/intel/composer_xe_2013.2.146/compiler/lib/intel64 -Wl,
-rpath,/usr/lib/gcc/x86_64-redhat-linux/4.4.6 -L/usr/lib/gcc/x86_64-redhat-linux/4.4.6
-Wl,- rpath,/mnt/data/users/dm4/vol9/zheltkov/tmp/petsc-3.3/-Xlinker -lmpigc4
-Wl,-rpath,/opt/intel/mpi-rt/4.1 -lml -lpthread -Wl,-rpath,
/opt/intel/composer_xe_2013/mkl/lib/intel64
-L/opt/intel/composer_xe_2013/mkl/lib/intel64 -lmkl_intel_lp64 -lmkl_intel_thread
-lmkl_core -liomp5 -lifport -lifcore -lm -ldl -lmpigf -lmpi_dbg -lmpigi -lrt
-limf -lsvml -lirng -lipgo -ldecimal -lcilkrts -lstdc++ -lgcc_s -lirc -lirc_s
But finally, the resulting files has two symbols with the same name, one of them is undefined and everything does not work:
[zheltkov#compiler-2 arch-linux2-c-debug]$ nm PETSc.so | grep __pyx_tp_new_8petsc4py_5PETSc_Object
0000000000200d20 t __pyx_tp_new_8petsc4py_5PETSc_Object
U __pyx_tp_new_8petsc4py_5PETSc_Object
What am I doing wrong? Why there are two symbols with the same name?
In an object file t indicates that the function has internal linkage (i.e. is declared as static), while in another file, U indicates the function is referenced, but not defined. An external function is indicated with T.
When you link to create a shared library, the linker doesn't complain about unresolved references, so it includes the static function (available only in the file that defined it), and an external symbol marked as undefined.
Here's a simpler example. Two files:
foo.c
#include <stdio.h>
static void hello(void)
{
printf("Hello\n");
}
bar.c
void sayhello(void)
{
hello();
}
Compile the two:
$ gcc -c -fPIC foo.c
$ gcc -c -fPIC bar.c
$ nm foo.o
0000000000000000 t hello
$ nm bar.o
U hello
0000000000000000 T sayhello
Now create a shared library
$ gcc -shared -o libhello.so foo.o bar.o
$ nm libhello.so
0000000000000700 t hello
U hello
The result of this is that if I define a function hello and link against this library to create an executable, the library will call my function in sayhello - not the static one. If I don't define it, the linker will give an undefined symbol error.

Resources