1

Command like this will work:

(LD) $(LDFLAGS) -o reip.app newlib/crt0.o reip.o renetif.o fs.o httpd.o liblwip.a newlib/libc.a

But if I place *.a before *.o files - it will be not able to find functions from libs.

I've searched through some old projects and found in makefiles lines like these:

$(CC)  $(LIBS) -o $(TARGET) JukeboxMain.o JukeboxPlayer.o ...

which doesn't work either until I move $(LIBS) to the end of line. But I remember it was working for me long time ago. Could someone please answer what changed and why it doesn't work anymore ) P.S. I'm not a big fan of playing with compilers, linkers and other tools - I mostly prefer to create something ;)

pulse
  • 303
  • 4
  • 18
  • 2
    Creating something includes creating a Makefile, and this includes understanding linkage, the pre-processor and compiler quirks – Elias Van Ootegem Feb 18 '14 at 12:50
  • @EliasVanOotegem Well, not necessarily a make file. At least not directly. A CMake project works just as well. – Cubic Feb 18 '14 at 12:53
  • Elias - I don't understand what you are talking about.. Makefile is not always needed. make is just an utility which simplifies building process. to create executable you need compiler(which include preprocessor), linker and probably something like libc. The question was why I should place static libs before other object files. – pulse Feb 18 '14 at 13:58
  • Yes, the answer for duplicate question is correct for my question also. – pulse Feb 18 '14 at 13:59

1 Answers1

7

I can't answer you as to why you think it might have worked before. But I can tell you why it doesn't work in general. Most POSIX-style linkers, which includes the GNU binutils ld using on GNU/Linux and others, are single-pass linkers.

That means they walk the elements listed in the command line from the start to the end one time and they don't go back. When the linker starts it's basically looking for one symbol, main. As it walks the command line, any object file (foo.o) the linker finds is always added to the executable. The object provides a list of symbols which are defined, and a list which are undefined (needed from other objects).

When the linker hits a static library (libfoo.a), it looks through the object files in that library and if an object contains any symbol which the linker needs, it adds that object to the executable. If it does not contain any symbol the linker needs, it skips that object.

At the end of the command line, if any symbol was needed but not found, then the link fails.

So, you can see that in order to be sure everything is found in a single pass, the things that NEED symbols from libraries must come before the libraries that provide those symbols, or else when the linker hits the library in its single pass it won't know that the libraries are needed and will skip them.

MadScientist
  • 92,819
  • 9
  • 109
  • 136
  • Notable (fun?) fact: `-lpthread` -- which is needed for most multi-thread applications on unix systems -- follows this exact same rule. However `-pthread` beeing functionally equivalent may be placed anywhere. – stefan Feb 18 '14 at 12:59
  • stefan: very true. That's because `-lpthread` is a straightforward "find a library named `pthread`", just like `-lfoo`. It has no special meaning. But `-pthread` is a magical flag (not for the linker, but to the compiler driver) which tells it to do all the things necessary to enable threading. This includes adding `-lpthread` (at the end, as it should be) but also whatever is needed during compilation (adding `-D_REENTRANT` or whatever). Since different systems use different options, `-pthread` was developed to "make it work" everywhere. – MadScientist Feb 18 '14 at 13:46
  • Thanks. That seems to be the correct answer) – pulse Feb 18 '14 at 13:55