Search code examples
makefilec-preprocessoravr

How can I have a step in a makefile to generate preprocess files and compile from those files?


I took a makefile from a previous project that compiles programs for an avr microcontroller. I ran into some problems with what IO ports/data directional addresses I was setting which was causing the microcontroller to fault and reset. Because of this I wanted to add a step in my makefile to have it generate the pre-proccessed files and then compile from these preprocessed files. I'm not too familiar with how rules/dependencies work in makefiles so I've made, what I believe is, a simple mistake in my understanding of how makefiles work. My rules to make the preprocessed files/object files and eventually the .elf file must be wrong. Up until I added the steps which attempted to create the preprocessed files creating the .elf file work fine. What is my simple mistake/understanding in how rules/dependencies work in make?

How I view this working is when I ask to make all it sees that it has a dependency of led.elf. To create this it has the dependency of the preprocessed files based on the line of $(OUTPUT).elf: $(PROCESS_FILES) so it starts with this line. When I try to make all however I get the error make: *** No rule to make target 'main.c', needed by 'main.e'. Stop. and I don't understand why. Can anyone help my understanding in make files?

SRC_FILES=\
main.c led.c comm.c
#Object files
PROCESS_FILES=$(SRC_FILES:.c=.e)
OBJ_FILES=$(PROCESS_FILES:.e=.o)
#Directories where to look for include files
INC_DIRS=\
-I. \
#Output file name
OUTPUT=led
#Programmer and port
PROG=dragon_isp

PORT=usb
#Debugging host and port
DHOST=localhost
DPORT=6423  
#Compiler related params
MCU=atmega2560
CC=avr-gcc
OBJCOPY=avr-objcopy
CFLAGS= -mcall-prologues -std=gnu99 -funsigned-char -funsigned bitfields \
-fpack-struct -fshort-enums -mmcu=$(MCU) -Wall -Wstrict-prototypes \
$(INC_DIRS)
#Optimization level
CFLAGS+=-Os
#Debug info
CFLAGS+=-gdwarf-2

#Generate hex file ready to upload
all: $(OUTPUT).elf
$(OBJCOPY) -R .eeprom -O ihex $(OUTPUT).elf $(OUTPUT).hex                           
#Link output files
$(OUTPUT).elf: $(PROCESS_FILES)
  $(CC) $(CFLAGS) $(OBJ_FILES) -o $(OUTPUT).elf -Wl,-Map,$(OUTPUT).map
#Create object files
$(PROCESS_FILES): %.e : %.c
  $(CC) -E $(CFLAGS) $< -o $@
$(OBJ_FILES): %.o : %.e
  $(CC) -x $(CFLAGS) $< -o $@
#Create assembler file of a C source
%.s: %.c
  $(CC) -S $(CFLAGS) $< -o $@
#Cleans all generated files
clean:
  rm -f $(OBJ_FILES)
  rm -f $(OUTPUT).elf
  rm -f $(OUTPUT).hex
  rm -f $(OUTPUT).map

Edit: I'm away from my computer now so I can't check this but thinking about my issue I'm starting to think I don't have a file named main.c in that directory. Even if I did I still think the makefile would not work correctly because I don't fully understand rules in makefiles.


Solution

  • My error was coming from the fact that I did not have a main.c file in my directory. Make sure you backup files when you're messing with the OBJ_FILES or similar variable and have a line that will delete whatever is in that variable upon a make clean.

    As for the rules, I had to make one small fix to achieve what I wanted. I changed

    $(OUTPUT).elf: $(PROCESS_FILES)
      $(CC) $(CFLAGS) $(OBJ_FILES) -o $(OUTPUT).elf -Wl,-Map,$(OUTPUT).map
    

    to

    $(OUTPUT).elf: $(OBJ_FILES)
      $(CC) $(CFLAGS) $(OBJ_FILES) -o $(OUTPUT).elf -Wl,-Map,$(OUTPUT).map
    

    This then sees it needs the object files which in turn needs the preprocessed files.

    Edit: I also changed OBJ_FILES=$(PROCESS_FILES:.e=.o) to OBJ_FILES=$(SRC_FILES:.c=.o). I also added $(PROCESS_FILES) to $(OUTPUT).elf: $(OBJ_FILES) so the rule would generate both the preprocessed files and object files independently. I had to change $(OBJ_FILES): %.o : %.e to $(OBJ_FILES): %.o : %.c to make this work.