Reputation: 353
% in my makefile didn't work.
I've tested the makefile on ubuntu 16.04 x64.
My makefile code is that: Version 1
CC=gcc
OBJ=main.o
TARGET:=main
.PHONY: clean
all : main
# ${OBJ}:%.o:%.c
%.i : %.c
$(info Preprocess: build main.i)
${CC} -E -o $@ $<
%.s : %.i
$(info Compile: build main.s)
${CC} -S -o $@ $<
%.o : %.s
$(info Assemble: build main.o)
${CC} -c -o $@ $<
main : main.o
$(info Link: build main.o)
${CC} -o $@ $^
clean:
rm -f *.o *.out *.s *.i *.asm *.map ${OBJ} main
run make, the terminal print message:
gcc -c -o main.o main.c
Link: build main.o
gcc -o main main.o
So only the last rule(main: main.o) run . fist step is autoderived code (gcc -c -o main.o main.c). why other rules didn't run?
And then I modify 3rd rules, add static mode: Version 2
...
%.i : %.c
$(info Preprocess: build main.i)
${CC} -E -o $@ $<
%.s : %.i
$(info Compile: build main.s)
${CC} -S -o $@ $<
main.o : %.o : %.s
$(info Assemble: build main.o)
${CC} -c -o $@ $<
%: %.o
$(info Link: build main.o)
${CC} -o $@ $^
Then all rules take effect, display message :
Preprocess: build main.i
gcc -E -o main.i main.c
Compile: build main.s
gcc -S -o main.s main.i
Assemble: build main.o
gcc -c -o main.o main.s
Link: build main.o
gcc -o main main.o
rm main.i
(why run "rm main.i"?)
I modify makefile again: Version 3
%.o:%.c
$(info build main.o)
${CC} -c -o $@ $<
main : main.o
$(info Link: build main.o)
${CC} -o $@ $^
It can be run correctly. Print message:
build main.o
gcc -c -o main.o main.c
Link: build main.o
gcc -o main main.o
So, why version 1 can't work correctly?
Upvotes: 1
Views: 1417
Reputation: 3454
It doesn't work because make
knows how to build an object file (.o
) from a .c
source, is a built-in implicit rule
You can disable implicit rules, if you run your version 1 with make -r
it should run as expected.
The .i
file is removed because is an intermediate file, by default make
remove all intermediate files, you can avoid that by using .PRECIOUS: some-file-name
%
rules in makefiles are referred as stem, pattern rules (not wildcards which are another thing)
You can run make
with the argument --debug
or --debug=all
for a verbose log or a more verbose log
edit
You have two more options to disable built-in rules and get version 1 working:
%.o: %.c
.SUFFIXES:
If you modify the suffix list, the only predefined suffix rules in effect will be those named by one or two of the suffixes that are on the list you specify
edit
An additional option to disable built-in rules that I used in the past:
MAKEFLAGS += --no-builtin-rules
Upvotes: 6
Reputation: 353
Static mode with explicit object should be needed for avoiding implicit rules take effect. So i rewrite makefile with static mode. It can work correctly and don't run "rm main.i".
CC:=gcc
SRCS:= $(wildcard *.c)
OBJ:= $(patsubst %.c, %.o, ${SRCS})
PREFILE:= $(patsubst %.o, %.i, ${OBJ})
ASMFILE:= $(patsubst %.o, %.s, ${OBJ})
TARGET:=main
all: ${TARGET}
.PHONY: clean distclean
$(PREFILE):%.i:%.c
$(info Preprocess: build main.i)
$(CC) -E -o $@ $<
$(ASMFILE):%.s:%.i
$(info Compile: build main.s)
$(CC) -S -o $@ $<
$(OBJ):%.o:%.s
$(info Assemble: build main.o)
$(CC) -c -o $@ $<
@objdump -DrwC -Mintel $@ > $(patsubst %.o,%.o.asm,$@)
$(TARGET):$(OBJ)
$(info Link: build main)
$(CC) -o $@ $^ -Wl,-Map=gcc.map
@objdump -D $@ > $(patsubst %,%.asm,$@)
clean:
rm -f *.o *.out *.s *.i *.asm *.map ${OBJ} ${TARGET}
distclean : clean
rm -f *.d
Upvotes: 1