2

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?

pakade
  • 75
  • 1
  • 7

1 Answers1

4

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.

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182
  • thanks your reply. it solves my problem. And i want to know can i change the default LD flags so that for each library the default property is `--no-as-needed` like in FEDORA. Where does the default link arguments come form? thanks! – pakade Feb 09 '17 at 13:55
  • @pakade You can't change this behaviour without building your own GCC toolchain. In Ubuntu - as in Fedora - its better to get used to the rules than fight them. In some countries you drive on the left of the road, in others you drive on the right. Most linux devs today don't even know its possible to link shared libraries the way you're used to. If you really wanted to do it like that on Ubuntu, you'd use e.g. `gcc -Wl,--no-as-needed -L. -lmy -I. -o test main.c -Wl,--as-needed`. But anyone would prefer `gcc -I. -o test main.c -L. -lmy` – Mike Kinghan Feb 09 '17 at 18:32