makefile with two rules for the same target - makefile

I have a makefile to create a library, and I need it to create a 80% library or a complete library, which means a library with 80% of the functions or a library with all of the functions.
When I call make, the "all" rule should create the 80% library (so far so good), and when I call "make complete" the "complete" rule should create the 100% library (still easy), and it should not relink in any case, here I have a problem.
WHAT GOES WELL:
here is what I have :
all: $(NAME)
$(NAME): $(OBJS)
ar -rc $# $^
complete: $(NAME) $(MORE_OBJS)
ar -rc $^
%.o : %.c
gcc -I. -c -o $# $<
.PHONY: complete
so if I run make it goes:
>make
gcc -I. -c -o function01.o function01.c
gcc -I. -c -o function02.o function02.c
gcc -I. -c -o function03.o function03.c
gcc -I. -c -o function04.o function04.c
ar -rc libtest.a function01.o function02.o function03.o function04.o
and make again:
>make
make: Nothing to be done for 'all'.
perfect. then with make complete:
>make complete
gcc -I. -c -o function_05.o function05.c
gcc -I. -c -o function_06.o function06.c
ar -rc libtest.a function05.o function06.o
or of course:
>make fclean
rm *.o
rm libtest.a
>make complete
gcc -I. -c -o function01.o function01.c
gcc -I. -c -o function02.o function02.c
gcc -I. -c -o function03.o function03.c
gcc -I. -c -o function04.o function04.c
ar -rc libtest.a function01.o function02.o function03.o function04.o
gcc -I. -c -o function_05.o function05.c
gcc -I. -c -o function_06.o function06.c
ar -rc libtest.a function05.o function06.o
WHAT GOES WRONG:
but if I prompt make complete again:
>make complete
ar -rc libtest.a function05.o function06.o
I don't recompile but I relink the library.
I've tried a lot of approach, with the target-specific assignment, re-ordering the targets and the rules in many different combination, but I didn't find any way of doing it. am I missing something or is it indeed hard?
also, I can't put the additional functions in another file with its own makefile and use "make -C" to make it and then add it to the library, everything has to be in this makefile and the sources at the root

make complete will always run, because the target name is complete and no file named complete is ever created. So as far as make knows that file is not up to date and needs to be rebuilt.
There is no straightforward way to do this because make doesn't support multiple different recipes creating the same target.
You can fake it out by using a sentinel file to inform make whether the target exists or not. To do this, you need to create the file complete so make can use it to track whether or not it needs to be rebuilt. Try:
complete: $(NAME) $(MORE_OBJS)
ar -rc $^
#touch $#

Related

Libft bonus rule relinks

So, right now my Makefile looks like this
SRCS = (let's say there are some .c files)
BONUS_SRCS = (and there are some _bonus.c files)
OBJS = $(SRCS:.c=.o)
BONUS_OBJS = $(BONUS_SRCS:.c=.o)
HDRS = libft.h
NAME = libft.a
RM = rm -rf
GCC = gcc
AR = ar -crs
FLAGS = -Wall -Wextra -Werror
.c.o:
$(GCC) $(FLAGS) -I includes -c $< -o $(<:.c=.o)
$(NAME): $(OBJS) $(HDRS)
$(AR) $(NAME) $(OBJS)
all: $(NAME)
bonus: $(OBJS) $(BONUS_OBJS) $(HDRS)
$(AR) $(NAME) $(OBJS) $(BONUS_OBJS)
re: clean fclean all
clean:
$(RM) $(OBJS) $(BONUS_OBJS)
fclean: clean
$(RM) $(NAME)
.PHONY:
all clean fclean re bonus
And if I try to make bonus make compiles bonus functions at first, and every other make bonus relinks. Is there any way to tell make not to relink?
By "relink" I mean recreating the libft.a every time I call make bonus.
Example make:
$> make
gcc -Wall -Wextra -Werror -I includes -c test_a.c -o test_a.o
ar -crs libft.a test_a.o
$> make
make: `libft.a' is up to date.
$>
But make bonus:
$> make bonus
gcc -Wall -Wextra -Werror -I includes -c test_a.c -o test_a.o
gcc -Wall -Wextra -Werror -I includes -c test_b.c -o test_b.o
ar -crs libft.a test_a.o test_b.o
$> make bonus
ar -crs libft.a test_a.o test_b.o
$>
And this is confusing as hell.
It's not confusing if you remember that make doesn't have some magic database of information about what it did last time. It has your makefile, and it has the files on the filesystem (and the last modified time that the filesystem tracks).
So when you run make bonus, make looks for a rule that knows how to build the target bonus and finds this rule:
bonus: $(OBJS) $(BONUS_OBJS) $(HDRS)
$(AR) $(NAME) $(OBJS) $(BONUS_OBJS)
This rule tells make that if it runs this recipe the target bonus will be updated. Make sees that the target bonus does not exist (there's no file named bonus on the disk) so it decides that target is out of date and needs to be updated.
But, of course, your recipe does NOT update the target bonus; bonus is not created or updated by this recipe at all.
So, the next time you run make bonus make again looks for a file named bonus, it still doesn't exist, so make again uses the recipe you told it would update that target. And on and on.
Check out Paul's Second Rule of Makefiles.
It should work to adjust your makefile as following
.PHONY: bonus
bonus: $(NAME)

in makefile echoing "compiling" before the compilation

i thought it would be easy but i can't actually figure out nor find on internet, a solution to advertise "compilation of the objects file" (for instance) just before compiling, and avoiding relink in the same time
my makefile would be something like this :
libfrog.a: $(OBJS)
#echo "building the library"
ar -rc $# $^
%.o:%.c
gcc -i. -c -o $# $<
which produce, when prompt "make" :
gcc -I. -c -o file01.o file01.c
gcc -I. -c -o file02.o file02.c
gcc -I. -c -o file03.o file03.c
gcc -I. -c -o file04.o file04.c
gcc -I. -c -o file05.o file05.c
building library
ar -rc libfrog.a file01.o file02.o file03.o file04.o file05.o
but i would like to have :
compilation of the objects files
gcc -I. -c -o file01.o file01.c
gcc -I. -c -o file02.o file02.c
gcc -I. -c -o file03.o file03.c
gcc -I. -c -o file04.o file04.c
gcc -I. -c -o file05.o file05.c
building library
ar -rc libfrog.a file01.o file02.o file03.o file04.o file05.o
now :
1 - if i put an echo before the rule libfrog.a is called (say by creating another first rule), it will print even if i prompt "make" two times and nothing is to be done...
2 - if i put an echo in the rule %.o:%.c it will print for each file
3 - if i put an echo as a dependency of the first rule it will force to relink all the files when prompt "make" again, even when just one file has been modified libfrog.a: echo $(OBJS) (and a rule "echo" which echo the text)...
so I've tried to echo for each compilation but with changing the text to echo nothing, i failed... i tried to create an echo.txt file just to create a rule that would depend on its existence but i failed too. I have no idea if it's possible ?
It's not really simple to do. But if you're using GNU make you can do it with the help of order-only prerequisites:
%.o : %.c | announce
gcc -I. -c -o $# $<
.PHONY: announce
announce:
echo "compilation of the objects files"
Personally I don't think showing this message is needed and I wouldn't add even the above amount of complexity to support it in my makefiles.
But if you really want to do it and you don't want the message to be printed unless some object file needs to be made, you'll have to get really fancy and do something like this:
PRINTED :=
%.o : %.c
$(or $(PRINTED),$(eval PRINTED := :)echo "compilation of the objects files")
gcc -I. -c -o $# $<
Once it's working you'll want to add a # before the first recipe line.

Some implicit makefile?

I am trying to understand makefile.
I took atmega168 bootloader's makefile and simplified it to this:
CC = avr-gcc
override CFLAGS = -g -Wall -Os -mmcu=atmega328p -DF_CPU=16000000L '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' -DBAUD_RATE=57600
atmega328: ATmegaBOOT_168_atmega328.hex
%.elf: ATmegaBOOT_168.o
avr-gcc -g -Wall -Os -mmcu=atmega328p -DF_CPU=16000000L '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' -DBAUD_RATE=57600 -Wl,--section-start=.text=0x7800 -o $# $<
clean:
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex
%.hex: %.elf
avr-objcopy -j .text -j .data -O ihex $< $#
When I ran $ make atmega328 I get:
avr-gcc -g -Wall -Os -mmcu=atmega328p -DF_CPU=16000000L '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' -DBAUD_RATE=57600 -c -o ATmegaBOOT_168.o ATmegaBOOT_168.c
avr-gcc -g -Wall -Os -mmcu=atmega328p -DF_CPU=16000000L '-DMAX_TIME_COUNT=F_CPU>>4' '-DNUM_LED_FLASHES=1' -DBAUD_RATE=57600 -Wl,--section-start=.text=0x7800 -o ATmegaBOOT_168_atmega328.elf ATmegaBOOT_168.o
avr-objcopy -j .text -j .data -O ihex ATmegaBOOT_168_atmega328.elf ATmegaBOOT_168_atmega328.hex
rm ATmegaBOOT_168_atmega328.elf ATmegaBOOT_168.o
Why cannot I remove CC or CFLAGS?
I understand some basics of makefile. I read a lot on the internet, plus went through gnu manual, but I cannot understand the very first output with ATmegaBOOT_168.c. What/How has generated first command?
Was there used some second makefile? If yes, how to find its location?
UPDATE:
If I rename ATmegaBOOT_168.c to ATmegaBOOT_1681.c. Running $ make atmega328 gives:
make: *** No rule to make target 'ATmegaBOOT_168_atmega328.hex', needed by 'atmega328'. Stop.
but the rule is present.
CC and CFLAGS are variables used in the built in implicit rules of GNU make. When you run make, it reads your makefile a bit like:
No target given, so we'll make the first: atmega328. This requires a .hex file.
The .hex file can be generated from a .elf file per the last rule.
.elf files can be generated by the %.elf rule (which here looks like you've broken the pattern, as there's no % in the dependencies).
There's no rule for .o in this file, so the default recipe $(CC) $(CPPFLAGS) $(CFLAGS) -c is used. Since a .c file is found, this rule is applicable and generates the first command. The rule could have been written (as shown in suffix rules):
.c.o:
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $# $<
Backtrack up this list, now that the source has been found, and run the commands.
If the implicit rule variables are left unset, you will typically get programs built for your host system using cc.

How to restore g++/gcc compiling messages

I'm using CentOS 6.5. When I do a make, I typically see the full gcc/g++ commands that the Makefile is executing, like
...
gcc -std=gnu99 -DHAVE_CONFIG_H -I. -I/opt/emacs/emacs-24.3/lib -I../src -I/opt/emacs/emacs-24.3/src -g3 -O2 -MT pthread_sigmask.o -MD -MP -MF .deps/pthread_sigmask.Tpo -c -o pthread_sigmask.o pthread_sigmask.c
...
But in some systems, I only see:
$ make
Building test1.o...
Building test2.o...
...
Is it possible to change the "Building ..." messages back to the full gcc/g++ command output?
The output that you see when you run make with a given makefile
depends on how the makefile is written. You will see the
output that the author of the makefile wants you to see.
If a command in a recipe in the makefile is prefixed with #,
then make will not echo the command. So if my makefile is, e.g.
foobar: foobar.o
gcc -o $# $<
foobar.o: foobar.c
gcc -c -o $# $<
then the output of make will be:
gcc -c -o foobar.o foobar.c
gcc -o foobar foobar.o
But if I change the makefile to:
foobar: foobar.o
#echo "Linking foobar"
#gcc -o $# $<
foobar.o: foobar.c
#echo "Compiling foobar"
#gcc -c -o $# $<
then the output becomes:
Compiling foobar
Linking foobar
So to see the output that you would prefer to see you will have to edit the
makefile, removing the #-prefixes from the commands you expect to see
and deleting entirely the commands that print the "Building..." messages.
At least, this is what you would need to do if the makefiles that bother
you in this way build the target using recipes that directly invoke gcc/g++. It
is possible that they build their targets using recipes that invoke some intermediate
tool that doesn't echo the compiler commands and instead emits the "Building..."
messages. Without seeing the makefile(s) I can't say.

makefile which get also the name of the file compile

I need a makefile which get also the name of the file compile
For example:
make foo
and the makefile should compile foo.c to foo.
This is my makefile. How to change it?
all: out
out: out.o
gcc -g -m32 -Wall -o out out.o
out.o: out.c
gcc -m32 -g -Wall -ansi -c -o out.o out.c
.PHONY: clean
#Clean the build directory
clean:
rm -f *.o out
There is no direct way where you can pass arguments to the Makefile but instead you can take advantage of variables to achieve what you want. Check the modifications done to the Makefile below
NAME ?=out #Default binary generated is out if you dont pass any argument
${NAME}: ${NAME}.o
gcc -g -m32 -Wall -o ${NAME} ${NAME}.o
${NAME}.o: ${NAME}.c
gcc -m32 -g -Wall -ansi -c -o ${NAME}.o out.c
.PHONY: clean
#Clean the build directory
clean:
`rm -f *.o ${NAME}`
And you should call the Makefile by typing
$ make NAME=foo
$ make clean NAME=foo
Passing arguments directly to Make is trivially easy.
Your current makefile can be invoked with make foo, and will compile foo.c to produce foo, because Make has implicit rules for handling cases like foo.c => foo; there will be no error even though "foo" is not the target of any rule. (At least, this is the case with GNU Make 3.81, which is what I am using.)
If you want to control the choice of compiler and flags (as in your out rule), there is more than one way to do it. The simplest (though not strictly the best) is to modify a couple of variables in the makefile:
CC = gcc
CFLAGS = -g -m32 -Wall -ansi
Another option is to override the implicit rule with a pattern rule of your own:
%: %.c
gcc -g -m32 -Wall -ansi -o $# $<
If you want it to build foo.o in a separate step, you must split the rule into two rule-- and also put in a rule with no recipe to cancel Make's implicit rule:
%: %.o
gcc -g -m32 -Wall -o $# $^
%.o: %.c
gcc -m32 -g -Wall -ansi -c -o $# $<
%: %.c
Further refinements are possible, once you have mastered the basics.

Resources