As showed in first screenshot, my ideal AVR project structure is that:
*.o
, *.elf
and *.hex
files are in build
folder.PomoScheler.c
and pinDefines.h
as main files are in root folder, while other *.c
and *.h
are in src
folder.But *.o
are always generated at the same folder as *.c
like showed in second screenshot, no matter how.
(I attached my endeavors and whole Makefile below the screenshots)
Firstly, I tried build/
before $@
, in vain. The terminal still the same.
# My first Makefile endeavor
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o build/$@
# Terminal command generated by Makefile (Look at the end: *.o path still same as *.c)
avr-gcc -Os -g -std=gnu99 -Wall -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -ffunction-sections -fdata-sections -DF_CPU=1000000UL -DBAUD=9600UL -I. -I~/Developer/bin/avr8-gnu-toolchain-darwin_x86_64/avr/include -mmcu=atmega328p -c -o src/RotaryEncoder.o src/RotaryEncoder.c
Secondly, I tried to add mv $@ build
to explicitly move it to build
folder. But nothing happened. Even echo
are not displayed in Terminal.
# My second Makefile endeavor
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@
mv $@ build
echo ---------Hello---------
Thirdly, I delete $(HEADERS)
and replace $<
with $^
just to have a try. The mv
is executed. But it cannot find *.o
file this time even though I have VPATH = src:build
in Makefile.
# My third Makefile endeavor
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $^ -o $@
mv $@ build
# Terminal error
Assembler messages:
Fatal error: can't create build/src/RotaryEncoder.o: No such file or directory
And my whole Makefile is here. Please help me out.
# My whole Makefile
MCU = atmega328p
F_CPU = 1000000UL
BAUD = 9600UL
LIBDIR = ~/Developer/bin/avr8-gnu-toolchain-darwin_x86_64/avr/include
PROGRAMMER_TYPE = usbtiny
PROGRAMMER_ARGS =
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
##########------------------------------------------------------##########
VPATH = ./src:./build
TARGET = $(lastword $(subst /, ,$(CURDIR)))
SOURCES=$(wildcard *.c src/*.c $(LIBDIR)/*.c)
OBJECTS=$(SOURCES:.c=.o)
HEADERS=$(SOURCES:.c=.h)
CPPFLAGS = -DF_CPU=$(F_CPU) -DBAUD=$(BAUD) -I. -I$(LIBDIR)
CFLAGS = -Os -g -std=gnu99 -Wall
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -ffunction-sections -fdata-sections
LDFLAGS = -Wl,-Map,build/$(TARGET).map
LDFLAGS += -Wl,--gc-sections
TARGET_ARCH = -mmcu=$(MCU)
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o build/$@
$(TARGET).elf: $(OBJECTS)
$(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LDLIBS) -o build/$@
%.hex: %.elf
$(OBJCOPY) -j .text -j .data -O ihex build/$< build/$@
all: $(TARGET).hex
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
This is clearly not right:
OBJECTS = $(SOURCES:.c=.o)
because the object files you want to create are not foo.o
etc. which is what this will expand to; the object files are build/foo.o
etc. So this has to be:
OBJECTS = $(patsubst %.c,build/%.o)
All of your attempts to trick make by telling it your recipe will build one target (foo.o
) but actually building a totally different target (build/foo.o
) are doomed to fail, regardless of whether you have the compiler do it directly, you use mv
, or any other method.
If you just tell make what your recipe actually does, you will have a much simpler time of it:
build/%.o: %.c
mkdir -p $(@D)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $^ -o $@
Probably you have similar issues with the other rules that you want to put into other directories.
You can't do this by trying to hide it from make. Make has to know where the files actually are.
BTW, VPATH cannot help here. VPATH is for finding source files, it cannot be used for finding generated files. So you could use VPATH to find your .c
files but not your .o
files.