Strange linking behaviour and undefined symbols - c

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.

Related

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

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.

Linkin two shared library with same symbol name but different symbol type

I want to link two shared libraries that both two libraries have same symbol name but different symbol type.
For example, there are liba.so and libb.so libraries that consist of two files a.c/b.c and b_wrapper.c/a_wrapper.c
a.c
__thread int var;
a_wrapper.cpp
extern __thread int var;
liba.so
$ gcc -fPIC -c a.c -o a.o
$ g++ -fPIC -c a_wrapper.cpp -o a_wrapper.o -std=c++11
$ g++ -fPIC -shared -o liba.so a.o a_wrapper.o -std=c++11
b.c
int var;
b_wrapper.c
extern int var;
libb.so
$ gcc -fPIC -c b.c -o b.o
$ g++ -fPIC -c b_wrapper.cpp -o b_wrapper.o -std=c++11
$ g++ -fPIC -shared -o libb.so b.o b_wrapper.o -std=c++11
then link liba.so and libb.so to top.c file, I get some error message
$ g++ top.cpp -ldl -o exe ./liba.so ./libb.so -std=c++11
/usr/bin/ld: var: TLS definition in ./liba.so section .tdata mismatches non-
TLS definition in ./libb.so section .bss
./libb.so: error adding symbols: Bad value
collect2: error: ld returned 1 exit status
I think the problem is because var in a.c is defined in thread local storage bss(tbss), but var in b.c is defined in normal bss.
I have read this post Linking two shared libraries with some of the same symbols
and try -Bsymbolic, --version-script and -fvisibility=hidden, but all these methods can not achieve my goal.
-Bsymbolic : I used it when creating liba.so and libb.so, but when I linked liba.so and libb.so I still got same error message described as above
--version-script and -fvisibility=hidden : I can't let var variable become local to one file(a.c) since other files(a_wrapper.cpp) will extern and use that variable
Is there any way that I can link two shared libraries that has some same symbol name but different symbol type?

undefined symbols when linking one .so with other

a.so defines function A(), b.so defines function B() and calls A() that is defined in a.so. b.so is linked to a.so as below
gcc -fPIC -shared B.c -o libb.so -la
Now I created a binary which is calling B() that is defined in b.so
gcc mybin.c -o mybin -lb
gcc is checking for every symbol in b.so and throws error saying A() is not defined.
gcc mybin.c -o mybin -lb -la
The above works but I had to link mybin with a.so even though it is not directly related to a.so. My requirement is that if b.so is properly linked with a.so, linking mybin with just b.so should work.
Is this possible ??
When linking the executable the linker wants to know that the libraries needed by libb.so exist so it can check they resolve any undefined references in libb.so
The linker looks for the required libraries in the usual places, so if that wouldn't find liba.so then you can tell the linker where to look by using LD_LIBRARY_PATH as shown by another answer, or by using the linker option that exists specifically for this purpose, -rpath-link
gcc mybin.c -o mybin -lb -Wl,-rpath-link=.
(The -Wl, prefix is how you tell GCC to pass an option to the linker, which is needed for linker options that GCC doesn't know about directly.)
Alternatively, you can tell the linker to allow undefined symbols in libb.so in which case it doesn't try to find liba.so to resolve the reference to A(), and trusts that you'll link correctly and ensure the library is available at run-time. That is done with the --allow-shlib-undefined option:
gcc mybin.c -o mybin -lb -Wl,--allow-shlib-undefined
However, it's generally better to let the linker check that all symbols are defined, and tell it how to find the required libraries, as it finds real problems sooner.
The -rpath-link option only tells the linker where to look for additional shared libraries, it has no visible effect on the linked executable (i.e. it doesn't record the path to the library in the executable anywhere). Another alternative is to create libb.so so that it contains the knowledge of how to find liba.so embedded within it. That is done with the -rpath linker option, e.g. if liba.so is in /some/path you could do:
gcc -fPIC -shared B.c -o libb.so -la -Wl,-rpath=/some/path
This puts a DT_RPATH tag in libb.so and the linker will use that to find its dependencies:
readelf -d libb.so | fgrep RPATH
0x000000000000000f (RPATH) Library rpath: [/some/path]
Now you can link the executable without needing any knowledge of liba.so, the linker will see that libb.so needs liba.so and will use the RPATH to find it:
gcc mybin.c -o mybin -lb
This works fine if the path /some/path/liba.so is fixed, but it might not be true that the library is found in the same location during development and after your executable is deployed. In that case you can still use -rpath-link for the executable to tell the linker where to look for it during linking, and rely on the RPATH to find it at run-time. Or you can use the special string $ORIGIN in the RPATH which the dynamic linker expands to the location of the object containing the RPATH, e.g. if liba.so and libb.so are always in the same directory, you can link libb.so like this (note the quotes to prevent the shell expanding $ORIGIN):
gcc -fPIC -shared B.c -o libb.so -la '-Wl,-rpath=$ORIGIN'
readelf -d libb.so | fgrep RPATH
0x000000000000000f (RPATH) Library rpath: [$ORIGIN]
The missing bit was the LD_LIBRARY_PATH:
export LD_LIBRARY_PATH=.
gcc -fPIC -shared a.c -o liba.so
gcc -fPIC -shared b.c -o libb.so -la
gcc mybin.c -o mybin -lb -L.
The reason -L does not work seems it that this flag it used to « Add directory dir to the list of directories to be searched for -l » , see the GCC doc. And libba.so is not specified in a -l.
Here are the steps:
gcc -fPIC -shared a.c -o liba.so
gcc -fPIC -shared b.c -o libb.so
gcc mybin.c -o mybin -lb -la -L. # -L to look for the directory to load .so files
Then make sure you do:
export LD_LIBRARY_PATH=<your_directory>
You need to have liba.so and libb.so mentioned in gcc mybin.c -o mybin -lb -la -L. as the function A() needs to be loaded at runtime. b.so IS NOT LINKED with a.so. Linking happens that runtime in shared library. They are compiled and any reference to functions or extern variables are not resolved.
If you want to include b.so but not a.so then compile the b as static library thereby it loads a into its binary. And then when you compile mybin you will only need b.lib

Building a shared library using gcc on Linux and MinGW on Windows

I'm having trouble with generating a build setup that allows shared libraries to be built in both Linux and Windows using gcc and MinGW, respectively. In Linux, a shared library doesn't have to resolve all dependencies at compile time; whereas, this appears to the case in Windows. Here is the problem setup:
$ cat foo.h
#ifndef FOO_H
#define FOO_H
void printme();
#endif
$ cat foo.c
#include "foo.h"
#include <stdio.h>
void printme() {
printf("Hello World!\n");
}
$ cat bar.h
#ifndef BAR_H
#define BAR_H
void printme2();
#endif
$ cat bar.c
#include "bar.h"
#include "foo.h"
void printme2() {
printme();
printme();
}
$ cat main.c
#include "bar.h"
int main(){
printme2();
}
$ cat Makefile
.c.o:
gcc -fPIC -c $<
all: foo.o bar.o main.o
gcc -shared foo.o -o libfoo.so
gcc -shared bar.o -o libbar.so
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
Now, in Linux, this compiles and runs just fine:
$ make
gcc -fPIC -c foo.c
gcc -fPIC -c bar.c
gcc -fPIC -c main.c
gcc -shared foo.o -o libfoo.so
gcc -shared bar.o -o libbar.so
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
$ ./main
Hello World!
Hello World!
In Windows, we need to change so to dll, which is minor and fine:
$ cat Makefile
.c.o:
gcc -fPIC -c $<
all: foo.o bar.o main.o
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o -o libbar.dll
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
However, when we try to build, we get the following error:
$ make
gcc -fPIC -c foo.c
foo.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c bar.c
bar.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c main.c
main.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o -o libbar.dll
bar.o:bar.c:(.text+0x7): undefined reference to `printme'
bar.o:bar.c:(.text+0xc): undefined reference to `printme'
collect2.exe: error: ld returned 1 exit status
make: *** [all] Error 1
Now, we can fix the error by simply including the objects from foo.o into libbar.dll:
$ cat Makefile
.c.o:
gcc -fPIC -c $<
all: foo.o bar.o main.o
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o foo.o -o libbar.dll
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
$ make
gcc -fPIC -c foo.c
foo.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c bar.c
bar.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -fPIC -c main.c
main.c:1:0: warning: -fPIC ignored for target (all code is position independent) [enabled by default]
gcc -shared foo.o -o libfoo.dll
gcc -shared bar.o foo.o -o libbar.dll
gcc main.o -Wl,-rpath=. -L . -lbar -lfoo -o main
$ ./main
Hello World!
Hello World!
However, I don't like this approach since libbar.dll now contains symbols for both foo and bar. In Linux, it only contains symbols for bar. This separation is important for situations where a library depends on some standard numerical library like BLAS. I'd like to be able to deploy the shared library and have it depend on the optimized version of the numerical library on the user's machine and not my own.
In any case, what's the proper procedure to create a shared library where not all of the symbols are present at compile time?
In case it matters, I compiled these examples with gcc 4.6.3 on Linux and mingw-get-inst-20120426.exe with gcc 4.7.2 on Windows.
On Windows, you need to create an import library for the DLL. An import library looks like a static library, in that it defines all of the needed symbols, but it doesn't have the actual function implementations, it just has stubs. The import library will resolve the "undefined reference" errors while avoiding static linking.
To create an import library with MinGW, follow the instructions here. The key is that when building the DLL, you must pass the option -Wl,--out-implib,libexample_dll.a to the linker to generate the import library libexample_dll.a.
Then, when you compile your main executable, you use the -lexample_dll option (along with -L.) to link against the import library. So with your code, I think this should work:
all: foo.o bar.o main.o
gcc -shared foo.o -o libfoo.dll -Wl,--out-implib,libfoo.a
gcc -shared bar.o foo.o -o libbar.dll -Wl,--out-implib,libbar.a
gcc main.o -Wl,-rpath=. -L. -lbar -lfoo -o main
Also, note that on Windows, the calling convention for exported functions in DLL is almost always __stdcall, not the default __cdecl, so if you want your DLLs to be usable by other software, I'd recommend making them __cdecl. But that's not strictly requires, as long as both the code in the DLL and the header files agree on what the calling convention is.

Undefined reference to `initscr' Ncurses

I'm trying to compile my project and I use the lib ncurse. And I've got some errors when compiler links files.
Here is my flags line in Makefile:
-W -Wall -Werror -Wextra -lncurses
I've included ncurses.h
Some layouts :
prompt$> dpkg -S curses.h
libslang2-dev:amd64: /usr/include/slcurses.h
libncurses5-dev: /usr/include/ncurses.h
libncurses5-dev: /usr/include/curses.h
prompt$> dpkg -L libncurses5-dev | grep .so
/usr/lib/x86_64-linux-gnu/libncurses.so
/usr/lib/x86_64-linux-gnu/libcurses.so
/usr/lib/x86_64-linux-gnu/libmenu.so
/usr/lib/x86_64-linux-gnu/libform.so
/usr/lib/x86_64-linux-gnu/libpanel.s
And here are my erros :
gcc -W -Wall -Werror -Wextra -I./Includes/. -lncurses -o Sources/NCurses/ncurses_init.o -c Sources/NCurses/ncurses_init.c
./Sources/NCurses/ncurses_init.o: In function `ncruses_destroy':
ncurses_init.c:(.text+0x5): undefined reference to `endwin'
./Sources/NCurses/ncurses_init.o: In function `ncurses_write_line':
ncurses_init.c:(.text+0xc5): undefined reference to `mvwprintw'
./Sources/NCurses/ncurses_init.o: In function `ncurses_init':
ncurses_init.c:(.text+0xee): undefined reference to `initscr'
collect2: error: ld returned 1 exit status
Thanks a lot
You need to change your makefile so that the -lncurses directive comes after your object code on the gcc command line, i.e. it needs to generate the command:
gcc -W -Wall -Werror -Wextra -I./Includes/. -o Sources/NCurses/ncurses_init.o -c Sources/NCurses/ncurses_init.c -lncurses
This is because object files and libraries are linked in order in a single pass.
In C++ , I fixed it just by linking the ncurses library .
Here is the command :
g++ main.cpp -lncurses
I got flags to correct order by using LDLIBS variable:
ifndef PKG_CONFIG
PKG_CONFIG=pkg-config
endif
CFLAGS+=-std=c99 -pedantic -Wall
LDLIBS=$(shell $(PKG_CONFIG) --libs ncurses)
man gcc | grep -A10 "\-l library"
-l library
Search the library named library when linking. (The second alternative with the library as a separate argument is only for POSIX
compliance and is not recommended.)
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files
in the order they are specified. Thus, foo.o -lz bar.o searches
library z after file foo.o but
before bar.o. If bar.o refers to functions in z, those functions may not be loaded.

Resources