Make does not compile good files - c

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

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.

How to make a Makefile that includes my header?

I am new to c programming, and I am having a problem with making Makefile for it.
I did like
CC = gcc
CFLAGS = -fsanitize=address -g -Wall -Wvla
OUTPUT = prac
all: $(OUTPUT)
mymalloc.o: mymalloc.c mymalloc.h
$(CC) $(CFLAGS) -c $# mymalloc.c
%: %.c
$(CC) $(CFLAGS) -o $# mymalloc.o $^
and I try to make file with just typing "make"
But it keep says
gcc -fsanitize=address -g -Wall -Wvla -o prac mymalloc.o prac.c
clang: error: no such file or directory: 'mymalloc.o'
make: *** [prac] Error 1
whenever I try to make it , did I do something wrong?
Thank you.
Edit)
I got it right with using this!
CC = gcc
CFLAGS = -fsanitize=address -g -Wall -Wvla
DEPS = mymalloc.h
OBJS = prac.o mymalloc.o
%.o: %.c $(DEPS)
$(CC) $(CFLAGS) -c -o $# $<
prac: $(OBJS)
$(CC) $(CFLAGS) -o $# $^
You need to make the executable dependent on mymalloc.o:
%: %.c mymalloc.o
$(CC) $(CFLAGS) -o $# mymalloc.o $^
The dependency tells make that it needs to execute the rule for creating mymalloc.o.
Also your rule for making mymalloc.o is wrong. You need -o before $#:
mymalloc.o: mymalloc.c mymalloc.h
$(CC) $(CFLAGS) -c -o $# mymalloc.c
Otherwise it's trying to use the output file as one of the input files.

Multiple targets but same dependency

This is a part of my makefile :
SRC = ./
DIRS = src libs/maths libs/struct
BIN_DIR = ./bin/
SRC_DIRS= $(foreach dir, $(DIRS), $(addprefix $(SRC), $(dir)))
SRC_TEST= $(sort $(SRC_DIRS))
SRCS = $(foreach msrc, $(SRC_DIRS), $(wildcard $(msrc)/*.c))
DEL_PRE = $(foreach target, $(SRCS), $(notdir $(target)))
ADD_PRE = $(foreach target, $(DEL_PRE), $(addprefix $(BIN_DIR), $(target)))
OBJS = $(ADD_PRE:.c=.o)
.PHONY: all clean re
all: $(EXEC)
$(EXEC): $(OBJS)
$(CC) $(OBJS) -o $# $(LDLIBS)
$(OBJS): $(SRCS)
$(CC) -o $# -c $<
When i use make all, i have in output :
gcc -o bin/main.o -c src/main.c
gcc -o bin/cosin.o -c src/main.c
gcc -o bin/pears.o -c src/main.c
gcc -o bin/outil.o -c src/main.c
gcc -o bin/verif.o -c src/main.c
But i would like to have for each target, it assigned dependency :
gcc -o bin/main.o -c src/main.c
gcc -o bin/cosin.o -c libs/maths/cosin.c
gcc -o bin/pears.o -c libs/maths/pears.c
gcc -o bin/outil.o -c libs/struct/outil.c
gcc -o bin/verif.o -c libs/struct/verif.c
How can i fix it ?
This seems like a very common misconception; I just answered effectively this same question yesterday. I'm not sure where it comes from or how to combat it.
This rule:
$(OBJS): $(SRCS)
$(CC) -o $# -c $<
does not somehow magically combine the contents of the OBJS variable and the SRCS variable to figure out how they match up. The variable references are simply expanded, and the result is this:
bin/main.o bin/cosin.o ... : src/main.c libs/maths/cosin.c ...
$(CC) -o $# -c $<
which is the same as if you'd written this:
bin/main.o : src/main.c libs/maths/cosin.c ...
$(CC) -o $# -c $<
bin/cosin.o : src/main.c libs/maths/cosin.c ...
$(CC) -o $# -c $<
...
Now, you can hopefully see why you compile the same file: in every rule you have the same prerequisites, so $< is always the first one, which is always src/main.c.
There are multiple ways to work this but if you really want to have all the source files from different directories compiled into object files in the same directory your job is harder, because there's no common pattern that will match them all. In this case the simplest thing to do is use VPATH for directory search: replace the above rule with this:
$(BIN_DIR)/%.o : %.c
$(CC) -o $# -c $<
then tell make how to find your source files, like this:
VPATH := $(sort $(dir $(SRCS))
Be aware this method can't be used for any source files that are themselves generated output that make is expected to create.

makefile exit with no reason when compile .pc and .c at the same time. very strange

I am using pro*c in AIX,I want make my .pc file compile to a .so libary. And link it. This is my directory:
ls
connect.pc func.c get_log.pc main.c makefile sql_err.pc
This is my makefile:
#Makefile
CC = cc -g -brtl
CFLAGS = -g -c
ESQL = proc
RM = rm -f
MYHOME = /home/xxx
OBJ = main.o func.o
LIBOBJ = get_log.o connect.o sql_err.o
DBINC = -I$(ORACLE_HOME)/precomp/public
DBLIB = -L$(ORACLE_HOME)/lib -lclntsh
INCLUDE = -I$(MYHOME)/include
.SUFFIXES: .pc .c .o
.pc.o:
$(ESQL) include=$(MYHOME)/include iname=$*.pc
$(CC) -o $*.o $(CFLAGS) $*.c $(INCLUDE) $(DBINC) $(DBLIB)
$(RM) $*.c
$(RM) $*.lis
libmydb.so:$(LIBOBJ)
$(CC) -qmkshrobj -o $# $(LIBOBJ) $(DBLIB)
mv $# $(MYHOME)/lib
query:$(OBJ)
cc -o $# $(OBJ) -L$(MYHOME)/lib -lmydb
mv $# $(MYHOME)/bin
func.o:func.c
$(CC) -c $(CFLAGS) $< $(INCLUDE)
main.o:main.c
$(CC) -c $(CFLAGS) $< $(INCLUDE)
clean:
rm -f *.o *.lis
when I make I get this:
.......
cc -g -brtl -o sql_err.o -g -c sql_err.c -I/home/xxx/include -I/oracle/product/10.2.0/precomp/public -L/oracle/product/10.2.0/lib -lclntsh
rm -f sql_err.c
rm -f sql_err.lis
cc -g -brtl -qmkshrobj -o libmydb.so get_log.o connect.o sql_err.o -L/oracle/product/10.2.0/lib -lclntsh
mv libmydb.so /home/xxxlib
when it done mv libmydb.so ,it exit!!!without wrong message.why?? I also need my .c to compile to .o and finally to an executable file query link libmydb.so.
when I change the squeuce like this put .c.o before .pc.o:
query:$(OBJ)
cc -o $# $(OBJ) -L$(MYHOME)/lib -lmydb
mv $# $(MYHOME)/bin
func.o:func.c
$(CC) -c $(CFLAGS) $< $(INCLUDE)
main.o:main.c
$(CC) -c $(CFLAGS) $< $(INCLUDE)
.pc.o:
$(ESQL) include=$(MYHOME)/include iname=$*.pc
$(CC) -o $*.o $(CFLAGS) $*.c $(INCLUDE) $(DBINC) $(DBLIB)
$(RM) $*.c
$(RM) $*.lis
libmydb.so:$(LIBOBJ)
$(CC) -qmkshrobj -o $# $(LIBOBJ) $(DBLIB)
mv $# $(MYHOME)/lib
it give this message,although I have libmydb.so last step:
prepaid(wmfe)/home/xxx/src>make
cc -g -brtl -c -g -c main.c -I/home/xxx/include
cc -g -brtl -c -g -c func.c -I/home/xxx/include
cc -o query main.o func.o -L/home/xxx/lib -lmydb
ld: 0706-006 Cannot find or open library file: -l mydb
ld:open(): A file or directory in the path name does not exist.
make: 1254-004 The error code from the last command is 255.
Stop.
I can't handle this ,very strange,Help!!
By default make will make the first rule in your makefile, but it must not start with a dot. So the default rule in your makefile is libmydb.so and that is being built.
That rule is only dependent on the LIBOBJ and OBJ is not a dependency so it doesn't care about those. It doesn't exit with no reason, it exits because it has done the job you defined for it. There is no error to report.
If you change the order then the default rule is changed and it tries to compile query. This has no dependencies to the library, so it doesn't try to compile that.
If you want to compile everything you should have, for example, a rule all that lists the dependencies. In this case probably libmydb.so and query at least, in correct order. If this is the first rule it will be the default and your compilation will succeed.

makefile compiling multiples targets

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

Resources