Add flags on Makefile compilation only if a parameter is given - c

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.

Related

GNU Makefile : How to use pattern-rule adding a compilation flag to a match-anything pattern-rule by using pattern-specific variable value?

I have created several test files test_*.c, each testing a single function of a c library I built.
I first wrote a Makefile for compiling each c file to produce its corresponding binary:
TEST_SRCS = ${wildcard *.c}
TEST_EXECS = ${TEST_SRCS:.c=}
PROJECT_PATH = ../my_project
CFLAGS = -Wall -Wextra -Werror
%:: %.c ${PROJECT_PATH}/libmyproject.a
gcc ${CFLAGS} $< -L${PROJECT_PATH} -lmyproject -o $#
all: ${TEST_EXECS}
clean:
rm -f ${TEST_EXECS}
re: clean all
.PHONY: all clean re
This works as expected, so when i type make test_<name_of_my_function> and if the 'test_<name_of_my_function>.c' file exists, it compiles it to create the 'test_<name_of_my_function>' binary.
But now i want to add a rule that creates the binary in debug mode by adding the gcc flag -g to the command if i run the command make debug_test_<name_of_my_function>.
I tried adding the pattern-specific rule debug_% and use a pattern-specific value for appending -g to CFLAGS:
TEST_SRCS = ${wildcard *.c}
TEST_EXECS = ${TEST_SRCS:.c=}
PROJECT_PATH = ../my_project
CFLAGS = -Wall -Wextra -Werror
%:: %.c ${PROJECT_PATH}/libmyproject.a
gcc ${CFLAGS} $< -L${PROJECT_PATH} -lmyproject -o $#
all: ${TEST_EXECS}
debug_%: CFLAGS += -g
debug_%: %
clean:
rm -f ${TEST_EXECS}
re: clean all
.PHONY: all clean re
But when i run for example debug_test_function1, i get the following ouptut :
make: *** No rule to make target 'debug_test_function1'. Stop.
Note that whatever prerequisite rule i use for the target debug_%, it isn't executed (even if the prerequisite is not a pattern rule).
Note also that if i replace in the makefile
debug_%: CFLAGS += -g
debug_%: %
by
debug%: %.c ${PROJECT_PATH}/libft.a
gcc ${CFLAGS} -g $< -L${PROJECT_PATH} -lmyproject -o $#
it works. But i'd lose the benefit of using a pattern-specific variable here.
Any clue oh how to use pattern-specific variable values to do it?
Thank you for your help !
This:
debug_%: %
does not define a pattern rule. It deletes a pattern rule. See the GNU make manual. So, you've not defined any rules here that know how to build debug_test_function1 (because there's no file debug_test_function1.c to build it from and the only rule you have available is the match-anything rule).
You have to provide the recipe here, you cannot omit it. But obviously you can still add a pattern-specific variable; why not?:
debug_%: CFLAGS += -g
debug_%: %.c ${PROJECT_PATH}/libft.a
gcc ${CFLAGS} $< -L${PROJECT_PATH} -lmyproject -o $#
I'm not really sure what "benefit of pattern-specific variables" you are referring to since you don't seem to build an other prerequisites that need to inherit the pattern-specific variable. But the above should work.

Makefile does not compile the current changes .c file

I am writing a makefile for my program, but whenever i do make in my pwd, it is not showing with the latest changes made in .c file. What am i doing wrong with this ?
web : mweb.o
gcc -o bin/web bin/web.o
mweb.o : src/web.c
gcc -c -std=c99 -Wall src/web.c -o bin/web.o
clean:
rm -f web
It's always wrong for your makefile rules to create files that are not the identical pathname of the target you provided in your rule. So:
<target>: ...
<command>
The <command> must create the file named by <target>.
Here, your <target> in the first rule is web, but the compile command you gave creates the file bin/web. Your <target> on the second rule is mweb.o but the compile command creates the file bin/web.o.
That cannot work.
The best thing to do is use make's $# automatic variable: those are set by make and always contain the files that make expects you to create.
CFLAGS = -std=c99 -Wall
bin/web : bin/mweb.o
$(CC) $(CFLAGS) -o $# $^
bin/mweb.o : src/web.c
$(CC) -c $(CFLAGS) $< -o $#
clean:
rm -f web

Why am I getting this error Makefile: No rule to make target 'timer.c', needed by 'timer.o'. Stop

My working directory looks like this:
main.c
Makefile
my_memmove.h
my_memmove.c
c-timer-lib
timer.c
timer.h
My makefile looks like this:
CC := gcc
CFLAGS := -std=gnu99 -g -Wall -Wextra -Ic-timer-lib
TARGET := output
output: main.o my_memmove.o timer.o
$(CC) $(CFLAGS) main.o my_memmove.o timer.o -o $(TARGET)
main.o: main.c
gcc -c main.c
my_memmove.o: my_memmove.c my_memmove.h
gcc -c my_memmove.c
timer.o: c-timer-lib/timer.c c-timer-lib/timer.h
gcc -c c-timer-lib/timer.c -o $#
clean:
rm *.o $(TARGET)
I don't understand why I keep getting the "Makefile: No rule to make target 'timer.c', needed by 'timer.o'. Stop." error. I believe that it's because the timer.c and timer.h files can't be found.
So much confusion here! :)
First, this is definitely wrong:
$(CC) $(CFLAGS) -I main.o ...
The -I main.o tells the compiler that it should use main.o as the name of a directory to search for include files. That clearly won't work. You should remove the -I here.
On to your problem: you have to realize that there are two completely different programs at play here: make which figures out how to run commands, and the commands that are being run, in this case the compiler gcc.
The -I option is an option to the compiler so that the compiler knows where to look for header files that are included by your source code with #include.
That option means nothing to make; it doesn't understand that option. It's just some text to pass to the compiler. Make is looking for the source file timer.c and it can't find it because you haven't told make where it is.
You have to write your rule to look in the correct place, like this:
timer.o: c-timer-lib/timer.c c-timer-lib/timer.h
gcc -c c-timer-lib/timer.c -o $#
(you should always use -o $# so that your compile line puts the output file where make expects to find it, which will be put into the $# variable by make before it evaluates your recipe.)
ETA
Also, are you sure that -DUNITS="ms" is right? We can't tell without seeing how UNITS is used in the source, but I suspect you probably need an extra level of quotes here, like -DUNITS='"ms"'
Really, you are trying to do too much in this makefile. Make already knows how to correctly build object files from source files. If you don't force the issue by writing your own rules, then make's built-in rules will do the job for you. Your makefile can be written like this:
CC := gcc
CFLAGS := -std=gnu99 -g -Wall -Wextra -Ic-timer-lib -DUNITS='"ms"'
TARGET := output
$(TARGET): main.o my_memmove.o c-timer-lib/timer.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $^ $(LDLIBS)
my_memmove.o: my_memmove.h
c-timer-lib/timer.o: c-timer-lib/timer.h
clean:
rm *.o $(TARGET)
make doesn't know which headers your source requires so you have to add the prerequisites by hand, although you can add extra rules to allow it to figure that out for itself.

Why does my Makefile do nothing?

#
# MakeFile assignment 2
# Variables
CC=gcc
LINK=gcc
CFLAGS=-c -Wall -I.
OBJECT_FILES = cmpsc311-f13-assign2.o a2support.o
#Suffix rules
.SUFFIXES: .c .o
.c.o:
$(CC) -c $(CFLAGS) -o $# $<
#Productions
cmpsc311-f13-assign2 : $(OBJECT_FILES)
$(LINK) $(OBJECT_FILES) -o $#
#Dependencies
cmpsc311-f13-assign2.o : cmpsc311-f13-assign2.c a2support.h
a2support.o : a2support.c a2support.h
clean:
rm cmpsc311-f13-assign2.o
rm a2support.o
Every time I use the command make Makefile it does nothing, is there something wrong with my makefile or is it another issue?
Running the following command also dose nothing:
gcc -o cmpsc311-f13-assign2 cmpsc311-f13-assign2.c a2support.c a2support.h -I.
Every time I use the command make Makefile it does nothing
make Makefile tries to create Makefile. Since you don't have any rule to create it, there's nothing to do.
Usually make is invoked with no arguments; it uses Makefile by default, and tries to make the first target defined (in your case, cmpsc311-f13-assign2).
You can use the -f option to specify a different makefile to use:
make -f foo.mk
or you can use an argument to specify what to build:
make clean
or both:
make -f foo.mk clean
Apart from the answer mentioned above you also need to add a TAB character at line 14.
$(CC) -c $(CFLAGS) -o $# $<

How can I write Makefile (with sub Makfile ) more concise

When I do practice , I have a practice path.
Under this path , I have an Include path named myInclude (I have some useful function is this folder and I always use it.)
And a code path named symbol_try.I always make add new folder (with a c file and main function in it) in symbol_try and compile it.
Each time I have to compile it by gcc in terminal .Its a boring work , so I write a Makefile.
Here is an example:
the main Makefile in practice path:
FOBJS=
include myInclude/Rule.mk
include symbol_try/codeList_13.1/Rule.mk
symbol:$(FOBJS) <==What exactly I what . A executable file.
gcc -o symbol $(FOBJS) -pthread -lpthread
subsystem:
cd myInclude/ && $(MAKE)
cd symbol_try/codeList_13.1/ &&$(MAKE)
clean:
rm -rf symbol
In the myInclude/Rule.mk
FOBJS+=myInclude/otherFunction.o myInclude/error.o \
myInclude/unit.o myInclude/unitTest.o\
In the symbol_try/codeList_13.1/Rule.mk
FOBJS+=symbol_try/codeList_13.1/codeList_13.1.o
In myInclude/Makefile:
OBJS=otherFunction.o error.o unit.o unitTest.o
ALL:$(OBJS)
.PHONY:ALL
$(OBJS):%.o:%.c
gcc -c $< -o $#
clean :
otherFunction.o error.o unit.o
In symbol_try/codeList_13.1/Makefile:
codeList_13.1.o:codeList_13.1.c
gcc -c codeList_13.1.c
Well.That can work. But as you see , I have to write a Rule.mk(to initialize the FOBJS) and a Makefile for each folder.
I am new for make , I want find a way more concise , witch I only need write one Makefile for each folder and a main Makefile.No Rule.mk any more.
PS: I always change the code in myInclude ,so I don't want to build it a library.
Thanks for any help.
Here's one way you can do it with just one Makefile:
CC = gcc
CPPFLAGS += -I myInclude/ (1)
CFLAGS += -std=c99 -Wall (2)
VPATH = myInclude/ \ (3)
symbol_try/codeList_13.1/
symbol: otherFunction.o error.o unit.o unitTest.o codeList_13.1.o (4)
$(CC) -o $# $^ (5)
.PHONY : clean
clean:
rm -f symbol *.o
Note that make knows how to build C files and has some standard macros: CC, CPPFLGAS, CFLAGS
Add the include paths of your headers. You presumably have some headers for the individual object files in the myInclude directory.
Put the compiler flags here.
Add the paths to the source files you want to build.
List the object files that the executable depends upon
As there is no file called symbol.c you need to tell make how to create symbol.o with a rule. $# means the target ('symbol', here), and $^ means all of the prerequisites (the object files listed).
Here's a list of all of the files in my test directories for this:
$ find . -type f
.
./Makefile
./myInclude/error.c
./myInclude/header.h
./myInclude/otherFunction.c
./myInclude/unit.c
./myInclude/unitTest.c
./symbol_try/codeList_13.1/codeList_13.1.c
And the build output:
$ make
gcc -std=c99 -Wall -I myInclude/ -c -o otherFunction.o myInclude/otherFunction.c
gcc -std=c99 -Wall -I myInclude/ -c -o error.o myInclude/error.c
gcc -std=c99 -Wall -I myInclude/ -c -o unit.o myInclude/unit.c
gcc -std=c99 -Wall -I myInclude/ -c -o unitTest.o myInclude/unitTest.c
gcc -std=c99 -Wall -I myInclude/ -c -o codeList_13.1.o symbol_try/codeList_13.1/codeList_13.1.c
gcc -o symbol otherFunction.o error.o unit.o unitTest.o codeList_13.1.o
Why don't you create a library from the objects in myInclude and do the linking in the Makefile in your code path (symbol_try/codeList_13.1). The latter is better anyway because the needed libraries (-pthread -lpthread in your case) might change as well for some other code.
The main Makefile now would have got nothing to do but call make in all needed subdirectories.
In each folder have a makefile with
SOURCES=sample.c sampletest.c
OBJECTS=$(SOURCES:%.c=$(OBJDIR)/%.o)
all: $(OBJECTS)
$(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) -o $# $<
In the root directory of a project, create a makefile with a rule to compile every sub-folder like the below.
Dirs= path-to-rootdir
objs:
set -e ; \
for i in $(Dirs) ; do \
$(MAKE) CC="$(CC)" CFLAGS="$(CFLAGS_MODULE)" LDFLAGS="$(LDFLAGS)" OBJDIR="$(OBJDIR)" -C $$i; \
done
And then you could use it build the executable by adding a rule
EXE: objs
$(CC) -L./Path1 $(LIB_PATH) -llib1 -o $(EXE_NAME) $(wildcard $(OBJDIR)/*.o)
Hope this helps!!!

Resources