i have written such a code in my Ubuntu system:
my.h
#include <stdio.h>
int a;
int set(void);
lib.c
#include "my.h"
int set(void) {
a = 100;
return 0;
}
main.c
#include "my.h"
int main(void){
set();
printf("a = %d\n", a);
return 0;
}
and then i use follow commands to build them:
gcc -shared -fPIC -o libmy.so -I. lib.c
gcc -L. -lmy -I. -o test main.c
when i build the test, i get the error information :
main.c:(.text+0x5):undefined reference to 'set'
collect2: error: ld returned 1 exit status
but when i use the same code run in Fedora23 and Fedora24, it works well.
so i want to know why can this happen? is there any limitation in Ubuntu system?
You have fallen foul of a difference between the linkage conventions of Fedora's GCC builds and Debian/Ubuntu's GCC builds.
When you invoke gcc
to perform linkage of a C executable it in turn invokes the system linker
ld
, passing it your commandline linkage options and silently adds to
them a large number of "boilerplate" linkage options which are invariant
for C language linkages (similarly for g++
and C++ language linkages).
Those invariant linkage options are decided by your distro and configured into their build of GCC. So they are not invariant across distros.
Debian/Ubuntu GCC silently adds --as-needed
to the linkage options at a
position before your input files and libraries. Fedora's GCC does not.
The effect of --as-needed
is to make the linker link a shared library
that it finds in the linkage sequence only if that library provides
a definition of one or more symbols for which the linker has already found
undefined references (i.e. within object files or libraries earlier
in the linkage sequence). This behaviour applies in any case for static libraries.
So --as-needed
makes the linkage rules similar for both static and shared
libraries - which might be considered helpful to the average user.
This difference is a linkage policy difference between the distros. What it means to you is that to link successfully on Ubuntu, your linkage commandline must mention any library after any object file or other library that depends on it. And if you are compiling-and-linking in one command, then you must mention any library after any source file whose corresponding object file depends on that library. So on ubuntu, your problem commandline should be:
gcc -I. -o test main.c -L. -lmy
to succeed. This will also of course work for Fedora.
If you are interested in inspecting the hidden differences in the linkage
options between the two distros you can reveal them by add -Wl,-v
to your
compile-and-link command to get verbose linker output.