I have to make a XC8 project in Ubuntu terminal with makefile. The directory structure is like this
Project/lib/GPIO/gpio.c
Project/lib/GPIO/gpio.h
Project/main.c
Project/Makefile
Project/build/lib/GPIO
The makefile is generating intermediate files in the Project directory itself. Actually makefile will goto each location and generates intermediate files for each .c
file.
Like this
Project/gpio.d
Project/gpio.p1
Project/gpio.pre
Project/<other files>
But I wanted to generate them in Project/build/lib/GPIO
instead.
i.e
Project/build/lib/GPIO/gpio.d
Project/build/lib/GPIO/gpio.p1
Project/build/lib/GPIO/gpio.pre
Project/build/<other files>
Makefile:
CHIP := 18F4580
CC := xc8
INCLUDE_PATH := /opt/microchip/xc8/v2.10/include/
PROG := /usr/share/tinybldlin/tinybldlin.py
PORT := /dev/ttyUSB0
AR := libr
SRC_DIR := $(wildcard *.c)
INC_DIR := $(wildcard *.h)
LIB_DIR := \
. \
lib \
lib/GPIO
BUILD_DIR := \
build/ \
build/lib/GPIO
TARGET := pic${CHIP}
FLASH_REGION := 0-3000
ifeq (${SRCS},)
SRCS := $(foreach libdir, $(LIB_DIR), $(wildcard $(libdir)/*.c))
endif
ifeq (${INCS},)
INCS := $(foreach libdir, $(LIB_DIR), $(wildcard $(libdir)/*.h))
endif
ifeq (${OBJS},)
OBJS := $(SRCS:.c=.obj)
endif
ifeq (${P1},)
OBJS := $(SRCS:.c=.p1)
endif
MIN_CFLAGS := --chip=${CHIP} -I${INCLUDE_PATH} --ROM=${FLASH_REGION}
# The following MSG_CFLAGS controls the compiler messages
MSG_CFLAGS := -Q
# The following OPT_CFLAGS reduces the code size
OPT_CFLAGS := --opt=all
# The following OUT_CFLAGS controls the generated outputs
OUT_CFLAGS := --asmlist --summary=psect,mem -M${TARGET}.map
EXTRA_CFLAGS += ${MSG_CFLAGS} ${OPT_CFLAGS} ${OUT_CFLAGS}
CFLAGS := ${MIN_CFLAGS} ${EXTRA_CFLAGS} -DCOMPILER=${COMPILER}
ARFLAGS := r
${TARGET}.hex: ${OBJS}
${CC} ${CFLAGS} -intel $^ -o$@
${MAKE} xclean
${TARGET}.bin: ${OBJS}
${CC} ${CFLAGS} -bin $^ -o$@
${MAKE} xclean
%.p1: %.c ${INC_DIR}
${CC} ${CPPFLAGS} ${CFLAGS} --pass1 $<
%.obj: %.c ${INC_DIR}
${CC} ${CPPFLAGS} ${CFLAGS} -C $<
%.as: %.c ${INC_DIR}
${CC} ${CPPFLAGS} ${CFLAGS} -S $<
%.lib: %.obj
${AR} ${ARFLAGS} $@ $<
The first thing I'll say is that this answer relies on your using GNU make. You don't say for sure that you are but since you're using pattern rules I will assume so. Note that what you want to do is not possible with standard POSIX make (unless you want to write out explicit rules for every target to be built).
You need two things:
For #1, by default the compiler will generate the output which is the input file name, minus the extension (e.g. .c
) plus a specific extension (e.g. .as
). Since your input file is lib/GPIO/gpio.c
the compiler generates gpio.as
. Most compilers support a -o
option which allows you to rename the output: you'll have to check your compiler's documentation if this doesn't work. So, you'd want to write your rule:
%.as: %.c ${INC_DIR}
${CC} ${CPPFLAGS} ${CFLAGS} -S -o $@ $<
(etc.). Now when you compile lib/GPIO/gpio.c
into lib/GPIO/gpio.as
, make will set $@
to lib/GPIO/gpio.as
and invoke your compiler such that it creates lib/GPIO/gpio.as
not gpio.as
.
But you wanted to put the output files in a build
subdirectory. Now that you've convinced your compiler to write files where make tells it to, you have to tell make where to put the output.
So first, when you generate the output files to be created you have to create them with the correct path:
OBJS := $(SRCS:.c=.p1)
That converts lib/GPIO/gpio.c
into lib/GPIO/gpio.p1
which isn't what you want. You need this:
OBJS := $(SRCS:%.c=build/%.p1)
Now, make knows you want to build build/lib/GPIO/gpio.p1
instead. However now you'll get an error because make doesn't know how to create that file. You've told it how to build a %.p1
from %.c
, but the %
must be an exact text match between the target and prerequisite, and here the target %
matches build/lib/GPIO/gpio
but there's no build/lib/GPIO/gpio.c
so the rule doesn't match. You need to rewrite the rule like this:
build/%.p1: %.c ${INC_DIR}
${CC} ${CPPFLAGS} ${CFLAGS} --pass1 -o $@ $<
Now it should work. You might also want to add in a mkdir
to ensure the directory exists:
build/%.p1: %.c ${INC_DIR}
@mkdir -p ${@D}
${CC} ${CPPFLAGS} ${CFLAGS} --pass1 -o $@ $<