Improving a Makefile - c

I have a make file that I am trying to a make more flexible. So, if I am building an executable, there is primary.c and primary.h. Along with that, there are two other pairs of files that I need to build into the executable: helper_funcs.c / helper_funcs.h and fork.c / fork.h.
CC = gcc
CFLAGS = -c -g -Wall -Wextra
SOURCES = fork.c helper_funcs.c
DEPS = primary.h fork.h helper_funcs.h
OBJECTS = $(SOURCES:.c=.o)
EXECUTABLE = primary
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(OBJECTS) -o $#
.c.o: $(DEPS)
$(CC) $(CFLAGS) $< -o $#
clean:
rm -f *.o
rm -f $(EXECUTABLE)
My goal is to write this make file such that no matter how many additional source files I may have, all I have to do is add them to the SOURCES list and the Makefile will handle the compilation and linking.
When I go to compile this, I get the following:
rm -f *.o
rm -f primary
gcc -c -o fork.o fork.c -c -g -Wall -Wextra
gcc -c -o helper_funcs.o helper_funcs.c -c -g -Wall -Wextra
gcc -c -o primary.o primary.c -c -g -Wall -Wextra
primary.c: In function ‘build_state’:
primary.c:114: warning: implicit declaration of function ‘make_passive’
primary.c:120: warning: implicit declaration of function ‘make_active’
primary.c:127: warning: implicit declaration of function ‘string_builder’
primary.c: In function ‘main’:
primary.c:172: warning: implicit declaration of function ‘read_file’
gcc fork.o helper_funcs.o routed_LS.o -o routed_LS
The functions that it doesn't see are those included in the helper_funcs.c file. It seems to be picking up the functions in fork.c, but I can't understand where the difference lies.
Can anyone help me figure out how to clear these errors? Thanks!

Related

Program_name: linker input file unused because linking not done

I have 6 programs: HOSpital.c, GenPazienti.c, Triage.c, Paziente.c, Prestazione.c and Reparto.c.
No one of them includes any other.
How can i do the makefile?
I tried with:
all: HOSpital GenPazienti Paziente Prestazione Reparto Triage
HOSpital: HOSpital.o
gcc -o HOSpital HOSpital.c
HOSpital.o: HOSpital.c
gcc -c HOSpital HOSpital.c
GenPazienti: GenPazienti.o
gcc -o GenPazienti GenPazienti.c
GenPazienti.o: GenPazienti.c
gcc -c GenPazienti GenPazienti.c
Paziente: Paziente.o
gcc -o Paziente Paziente.c
Paziente.o: Paziente.c
gcc -c Paziente Paziente.c
Prestazione: Prestazione.o
gcc -o Prestazione Pretazione.c
Prestazione.o: Prestazione.c
gcc -c Prestazione Prestazione.c
Reparto: Reparto.o
gcc -o Reparto Reparto.c
Reparto.o: Reparto.c
gcc -c Reparto Reparto.c
Triage: Triage.o
gcc -o Triage Triage.c
Triage.o: Triage.c
gcc -c Triage Triage.c
clean:
rm -f *.o
But if i change something and i type "make" i get the error:
"Program_name: linker input file unused because linking not done"
Lets take a single example:
gcc -c HOSpital HOSpital.c
This will attempt to use HOSpital as an input file.
Either use the correct option to name the output file, -o, and name it correctly. Like in
gcc -c -o HOSpital.o HOSpital.c
Or don't specify the output file name at all, then the compiler will use the input source file and change the .c suffix to .o. Like in
gcc -c HOSpital.c
It's the same problem all over.
Not that it matters in the end, the rule is used so the object file will be built, but you don't actually use the object file:
gcc -o HOSpital HOSpital.c
Here you use the source file directly to create the program. I think you meant to use
gcc -o HOSpital.o HOSpital.o
And as with the previous problem, you make this mistake all over.
Finally some general tips.
First, build with more warnings enabled. It will help you in the long run to find mistakes in the code, and will help find out places where there's possible undefined behaviors. I recommend at least adding -Wall -Wextra -pedantic.
Then you don't need to list all the object files and their rules explicitly in the makefile. The make program already knows how to make e.g. object files through implicit rules.
That last point means you can shorten down the makefile to something like
CFLAGS = -Wall -Wextra -pedantic -pipe
LD = gcc
LDFLAGS = -pipe
HOSpital: HOSpital.o
$(LD) $(LDFLAGS) -o $# $^
GenPazienti: GenPazienti.o
$(LD) $(LDFLAGS) -o $# $^
Paziente: Paziente.o
$(LD) $(LDFLAGS) -o $# $^
Prestazione: Prestazione.o
$(LD) $(LDFLAGS) -o $# $^
Reparto: Reparto.o
$(LD) $(LDFLAGS) -o $# $^
Triage: Triage.o
$(LD) $(LDFLAGS) -o $# $^
clean:
-rm -f *.o
The variable $# is the target of the rule, and the variable $^ is all prerequisites. For e.g.
HOSpital: HOSpital.o
the variable $# is HOSpital and $^ is HOSpital.o.

What does "linker input file unused because linking not done" mean? (C makefile)

I have created a makefile to compile and link my program, however, I can't figure out why I am getting this error. Is it to do with SDL?
GCC = gcc
CFLAGS = -c -std=c99 -lm -Wall -Wextra -pedantic -O3 -Wfloat-equal -g
SDL = -lSDL2 -lSDL2_ttf -lSDL2_image -lSDL2_mixer
all: ./game
game: global.o display.o player.o entities.o controls.o sound.o menu.o
$(GCC) $(CFLAGS) global.o display.o player.o entities.o controls.o sound.o menu.o -o game
global.o: global.c
$(GCC) $(CFLAGS) $(SDL) global.c
display.o: display.c
$(GCC) $(CFLAGS) $(SDL) display.c
player.o: player.c
$(GCC) $(CFLAGS) $(SDL) player.c
entities.o: entities.c
$(GCC) $(CFLAGS) $(SDL) entities.c
controls.o: controls.c
$(GCC) $(CFLAGS) $(SDL) controls.c
sound.o: sound.c
$(GCC) $(CFLAGS) $(SDL) sound.c
menu.o: menu.c
$(GCC) $(CFLAGS) $(SDL) menu.c
clean:
rm *o game
Your linking command expands to:
gcc -c -std=c99 -lm -Wall -Wextra -pedantic -O3 -Wfloat-equal -g global.o display.o player.o entities.o controls.o sound.o menu.o -o game
which, as you can see, has the -c flag in it. The -c flag tells gcc not to do linking. So it has nothing to actually do. (.o files can only be used for linking, and you've disabled linking, which is why you get that message)
You don't want to use the same flags for compiling and linking. For compiling you probably want -c -std=c99 -Wall -Wextra -pedantic -O3 -Wfloat-equal -g, and for linking you want -lm -lSDL2 -lSDL2_ttf -lSDL2_image -lSDL2_mixer -g.
there are several small oversights in the posted makefile.
Amongst them:
library names are only used during the link step, not the compile step
suggest using the 'wildcard' make operator to get a list of the source files. Then use a patterm replacement operator to get a list of the object files:
for instance:
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
when a target (all, clean) will not produce a file of the same name, then insert a .PHONY: statement early in the make file:
similarly to:
.PHONY : all clean
the posted make file has no facilities to handle the associated header files, There are several ways to handle that. This follows the OPs lead and does not handle the header files, so changing a header file will not recompile/relink the effected source files.
this line: rm *o game will not remove the name.o files as it is missing the '.' between the root name and the 'o' extension. Also, the '-f' flag should be used with the 'rm' command.
suggest:
rm -f *.o game
this line: all: ./game can create problems
suggest:
all: game
once the list of object files is created (as above) then the compile rules can be reduced:
by using the make operators:
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $# -I.
the -g parameter to the compiler and linker allows for a debugger to be used. If that debugger is gdb then a better parameter is -ggdb
almost always, there is no need to evaluate a macro definition more than once, so rather than using = in a macro definition, use :=
If you want the game to be executable, then insert a chmod command as the last line in the 'link' rule
Suggest reading about the special operators that can be employed in a makefile to help you understand the following, suggested makefile
It is usually best to replace calls to the shell recognized commands with macros.
CC := /user/bin/gcc
RM := /usr/bin/rm
CFLAGS := -c -std=c99 -Wall -Wextra -pedantic -O3 -Wfloat-equal -ggdb
LFLAGS := -std=c99 -O3 -ggdb
SDL := -lSDL2 -lSDL2_ttf -lSDL2_image -lSDL2_mixer
SRC := $(wildcard *.c)
OBJS := $(SRC:.c=.o)
.PHONY : all clean
all: game
game: $(OBJS)
$(CC) $(LFLAGS) $(OBJS) -o $# $(SDL) -lm
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $# -I.
clean:
$(RM) -f *.o game
Do not put -lm or the SDL libraries into CFLAGS, library operands go to the end of the command line. Instead, use an extra variable LDLIBS and modify your game rule like this:
game: global.o display.o player.o entities.o controls.o sound.o menu.o
$(GCC) $(CFLAGS) -o $# global.o display.o player.o entities.o controls.o sound.o menu.o $(LDLIBS)
The -lm operand (it's not an option) and the operands for SDL only apply when linking, thus it should not be part of CFLAGS and should not be specified when compiling without linking (i.e. when -c is supplied).

Makefile fails with warning message

This is a makefile that fails to link the .o files to make an executeable.
enter code here
CC = c99
CFLAGS = -g -Wall -Wextra -O0
OBJECTS = main.o getoptions.o
P = testprog
$(P): $(OBJECTS)
$(CC) $(OBJECTS) -o $(P)
main.o : main.c
$(CC) $(CFLAGS) $(OBJECTS) -c main.c
getoptions.o : getoptions.c getoptions.h
$(CC) $(CFLAGS) -c getoptions.o
I get this warning:
gcc: warning: getoptions.o: linker input file unused because linking not done
When I manually use:
c99 *.o -o testprog
linking succeeds.
Two issues here:
First, in your target for getoptions.o, you're passing getoptions.o for the -c option. You should be giving it the value of the source file getoptions.c
Second, get rid of $(OBJECTS) in the target for main.o. You don't need to pass in the object files for this step.
With those fixes you'll get a successful compilation:
c99 -g -Wall -Wextra -O0 -c main.c
c99 -g -Wall -Wextra -O0 -c getoptions.c
c99 main.o getoptions.o -o testprog
Edit:
The target line for main.o should be:
main.o : main.c getoptions.h
That way, if getoptions.h changes, main.o gets rebuilt.

Makefile does not make all targets

I am trying to have the compiled obj files in two different folder
dobjects: where the objects have the debug symbol (gcc with -g option)
sobjects: where the objects are compiled without the debug symbols.
Source files are the same,
I have the following makefile.
CC = gcc
CFLAGS = -Wall
OBJS = a.o b.o
SRCS = a.c b.c
SOBJS_DIR = sobjects
DOBJS_DIR = dobjects
SOBJS = $(addprefix $(SOBJS_DIR)/, $(OBJS))
DOBJS = $(addprefix $(DOBJS_DIR)/, $(OBJS))
all: release debug
release: $(SOBJS)
debug: $(DOBJS)
$(DOBJS_DIR)/%.o: CFLAGS += -g
$(DOBJS_DIR)/%.o $(SOBJS_DIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
clean:
rm dobjects/*
rm sobjects/*
But every time I try "make" only one target is made.
$ make
gcc -Wall -c a.c -o sobjects/a.o
gcc -Wall -c b.c -o sobjects/b.o
$ make
gcc -Wall -g -c a.c -o dobjects/a.o
gcc -Wall -g -c b.c -o dobjects/b.o
any help would be greatly appreciated
This rule does not do what you think it does:
$(DOBJS_DIR)/%.o $(SOBJS_DIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
Pattern rules with multiple targets tell make that one single invocation of the recipe will build BOTH targets. So when make runs that rule to build $(DOBJS_DIR)/a.o, make believes that $(SOBJS_DIR)/a.o was also built, so it doesn't try to run the rule to build it. But your rule doesn't actually build it, so when you run make a second time it sees that object file is missing and runs the above rule again, to build the missing one.
You have to write this as two different rules:
$(DOBJS_DIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
$(SOBJS_DIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#

"make clean" causes "make all" failure

When I execute this Makefile without clean, it functions OK and both the shared library and the main executable are created correctly. However, when I add the clean target, the "make all" fails. What could be the reason?
CC = gcc
CFLAGS = -fPIC -Wall -Werror
LDFLAGS = -shared
TARGET_LIB= libnsd.so
lib: nsd.o nd.o
$(CC) $(LDFLAGS) -o ${TARGET_LIB} nsd.o nd.o -lm
nd.o : nd.c nd.h
$(CC) -c $(CFLAGS) nd.c
nsd.o : nsd.c nsd.h
$(CC) -c $(CFLAGS) nsd.c
all: main.c
$(CC) -o -I. -L. main.c -lnsd
clean:
rm -f libnsd.so nd.o nsd.o
Your all: target needs to depend on the lib target, so the library is built first.
The -o argument to the compiler also needs a name for executable it should create.
all: lib main.c
$(CC) -o main -I. -L. main.c -lnsd
Normally you want the target name to be the file that you create, otherwise things get rebuilt when it's not needed. (the lib: target has the same issue) but as an exampe for the executable:
.PHONY: all
all: lib main
main: lib main.c
$(CC) -o main -I. -L. main.c -lnsd
nos's answer is on the right track.
It only appeared to work before, because you happened to run make in the right order. It won't work after a clean operation because, as nos points out, you have not declared all of your prerequisites. The rule that links main.o must depend on the shared library target, so make knows the right order to build things.
Also, you REALLY want your targets to be the actual file you're building. If they're something else, then make will always think they're out of date even if you haven't changed anything, and always rebuild them.
Something like this will be better:
CC = gcc
CFLAGS = -fPIC -Wall -Werror
CPPFLAGS = -I.
LDFLAGS = -shared
PROGRAM = main
TARGET_LIB= libnsd.so
all: $(PROGRAM)
$(PROGRAM): main.o $(TARGET_LIB)
$(CC) -o $# -L. main.o -lnsd
$(TARGET_LIB): nsd.o nd.o
$(CC) $(LDFLAGS) -o $# nsd.o nd.o -lm
nd.o : nd.c nd.h
nsd.o : nsd.c nsd.h
clean:
rm -f libnsd.so *.o

Resources