LWIP Makefile error - c

After going through the LWIP documents, I wrote a simple tcp echo server code. To compile it and create an executable I wrote the following Makefile. Now, when I run the command make all, it gives error for each of .c files included in the makefile.
The file structure is as follows:
1. tcp_server.c is the main file where I create the tcp server.
2. It uses the tcp_new(), tcp_bind() etc functions defined in "lwip-1.4.1/src/core/lwip/tcp.c" and "lwip-1.4.1/src/core/lwip/tcp_out.c" and I have given the paths for compilation accordingly.
I am just a beginner in writing makefiles and have written the following file going through the GNU Make documentation.
CC=gcc
CFLAGS= -g -Wall
LWIPDIR=../lwip-1.4.1/src
TARGET=tcp_server
INCLUDES= -I../lwip-1.4.1/src/include -I../STABLE-1_4_0/ports/unix/proj/lib\
-I../STABLE-1_4_0/ports/unix/include -I../lwip-1.4.1/src/include/ipv4
LFLAGS= -L../STABLE-1_4_0/ports/unix/proj/lib/liblwip.so
#LIBS= -llwip
COREFILES=$(LWIPDIR)/core/tcp.c $(LWIPDIR)/core/tcp_out.c
VPATH = $(LWIPDIR)/core
OBJS = tcp_server.o tcp.o tcp_out.o
MAIN=tcp_server
all : edit
edit : $(OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o edit $(OBJS) $(LFLAGS)
tcp_server.o : tcp_server.c tcp.o tcp_out.o
$(CC) $(CFLAGS) $(INCLUDES) -c tcp_server.c $(LFLAGS)
tcp.o : $(LWIPDIR)/core/tcp.c
$(CC) $(CFLAGS) $(INCLUDES) -c $(LWIPDIR)/core/tcp.c $(LFLAGS)
tcp_out.o : $(LWIPDIR)/core/tcp_out.c
$(CC) $(CFLAGS) $(INCLUDES) -c $(LWIPDIR)/core/tcp_out.c $(LFLAGS)
clean :
rm -f *.o
All the files include certain headers defined in "lwip-1.4.1/src/include" and I given the arguments to -I accordingly. However on running make, the output shows "Undefined reference to" all the functions which are defined in the lwip header files. What could be the reason? Where I am going wrong?
Thank you for all the help.

UNDEFINED REFERENCE is a linker error so you should;
For gcc you should use -L to specify the directory your libraries are contained and use -l to link a particular library. For example change the line in your makefile;
LFLAGS= -L../STABLE-1_4_0/ports/unix/proj/lib
remove the comment before LIBS and change this target
edit : $(OBJS)
$(CC) $(CFLAGS) $(INCLUDES) -o edit $(OBJS) $(LFLAGS) $(LIBS)

Related

How to make static libraries with Makefile?

This is the Makefile
CC=gcc
CFLAGS=-Wall -pedantic -Werror -g
LDFLAGS=-lm
RM=rm -f
SOURCES=$(wildcard *.c)
TARGETS=$(SOURCES:.c=)
OBJECTS=$(SOURCES:.c=.o)
.PHONY: all clean
all: test_stack
%: %.c
$(CC) $(CFLAGS) $(LDFLAGS) $< -o $#
%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
%.a: %.o
ar rcs $# $<
ranlib $#
test_stack: genstacklib.a test_stack.o
$(CC) $(CFLAGS) -o $# $^ $(LDFLAGS)
clean:
$(RM) $(OBJECTS) $(TARGETS)
I have the files genstacklib.c, genstacklib.h and test_stack.c
Now I want to compile genstacklib as static library
When test_stack calls the methods of genstacklib, it throws an exeception:
for example: "undefined reference to `genStackNew'"
I don't get why test_stack can't access the methods, for my current understanding it should have access to the library.
Please copy and paste the exact errors you get into your question, with proper formatting, and also including the compile or link command that make printed. A statement like "throws an exception" is not precise and in fact is not really accurate because exceptions are thrown from running programs, but (if I understand your problem correctly) you are not able to link your program.
The problem is that the order of arguments to the linker is critical: all libraries must appear on the link line after all object files. Also the order of libraries matters but since you have only one that's not an issue.
In your rule:
test_stack: genstacklib.a test_stack.o
$(CC) $(CFLAGS) -o $# $^ $(LDFLAGS)
The $^ variable expands to the prerequisites, in this case genstacklib.a test_stack.o. So on your link line the library will appear before the object file, which won't work. Rewrite your rule like this:
test_stack: test_stack.o genstacklib.a
$(CC) $(CFLAGS) -o $# $^ $(LDFLAGS)
so the library comes after the object files and it will probably work.
As an aside, the variable LDFLAGS generally contains flags that manage the linker. Library references like -lm are traditionally put into a variable LDLIBS instead. Of course this is just convention but it's useful to follow conventions unless there's a good reason not to.

How do I get a makefile to compile multiple sources?

I would like my makefile to compile two sources, osmprun.c and echoall.c.
Currently it's just compiling osmprun.c, which creates errors.
Im at my wits end, Im not experienced with makefiles at all and I just don't understand what im doing wrong.
My makefile is:
CC=gcc
CFLAGS= -Wall -Wconversion -g
LIBS=-lm -lpthread
DEPS=
BUILD_DIR := build
SRCS := osmprun.c echoall.c
OBJS := $(addprefix $(BUILD_DIR)/,$(patsubst %.c,%.o,$(SRCS)))
$(BUILD_DIR)/%.o: %.c $(DEPS)
mkdir -p $(BUILD_DIR)
$(CC) -c $(CFLAGS) $< -o $#
echoall: $(OBJS)
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $< $(LIBS) -o $#
osmprun: $(OBJS)
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $< $(LIBS) -o $#
.PHONY: clean
clean:
rm -f $(BUILD_DIR)/*.o *~ core
test:
./osmprun
Can somebody help me figure out my mistake and explain what the problem is?
EDIT:
I've now changed the part where it is supposed to compile the two files to:
echoall: echoall.c
$(CC) $(CFLAGS) $^ $(LIBS) -o $#
osmprun: osmprun.c
$(CC) $(CFLAGS) $^ $(LIBS) -o $#
But it is still only compiling echoall, not osmprun
It would help greatly if you included the command you typed and the output you got, and what you wanted to get, especially because your terminology is not quite accurate. It's not true that make is not compiling all the object files. The problem is at the link stage.
However, I don't understand what your makefile is intended to do. You have two targets and they both depend on the SAME set of object files:
echoall: $(OBJS)
osmprun: $(OBJS)
Do you need to link both of those object files together? If so then what is the difference between the echoall program and the osmprun program, if they both contain the same set of object files?
Or, do you want to create the echoall program from the echoall.c source file and the osmprun program from the osmprun.c source file? If so, why do you list both objects as a prerequisite for both programs?
In any event your problem is here:
echoall: $(OBJS)
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $< $(LIBS) -o $#
osmprun: $(OBJS)
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $< $(LIBS) -o $#
(the mkdir here are useless: you know that the directory already exists because you already built the object files, but they don't hurt anything).
The problem is you're using $< which is the first prerequisite. Because both prerequisite lists are the same, you're building both programs from the same, single source file.
If you want both programs to contain both object files, you should use $^ here not $<. If you want each program to contain only its related object file, you should change the prerequisites to contain only the object file it should be built from (and also use $^).

Is this makefile example correct?

I'm looking at this makefile example from an academic course I'm following and some doubts emerged. Hope you will be able to clarify them.
(1) I'm wondering why the automatic variable $^ in the $(SRCDIR)/%.o: %.c receipe is needed? Couldn't just $(CC) -c $< $(CFLAGS) $(LDFLAGS) suffice?
(2) Regarding the % wildcard, if I have for instance ./src/main.c, $(SRCDIR)/%.o: %.c will be translated to ./src/main.o : ./src/main.c or just ./src/main.o : main.c ? In the second case, wouldn't the resulting receipe be wrong?
$(CC) -c ./src/main.c $(CFLAGS) $(LDFLAGS) VS $(CC) -c main.c $(CFLAGS) $(LDFLAGS)
(3) Also, why is -lpthread needed? Is it something related to the makefile options or it means just that some of the files are potentially using the pthread library? I thought many of this basic libraries were already present in the basic GNU toolchain.
Thanks in advance as always.
NAME = myprog
CC = gcc
CFLAGS = -Wall -O3 -I $(INCDIR)
LDFLAGS = -lpthread -lm
SRCDIR = ./src
INCDIR = ./include
BINDIR = /usr/local/bin
SOURCES = $(SRCDIR)/main.c $(SRCDIR)/dummy_functions.c
OBJECTS = $(SOURCES:.c=.o)
all: $(NAME)
$(NAME): $(OBJECTS)
$(CC) $^ -o $# $(CFLAGS) $(LDFLAGS)
$(SRCDIR)/%.o: %.c
$(CC) $^ -c $< $(CFLAGS) $(LDFLAGS)
clean:
...
Yikes. You should definitely not try to learn how to write makefiles from this course :-/.
For (1), you definitely do not want to use $^ when compiling, because it will add all your header files (should you declare any or set up to autogenerate them) to the compile line which is wrong. It should use $<.
For (2), you're right: the % is identical between the target and prerequisite, or the pattern rule doesn't match. The pattern rule should be either %.o : %.c or else $(SRCDIR)/%.o : $(SRCDIR)/%.c, or else you need to set VPATH = $(SRCDIR) in your makefile so make knows where to look for sources it can't find.
For (3), this is not related to make or makefiles: if your code uses threading then you need to add this option to the link line or you'll get link errors. Technically this is obsoleted by the -pthread option which should appear on both the compile and link lines. The compiler/linker do not add these libraries on their own you have to do it yourself.
$< expands to the first dependency. $^ contains them all. If the target has multiple dependencies (perhaps via a separate dependency declaration somewhere else in the Makefile), $< will not contain them all. Whether that is incorrect will depend on additional circumstances, but typically I would say it is at least surprising (and if you really only want the first file, you should spell that out in a comment at least).

Makefile not compiling all C files in directory

Iam working with gcc and MinGW on a Windows platform. I have a directory containing two *.c files:
main.c and funcs.c
I am using the following makefile:
CC=gcc
CFLAGS=-c
LDFLAGS=
SOURCEDIR = src
BUILDDIR = build
SOURCES=$(wildcard $(SOURCEDIR)/*.c)
OBJECTS=$(patsubst $(SOURCEDIR)/%.c,$(BUILDDIR)/%.o,$(SOURCES))
LIBRARIES=-L/mingw64/lib
INC= -I./include
EXECUTABLE=testLink
VPATH = src include build
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) $(LIBRARIES) -o ./dist/$#
$(OBJECTS): $(SOURCES)
$(CC) $(INC) $(CFLAGS) $< -o $#
Which should take the *.c files and generate *.o files with the same name. However I get the following output on make -
$ make
gcc -I./include -c src/funcs.c -o build/funcs.o
gcc -I./include -c src/funcs.c -o build/main.o
gcc build/funcs.o build/main.o -L/mingw64/lib -o ./dist/testLink
followed of course by a bunch of multiple definition errors. As you can see from the first two lines it is taking the same *.c file and compiling it twice into two different *.o files.
I am new to makefiles but I assume it is something wrong with my $(OBJECTS) rule and I'm pretty sure it's the $< which is causing the problem. I'm trying to create a generic makefile which will always work on my projects which have the same directory structure and take .c files turn them into .o files and link. Am I going about this entirely the wrong way or is there a simple fix to my makefile?
Thanks!
James
This rule:
$(OBJECTS): $(SOURCES)
$(CC) $(INC) $(CFLAGS) $< -o $#
expands to:
funcs.o main.c: funcs.c main.c
$(CC) $(INC) $(CFLAGS) $< -o $#
which is equivalent to:
funcs.o: funcs.c main.c
$(CC) $(INC) $(CFLAGS) $< -o $#
main.o: funcs.c main.c
$(CC) $(INC) $(CFLAGS) $< -o $#
$< refers to the first dependency (funcs.c) so your Makefile is trying to generate both funcs.o and main.o from the same source.
You just want a generic rule using % wildcard matching:
%.o: %.c
$(CC) $(INC) $(CFLAGS) $< -o $#
See https://www.gnu.org/software/make/manual/html_node/Pattern-Rules.html
Jeff pointed the mistake in his answer (all objects depend on all sources: that isn't a generic compilation rule for c sources).
However, the generic rule must have source & object paths. To sum it up, just replace
$(OBJECTS): $(SOURCES)
$(CC) $(INC) $(CFLAGS) $< -o $#
by
$(BUILDDIR)/%.o : $(SOURCEDIR)/%.c
$(CC) $(INC) $(CFLAGS) $< -o $#
(as explained in How to generate a Makefile with source in sub-directories using just one makefile)
note that this kind of dependency test doesn't take included .h files into account, so it's only intended for first builds. Modifying .h files afterwards doesn't trigger a compilation since the header files are not listed as dependencies.

Rule not recognized in makefile?

I have a basic makefile to compile C files necessary for compiling a shared library, I have an error because the makefile is not recognized:
SOURCES=/home/test/project/sources
OBJECTS=/home/test/project/objects
$(OBJECTS)/%.o:$(SOURCES)/%.c
$(CC) -fPIC -c $^ -o $#
sharedlib: $(OBJECTS)/%.o
$(CC) -shared -o libsharedlib.so $<
When I run make I get that there is no rule for target: $(OBJECTS)/%.o needed by sharedlib. While the rule is written right before sharedlib.
The main problem is that nowhere you are explicitly telling make what your source files are. Start by doing that:
SOURCEDIR=/home/test/project/sources
SOURCES=$(wildcard $(SOURCEDIR)/*.c)
Then, derive the object file names from the source file names by substituting .c for .o:
OBJECTDIR=/home/test/project/objects
OBJECTS=$(patsubst $(SOURCEDIR)/%.c,$(OBJECTDIR)/%.o,$(SOURCES))
You can still keep your generic rule to build object files:
$(OBJECTDIR)/%.o: $(SOURCEDIR)/%.c
$(CC) -fPIC -c $^ -o $#
But you give the explicit list of object files to the rule to make sharedlib:
libsharedlib.so: $(OBJECTS)
$(CC) -shared -o $# $<
Note that I made the name of the rule the same as the file that is being generated. That's important, because calling make twice in a row will then skip building the library a second time. You can always add an alias if you want:
sharedlib: libsharedlib.so
In that case, it's also good to tell make that sharedlib is not a real file:
.PHONY sharedlib
This prevents weird things from happening if you ever did have a file called sharedlib in the directory.
The library rule
sharedlib: $(OBJECTS)/%.o
is not enough to tell Make which objs are needed for the library.
This should work, and gives explicit control on which are the sources/objs pairs you want in the library:
SOURCESDIR=/home/test/project/sources
OBJECTDIR=/home/test/project/objects
OBJLIST = \
$(OBJECTS)/file1.o \
$(OBJECTS)/file2.o
$(OBJECTDIR)/%.o: $(SOURCESDIR)/%.c
$(CC) -fPIC -c $^ -o $#
sharedlib: $(OBJLIST)
$(CC) -shared -o libsharedlib.so $<

Resources