I am new to Linux OS. I am trying to compile a .c file using a makefile. The math library has to be linked. My makefile looks like this:

CC=gcc
CFLAGS=-Wall -lm

all:client

.PHONY: clean
clean:
    rm *~ *.o client

When I run make, I get the following error:

"undefined reference to rint"

So it is not able to link the math library.

But when I compile explicitly using

gcc client.c -lm -o client

it successfully compiles.

So how should I change my makefile such that it works. I have already tried adding LDFLAGS=-lm. But I get the same error.

I should also add that when I run make, it expands to

gcc -Wall -lm client.c -o client

(notice that when I run gcc explicitly with -lm at the end, it works).

share|improve this question
up vote 47 down vote accepted

Your linker (ld) obviously doesn't like the order in which make arranges the GCC arguments so you'll have to change your Makefile a bit:

CC=gcc
CFLAGS=-Wall
LDFLAGS=-lm

OBJECTS=client.o

client: $(OBJECTS)
    $(CC) $(CFLAGS) $(OBJECTS) -o client $(LDFLAGS)

all:client

.PHONY: clean
clean:
    rm -f *~ *.o client

In the line defining the client target change the order of $(LDFLAGS) as needed.

share|improve this answer
30  
LDLIBS is for libraries, LDFLAGS should be used for flags/search paths (-L) – falstaff May 2 '14 at 14:51
3  
3  
I also thought that -lm should be in LDFLAGS but as it turns out (see laindir's answer and gnu.org/software/make/manual/html_node/Catalogue-of-Rules.ht‌​ml), it should be in LOADLIBES instead, and then everything works out of the box (ie without defining explicit rules)! – Emil Vatai Apr 2 '15 at 18:51
1  
Where do you use source in your rules? It's defined, but not used. Having a hard time understanding this. – MrPickles Mar 5 '16 at 18:29
2  
@EmilVatai According to gnu.org/software/make/manual/make.html#index-LDLIBS LOADLIBES is deprecated and LDLIBS should be used instead. – Starfish Aug 2 '16 at 1:43

In more complicated build scenarios, it is common to break compilation into stages, with compilation and assembly happening first (output to object files), and linking object files into a final executable or library afterward--this prevents having to recompile all object files when their source files haven't changed. That's why including the linking flag -lm isn't working when you put it in CFLAGS (CFLAGS is used in the compilation stage).

The convention for libraries to be linked is to place them in either LOADLIBES or LDLIBS (GNU make includes both, but your mileage may vary):

LDLIBS=-lm

This should allow you to continue using the built-in rules rather than having to write your own linking rule. For other makes, there should be a flag to output built-in rules (for GNU make, this is -p). If your version of make does not have a built-in rule for linking (or if it does not have a placeholder for -l directives), you'll need to write your own:

client.o: client.c
    $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $@ $<

client: client.o
    $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@
share|improve this answer

Seems like the order of the linking flags was not an issue in older versions of gcc. Eg gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16) comes with Centos-6.7 happy with linker option before inputfile; but gcc with ubuntu 16.04 gcc (Ubuntu 5.3.1-14ubuntu2.1) 5.3.1 20160413 does not allow.

Its not the gcc version alone, I has got something to with the distros

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.