Linking header files with makefile: undefined reference error - c

I have a project with the following files, all in the same folder
client.c
server.c
reliable_udp.h
reliable_udp.c
conf.h
Among the other libraries, client.c includes also reliable_udp.h ( #include "reliable_udp.h") in order to use the functions packet_send and print_conf (that are implemented in reliable_udp.c).
I'm new to Makefiles, and I'm trying to write one:
CC = gcc
CFLAGS = -Wall -Wextra -Wpedantic -O3
SRC = client.c server.c
OBJ = $(SRC:.c=.o)
all: $(OBJ)
${CC} ${CLFAGS} client.o -o client
${CC} ${CLFAGS} server.o -o server
client.o: reliable_udp.h
clean:
rm -f *.o core
cleanall:
rm -f *.o core client server
If I try to run make, I get the following output:
gcc -Wall -Wextra -Wpedantic -O3 -c -o client.o client.c
gcc client.o -o client
client.o: In function `main':
client.c:(.text.startup+0x84): undefined reference to `packet_send'
client.c:(.text.startup+0x8b): undefined reference to `print_conf'
collect2: error: ld returned 1 exit status
Makefile:7: recipe for target 'all' failed
make: *** [all] Error 1
Obviously I'm failing writing correctly the Makefile. How should I fix it? Why am I getting this error?

Why am I getting this error?
Because the link recipes do not include the 'reliable_udp.0' object and because nothing in the makefile will compile 'reliable_udp.c into 'reliable_udp.o`
the posted makefile contains several problems, as expressed in the comments to the question.
The following is a proposed, simple makefile that should perform the desired functionality.
Note: replace <tab> with a tab character
Note: in the following makefile, the invocation command can be:
make -- to generate both 'client' and 'server'
as it will use the first target, which is 'all'
make all -- to generate both 'client' and 'server'
make client -- to only generate the 'client' executable
make server -- to only generate the 'server' executable
make clean -- to delete the object files
make cleanall -- to delete the object files and the executables
and now the proposed makefile
#use ':=' rather than '=' so macros only evaluated once
#assure the desired utilities are used
CC := /usr/bin/gcc
RM := /usr/bin/rm -f
CFLAGS := -Wall -Wextra -Wpedantic -std=GNU11 -O3
#generate a list of all the source files
SRC := client.c server.c reliable_udp.c
#generate a list of all the object file names
OBJ := $(SRC:.c=.o)
#let make know that the target 'all' will not produce a file of the same name
#notice the 'all' target dependencies are the final executables
.PHONY: all
all: client server
#this will perform all the compiles
#while expecting the user supplied header files to be in the local directory
%.o:%.c
<tab>$(CC) -c $(CFLAGS) $^ -o $# -I.
#link the 'client' executable
client: client.o reliable_udp.o
<tab>${CC} $^ -o $#
#link the 'server' executable
server: server.o reliable_udp.o
<tab>${CC} $^ -o $#
#let make know that this target will not produce a file of the same name
.PHONY: clean
clean:
<tab>$(RM) $(OBJ) core
#let make know that this target will not produce a file of the same name
.PHONY: cleanall
cleanall:
<tab>$(RM) $(OBJ) core client server

A quick fix would be to modify the Makefile as follows:
all: $(OBJ)
${CC} ${CLFAGS} reliable_udp.o client.o -o client
${CC} ${CLFAGS} reliable_udp.o server.o -o server
It's not pretty though, in "real world" a better option might be to make a shared library for "reliable_udp", or at least refactor Makefile a little bit.
The reason of the error is that "reliable_udp" is not compiled in to the final binaries, since it's not explicitly specified anywhere in the makefile.

Related

Add flags on Makefile compilation only if a parameter is given

I would like to know how the CFLAGS variable could be removed from the compilation and added when a parameter is given to the Makefile like "make cflags" without having to duplicate the compilation.
Here is a part of my Makefile :
EXE = $(PATH_EXE)/COLLECTEUR
all: ${EXE}
clean:
rm -f ${PATH_OBJ}/*.o
rm -f ${PATH_EXE}/*
clean_bin:
rm -f ${PATH_EXE}/*
link:
rm -f ${PATH_EXE}/*
$(PATH_EXE)/COLLECTEUR: $(PATH_OBJ)/Test.o $(OBJS)
${LD} ${CFLAGS} ${OBJS} $(PATH_OBJ)/Test.o ${LDFLAGS} -o $#
$(PATH_OBJ)/%.o : %.c
${CC} ${CFLAGS} $< -o $#
The general trick in make is to use a feature known as a target specific variable, which allows you to set or append to variables if a specific target is given, like so:
cflags: CFLAGS+=-Wall -Werror
cflags: all
What this says is for the target cflags append -Wall -Werror to the cflags, and the following line says that the cflags target depends on the all target.
Now, I did notice some errors in your compilation options.
The final link line ${LD} will invoke ld, which doesn't take ${CFLAGS} by default, you're probably better off using the compiler driver there as well (replace the ${LD} with ${CC}).
The compilation line for $(PATH_OBJ)/%.o files compiles and links the files, because it's missing the -c option, which instructs the compiler to compile only, and not to link.

makefile makes weird error

So I wrote a program to calculate Caesar cipher but I think it's not really matter - what matter is that when I'm trying to do make the compiler or who checks the syntax of my makefile is throw an error says :
make: *** No rule to make target 'clean.', needed by 'PHONY'. Stop.
In my directory I have 5 files:
main.c
ceasar.c
ceasar.h
parser.c
parser.h
and the makefile looks like:
PHONY : all clean.
CFLAGS = -c -g -Wall
CXXFLAGS = -o
CC = gcc
OBJECTS = main.o ceasar.o parser.o
EXTRA_SRCS = ceasear.h parser.h
all : ex1
ex1 : $(objects)
$(CC) $(CXXFLAGS) ex1 $(objects)
%.o : %.c $(wildcard $(EXTRA_SRCS))
$(CC) $(CFLAGS) $<
clean:
rm *.o
The makefile should clean the objects files when typed make clean
and the line $(wildcard $(EXTRA_SRCS)) should checks if the c file has header file(parser and caeser, not main).
I'm using ubuntu 15.10 and please help me :)
It's possible to specify fictitious target that has as purpose to execute a sequence of operations. These targets do not specify any dependency and must not appear as the first rule, to be carried out only if they are passed as arguments to make command explicitly. Fictitious target is not a file (the file does not exist) it is used to initiate the execution of the command in each case.
CFLAGS = -c -g -Wall
CXXFLAGS = -o
CC = gcc
OBJECTS = main.o ceasar.o parser.o
EXTRA_SRCS = ceasear.h parser.h
all : ex1
ex1 : $(objects)
$(CC) $(CXXFLAGS) ex1 $(objects)
%.o : %.c $(wildcard $(EXTRA_SRCS))
$(CC) $(CFLAGS) $<
.PHONY: clean
clean: rm *.o
Be careful because the fictitious target may be masked by existing files: if accidentally in the directory it creates a file called the same name of the fictitious target then, as the target has no dependencies, and the file already exists, that file does not need to be updated and then the command list will never be executed.

libgcrypt-config --libs: no such file or directory

I'm using gcrypt, but my compiler seems to unable to find it. Here is my makefile. function.c is a function source file containing functions I defined; I also wrote a header file miao.h with function declaration, and gcrypt.h is included in it. main.c is a source file including miao.h. When I do make: .Could anyone help me? This bothers me so long.
CC = gcc
CFLAGS = 'libgcrypt-config --cflags'
LIBS = 'libgcrypt-config --libs'
OBJS = function.o main.o main
all: $(OBJS)
function.o: function.c
$(CC) -c function.c $(CFLAGS)
main.o: main.c
$(CC) -c main.c $(CFLAGS)
main: main.o function.o
$(CC) -o main main.o function.o $(LIBS)
clean:
rm $(OBJS)
the makefile should be written more like the following:
caveat: I was unable to test the makefile as I do not have libgcrypt-config available.
Per the web site: https://gnupg.org/documentation/manuals/gcrypt/Building-sources.html the libgcrypt-config is an executable so should be surrounded by back-ticks, not single quotes so it will be executed in the current shell.
(back ticks on stackoverflow will result in emphasised text but should still be visible as to where they should be placed.)
Note: where I have placed <tab> your actual makefile needs to have a tab character
Note: targets, like all and clean do not produce a file with the same name, so early in the file there needs to be the statement: .PHONY: all clean
when defining a macro, use := rather than = so the macro is only evaluated once.
Any calls to shell functions should be incorporated via a macro, so it is easy to make a change. In general it is best to include the path to the shell function: I wrote this on Linux, your path may be different. Specifying the actual path becomes very important when cross compiling or there are duplicate names visible via the $PATH statement (as can easily be the case with gcc)
Note: the actual libgcrypt-config executable must be in visible via your $PATH environment variable.
Note: all the individual compile statements could be reduced to the following two lines: (and nothing else needed for the compiles)
%.o: %.c
<tab>$(CC) -c $< -o $# -I. $(CFLAGS)
Note: do not place the contents of a rule where the dependencies is expected. This error was noted in the clean: target
the proposed makefile follows:
CC := /usr/bin/gcc
RM := /usr/bin/rm
CFLAGS := `libgcrypt-config --cflags`
LIBS := `libgcrypt-config --libs`
OBJS := function.o main.o main
TARGET := main
.PHONY: all clean
all: $(TARGET)
function.o: function.c
<tab>$(CC) -c function.c $(CFLAGS) -o function.o -I.
main.o: main.c
<tab>$(CC) -c main.c $(CFLAGS) -o main.o -I.
$(TARGET): $(OBJS)
<tab>$(CC) -o $(TARGET) $(OBJS) $(LIBS)
clean:
<tab>$(RM) -f $(OBJS)

When I use "gcc" in makefile, after making it, I got a "cc" output

For example:
There are 3 source files {main.c test1.c test2.c} in the directory
and a directory file named test3,
and there is a source file named test.c in the directory of test3.
Now I want to create a makefile to compile and link these four source files.
And this is my Makefile:
# Cancel statement "CC=gcc"
src:=$(wildcard *.c) test3.c
obj:=$(patsubst %.c,%.o,$(src))
main:$(obj)
gcc -o main $(obj)
.PHONY:clean
clean:
rm *.o *~
When I called make to compile them, I got a output like this:
cc -c -o main.o main.c
cc -c -o test1.o test1.c
cc -c -o test2.o test2.c
cc -c -o test3.o test3/test3.c
gcc -o main main.o test1.o test2.o test3.o
I know 'cc' is linked to 'gcc' in Linux.
What I don't understand is why did Make call cc to compile these four source files, but call gcc to link the object files?
You changed one rule: the one that links the program main from the object files. And when make did that link, you can see it used gcc.
You didn't do anything to change the built-in rules that make is using to compile the object files, so they use the default (the value of the variable CC) which is cc.
You wrote only the rule to link the object files, and allowed Make to use its default rule to decide how to build the object files from the source files.
GNU Make will expose its rules if you ask it with --print-data-base. In this case, it tells us
%.o: %.c
# recipe to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
and
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
and finally
CC = cc
This explains why Make uses cc to compile your C sources. To change that, simply set CC = gcc. Here's a complete Makefile which does that and also makes best use of Make's built-in rules, to help when you need to extend it:
src := $(wildcard *.c) test3.c
obj := $(patsubst %.c,%.o,$(src))
CC = gcc
main: $(obj)
$(LINK.c) -o $# $^ $(LDLIBS)
.PHONY: clean
clean:
$(RM) *.o *~

Handling #include <folder/file.h> in C with makefiles

I am in the process of porting some code that was developed in the codeblocks IDE. I am transferring it to a Linux server where I can only use the command line to compile the code. The code is quite large (maybe 100 files) and I need to update the include commands in many files. For when I try to compile it errors on for instance: #include <gsl/gsl_math.h> with a file cannot be found error. I am assuming it cannot be found because the location of the gsl folder was declared in one of the search directory field options in the IDE. I could go through each file an update to the correct path, but is there a better way of doing this for use with a makefile?
Thanks!
EDIT Makefile In Question
# -c : do not link, just create object file
# -o : output file name
CFLAGS += -c -O2 -I../ctraj -I../cspice/include -I../SGP4 -I../cconj -I../GSL-1.13/include
LIBS = -L../ctraj -lctraj -L../cspice/lib -lcspice -L../SGP4 -lsgp4 -L../cconj -lcconj -L./ -lgsl-0 -lgslcblas-0 -lm
DEPS = light.h ../ctraj/ctraj.h ../cconj/cconj.h
OBJ = light.o tle.o propagator.o orbitfit.o conjunction.o light_displacement.o forces_LF.o
OUT = light.exe
%.o: %.c $(DEPS)
gcc -o $# $< $(CFLAGS)
light: $(OBJ)
cd ../ctraj/; make
gcc -o $(OUT) $(OBJ) $(LIBS)
clean:
rm *.o $(OUT)
Edit 2
Folder Structure
light->(GSL-1.13, Light, cconj, ctraj)
the makefile is inside the Light folder.
Error Message
cd ../ctraj/; make
make[1]: Entering directory `/light/ctraj'
gcc -o forces.o forces.c -c -Wall -Wno-maybe-uninitialized -Wno-unused-but-set-variable -O2 -I../cspice/include -Inrlmsise
In file included from ../Light/../cconj/cconj.h:12:0,
from ../Light/light.h:13,
from forces.c:3:
../Light/../cconj/../GSL-1.13/include/gsl/gsl_blas.h:26:28: fatal error: gsl/gsl_vector.h: No such file or directory
compilation terminated.
make[1]: *** [forces.o] Error 1
make[1]: Leaving directory /light/ctraj'
make: *** [light] Error 2
EDIT 3
Second makefile in cconj
# -c : do not link, just create object file
# -o : output file name
#-L../cconj -lcconj
CFLAGS += -c -O2 -I./ -I../GSL-1.13/include
LIBS = -L./ -lgsl-0 -lgslcblas-0 -lm
INC= -I../GSL-1.13/include
DEPS = cconj.h
OBJ = cconj_util.o ellipse_intersect.o collision_prob_real.o rcs2size.o
OUT = libcconj.a
%.o: %.c $(DEPS)
gcc -o $# $< $(CFLAGS)
cconj: $(OBJ)
ar rcs $(OUT) $(OBJ)
clean:
rm *.o $(OUT)
Try adding this line to your makefile, and tell us if it works:
CFLAGS += -I../GSL-1.13/include
In order to compile source code and produce object files, Make must use a rule. (If you don't put such a rule in the makefile, Make has a default rule for that purpose.) It looks something like this:
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
Without digging too deeply into how that works, we can say that CFLAGS is a list of arguments to be passed to the compiler. When we add -I../GSL-1.13/include, we tell the compiler "if you want to #include something and can't find it elsewhere, look in ../GSL-1.13/include".
If this approach doesn't work, then there's probably a rule in the makefile we must find and alter.
EDIT:
The problem isn't in this makefile (which already contains a reference to GSL-1.13/include). In this command:
cd ../ctraj/; make
this makefile launches a second Make process, which uses the Makefile in light/cconj/. According to the compiler output (gcc -o forces.o ...), that makefile does not include the reference. So try adding the same line there, and if that doesn't work, post that makefile and we'll keep looking.
Use -I option of gcc to specify where to look for includes.

Resources