RobotRock
RobotRock

Reputation: 4459

Makefile runs over C file twice

I have two files: assign1.c and ports.h.

FYI: I am using avr-gcc.

I built the following makefile, which I also use for another project (and other TARGET) where it works fine.

TARGET = assign2
LIB=
INCLUDE=ports.h
CFLAGS =-mmcu=atmega32 -Wall
CC = avr-gcc
SRC= $(TARGET).c
OBJ= $(SRC:.c=.o)

OBJCOPY = avr-objcopy
FORMAT  = ihex

MSG_COMPILING = Compiling:
MSG_LINKING = Linking:
MSG_FLASH = Creating load file for flash:

all:elf hex

elf: $(TARGET).elf
hex: $(TARGET).hex

%.hex: %.elf
    @echo $(MSG_FLASH) $@
    @echo 
    $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
    $(RM) *.elf $(TARGET)
    @echo 

%.elf: $(OBJ) $(LIB)
    @echo $(MSG_LINKING) $@
    @echo 
    $(CC)  $(CFLAGS)  $^ -o $@
    @echo 

%.o: $(SRC) $(INCLUDE)
    @echo $(MSG_COMPILING) $<
    @echo 
    $(CC)  $(CFLAGS) -c $<
    @echo 

.PHONY : clean

clean:
    $(RM) *.o *.hex *.elf $(TARGET)

The terminal prints the following output.

C:\Project>make
Compiling: assign2.c

avr-gcc  -mmcu=atmega32 -Wall -c assign2.c
In file included from assign2.c:8:
c:/winavr-20100110/lib/gcc/../../avr/include/util/delay.h:90:3: warning: #warnin
g "Compiler optimizations disabled; functions from <util/delay.h> won't work as
designed"

Linking: assign2.elf

avr-gcc  -mmcu=atmega32 -Wall  assign2.o -o assign2.elf

Compiling: assign2.c

avr-gcc  -mmcu=atmega32 -Wall -c assign2.c
In file included from assign.c:8:
c:/winavr-20100110/lib/gcc/../../avr/include/util/delay.h:90:3: warning: #warnin
g "Compiler optimizations disabled; functions from <util/delay.h> won't work as
designed"

avr-gcc   elf.o assign2.elf   -o elf
avr-gcc: elf.o: No such file or directory
make: *** [elf] Error 1
rm assign2.o

C:\Project>

For some reason it seems to compile the first file, a second time and doing so crashes.

Can anyone correct me on my errors?

Upvotes: 0

Views: 920

Answers (1)

MadScientist
MadScientist

Reputation: 101081

The problem is your pattern rules. You are writing pattern rules like this (after make expands the variables):

%.o: assign2.c ports.h

What this rule tells make is that ANY target it wants to build that matches the %.o pattern, can be built by compiling assign2.c. That's obviously not true: this rule build exactly one target: assign2.o.

So make reads your makefile and wants to build a file named elf. It sees that elf depends on $(TARGET).elf, so it builds that (that's the first compile and link, that works). Then make wants to build elf itself. You haven't declared it to be .PHONY, so make assumes it might be a real target.

Make looks through its built-in rules to find one that will let it build elf, and it finds a built-in rule: % : %.o which it can use to compile a program from a .o file with the same prefix. So now for target elf make wants to try to build a file elf.o. Oho! It sees there's a pattern rule that lets it build any .o file based on the assign2.c source file, so it runs that rule (that's the second compile) expecting it to build elf.o... which it doesn't, obviously.

Then make runs the built-in link recipe, using elf.o which doesn't exist, and fails.

The solution to your problem is two things:

First, you should always declare all your makefile targets that you don't actually want to build as .PHONY so make won't try to build them:

.PHONY: all elf hex

Second, you should never use pattern rules where the prerequisite is not also a pattern (this can be useful in certain very specific situations, but not in general). You should either change those pattern rules to explicit rules:

assign2.elf: $(OBJ) $(LIB)
        ...

$(OBJ): $(SRC) $(INCLUDE)
        ...

Or make them into full pattern rules by using the pattern in the prerequisites list as well:

%.elf : %.obj $(LIB)
        ...

%.o: %.c $(INCLUDE)
        ...

Upvotes: 3

Related Questions