makefile compiling multiples targets - c

This is my first post in this forum. Sorry for bothering but I've been looking for something similar and strangely I couldn't find it. Here's the issue.
I have three (main) files with no headers and I want to compile them either at once (if I simply type "make") or one by one (if I specify the name of the file with no extension). So I built my makefile but something is wrong in the command
$(TARGETS): $(BUILDS_DIR)% : $(SRCS_DIR)%.c
where I got this error
make: *** No rule to make target....
here's the complete file
.SUFFIXES: .c
ROOT = $(addprefix $(PWD), /)
BUILDS_DIR = $(addprefix $(ROOT), builds/)
SRCS_DIR = $(addprefix $(ROOT), src/)
SRCS = $(wildcard $(SRCS_DIR)*.c)
TARGETS = ${SRCS:$(SRCS_DIR)%.c=%}
EXES = ${addprefix $(BUILDS_DIR), $(TARGETS)}
CC = gcc
CFLAGS = -Wall -O3
RM = rm -f
.PHONY: all $(TARGETS) clean
all: $(TARGETS)
$(TARGETS): $(BUILDS_DIR)% : $(SRCS_DIR)%.c
$(CC) $(CFLAGS) \
$< \
-o $#
#echo -e "\n\n\t\t*** Compile successfully! ***\n" ;
clean:
$(RM) $(EXES) \
$(SRCS_DIR)*~
#echo -e "\n\n\t\t*** Cleanup complete! ***\n"
Where am I wrong? I guess the answer is very silly and probably based on a basic error.
thanks in advance

Assuming GNU Make (since you use its syntax).
The, or the first, problem is that you are trying to rewrite the target static pattern incorrectly, by trying to concatenate the target directory to the pattern, rather than simply using the target's filename.
You had:
$(TARGETS): $(BUILDS_DIR)% : $(SRCS_DIR)%.c
$(CC) $(CFLAGS) $< -o $#
The solution is to use add the directory path on the command line
$(TARGETS): % : $(SRCS_DIR)%.c
$(CC) $(CFLAGS) $< -o $(BUILDS_DIR)$#

Lets assume that your three source files are file1.c, file2.c and file3.c. I would created the makefile to look like this (assuming GNU make)
CC = gcc
CFLAGS = -ansi -Wall -pedantic
RM = rm -f
OBJS = file1.o file2.o file3.o
PROG=my_program
$(PROG) : $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $(PROG)
all : clean $(PROG)
file1 : file1.c
$(CC) $(CFLAGS) -c file1.c -o file1.o
file2 : file2.c
$(CC) $(CFLAGS) -c file2.c -o file2.o
file3 : file3.c
$(CC) $(CFLAGS) -c file3.c -o file3.o
clean :
$(RM) *.o $(PROG) *.*~
A sample using this make file is (I use the -n to show what rules would be run, but not actually run them because my source files are empty files for testing.)
[******#broadsword junk]$ make -n
gcc -ansi -Wall -pedantic -c -o file1.o file1.c
gcc -ansi -Wall -pedantic -c -o file2.o file2.c
gcc -ansi -Wall -pedantic -c -o file3.o file3.c
gcc -ansi -Wall -pedantic file1.o file2.o file3.o -o my_program
[******#broadsword junk]$ make -n file1
gcc -ansi -Wall -pedantic -c file1.c -o file1.o
We can shorten the above make file my making use of wild-cards;
CC = gcc
CFLAGS = -ansi -Wall -pedantic
RM = rm -f
OBJS = file1.o file2.o file3.o
PROG=my_program
$(PROG) : $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $(PROG)
all : clean $(PROG)
% : %.c
$(CC) $(CFLAGS) -c $< -o $#.o
clean :
$(RM) *.o $(PROG) .~
We need to append a '.o' to the output file name so that we are creating files in the format defined by the $(OBJ) variable of the first build rule works correctly. Doing this gives the following example runs:
[******#broadsword junk]$ make -n
gcc -ansi -Wall -pedantic -c -o file1.o file1.c
gcc -ansi -Wall -pedantic -c -o file2.o file2.c
gcc -ansi -Wall -pedantic -c -o file3.o file3.c
gcc -ansi -Wall -pedantic file1.o file2.o file3.o -o my_program
[******#broadsword junk]$ make -n file2
gcc -ansi -Wall -pedantic -c file2.c -o file2.o
BTW, I personally don't mind typing an extra two characters and I like having my target match the output of the set of rules that get run, so I would write the rules as either
file1.o : file1.c
$(CC) $(CFLAGS) -c file1.c -o file1.o
or
%.o :%.c
$(CC) $(CFLAGS) -c $< -o $#
Finally I strongly suspect that when we execute make or make all, we are not running the file-specific rules in the lower part of the makefile, rather we are running the the built in rule described in the GNU manual as: "n.o is made automatically from n.c with a recipe of the form $(CC) $(CPPFLAGS) $(CFLAGS) -c".

Related

makefile not changing input filename

I am trying to make a C program and have the following makefile:
CC=clang
CFLAGS=-std=c99 -Wall -pedantic
LDFLAGS=
LDLIBS=
OUT=nes_slop
SRC_DIR=src/
OBJ_DIR=obj/
SRCS=$(wildcard $(SRC_DIR)*.c)
OBJS=$(addprefix $(OBJ_DIR),$(notdir $(SRCS:.c=.o)))
MAKE=make
CLEAR=TRUE
all: clean $(OUT)
clean:
rm -i $(OUT) $(OBJS) -f
$(OUT): $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $(OUT)
$(OBJS): $(SRCS)
$(CC) -c $(CFLAGS) $(LDLIBS) $< -o $#
It was all well and good until I had more than 1 .c file:
clang -c -std=c99 -Wall -pedantic -lncurses src/gamestate.c -o obj/gamestate.o
clang -c -std=c99 -Wall -pedantic -lncurses src/gamestate.c -o obj/main.o
so, somehow the source file is not being updated, it's always gamestate.c... what's wrong with my makefile? any help is appreciated, thank you
In short, your rule should look something like this:
$(OBJS): %.o: %.c
$(CC) -c $(CFLAGS) $(LDLIBS) $< -o $#
You may also want to read this for how to generate automatic dependencies (so if you change a header file, your c files will automatically regenerate as needed) There's a TL;DR section at the top of that page, if you're not interested in the details.

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).

Make does not compile good files

I've got a problem with a Makefile, it just compiles many time the same file.
Here are my files:
$ ls *
carnet.data carnet.l carnet.y Makefile
struct:
carnet.c carnet.h ihm.c ihm.h struct.c struct.h
Here is my Makefile:
CC = gcc
LEX = lex
YACC = yacc
FLAGS = -Wall -Wextra -Werror -O3 -g
ELIB = -lfl # Flex library
TARGET = carnet
SRC = $(shell find struct/ -name "*.c")
OBJ = $(SRC:.c=.o)
SRCL = $(shell find -name "*.l")
OBJL = lex.yy.o
SRCY = $(shell find -name "*.y")
OBJY = y.tab.o
all : $(TARGET)
$(TARGET) : $(OBJ) $(OBJY) $(OBJL)
#echo "Linking"
#echo $(SRC)
#echo $(OBJ)
#$(CC) $^ -o $# $(FLAGS) $(ELIB)
$(OBJY) : $(SRCY)
#echo $<
#$(YACC) -d $<
#$(CC) -c y.tab.c -o $#
$(OBJL) : $(SRCL)
#echo $<
#$(LEX) $<
#$(CC) -c lex.yy.c -o $#
$(OBJ) : $(SRC)
#echo $<
$(CC) -c $< -o $# $(FLAGS)
clean :
rm y.tab.c $(OBJY) y.tab.h lex.yy.c $(OBJL)
rm $(OBJ)
destroy :
rm $(TARGET)
rebuilt : destroy mrpropper
mrpropper : all clean
And here is the output when I do a 'make':
struct/struct.c
gcc -c struct/struct.c -o struct/struct.o -Wall -Wextra -Werror -O3 -g
struct/struct.c
gcc -c struct/struct.c -o struct/carnet.o -Wall -Wextra -Werror -O3 -g
struct/struct.c
gcc -c struct/struct.c -o struct/ihm.o -Wall -Wextra -Werror -O3 -g
carnet.y
carnet.l
Linking
struct/struct.c struct/carnet.c struct/ihm.c
struct/struct.o struct/carnet.o struct/ihm.o
As we can see, when I do a 'echo $(SRC)' he finds all three files, but he only compiles the 'struct.c' file, and I don't understand why !
Thanks for your help,
Phantom
SRC = $(shell find struct/ -name "*.c")
You create a list here, $(SRC) will be struct/struct.c struct/carnet.c struct/ihm.c. Or any other order find may return, but according to your result, this seems to be the order.
OBJ = $(SRC:.c=.o)
This creates the modified list struct/struct.o struct/carnet.o struct/ihm.o
$(OBJ) : $(SRC)
#echo $<
$(CC) -c $< -o $# $(FLAGS)
Here we go, (partial, for clarity) expansion leads to
struct/struct.o struct/carnet.o struct/ihm.o : struct/struct.c struct/carnet.c struct/ihm.c
#echo $<
$(CC) -c $< -o $# $(FLAGS)
So you have a rule applied for building 3 targets, fine. Now, $< expands to the first prerequisite, which is struct/struct.c here.
One possible (and common) solution if you use a make capable of it, e.g. GNU make, is to use pattern rules instead of this find-hack:
struct/%.o : struct/%.c
#echo $<
$(CC) -c $< -o $# $(FLAGS)
Note that normally, you just maintain ONE list of the modules of your taget in your Makefile, usually the object files, manually, like here:
OBJS:= struct/struct.o struct/carnet.o struct/ihm.o

GCC default parameters (-Werror -Wall..)

currently I'm using this command to compile my .c files in Mint
gcc -std=gnu99 -Wall -Werror filename.c -o filename [-lm]
How do I make these parameters default, perhaps include them in the make filename.c command? Thanks :)
You need to write makefile like
CC = gcc
EXEC = filename
OBJS = filename.o \
FLAGS = -std=gnu99 -Wall -Werror
LDLIBS = -lm
all: $(EXEC)
$(EXEC): $(OBJS)
$(CC) $(FLAGS) -o $# $(OBJS) $(LDLIBS)
clean:
-rm -f $(EXEC) *.o
Then run make to compile your file

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 $#

Resources