从 makefile 在构建目录中创建中间文件
Create intermediate files in build directory from makefile
我必须使用 makefile 在 Ubuntu 终端中创建一个 XC8 项目。
目录结构是这样的
Project/lib/GPIO/gpio.c
Project/lib/GPIO/gpio.h
Project/main.c
Project/Makefile
Project/build/lib/GPIO
makefile 正在项目目录本身中生成中间文件。实际上 makefile 将转到每个位置并为每个 .c
文件生成中间文件。
像这样
Project/gpio.d
Project/gpio.p1
Project/gpio.pre
Project/<other files>
但我想在 Project/build/lib/GPIO
中生成它们。
即
Project/build/lib/GPIO/gpio.d
Project/build/lib/GPIO/gpio.p1
Project/build/lib/GPIO/gpio.pre
Project/build/<other files>
生成文件:
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} $@ $<
我要说的第一件事是,这个答案依赖于您使用 GNU make。你不能肯定地说你是,但因为你使用的是模式规则,我会这样假设。请注意,使用标准 POSIX make 无法实现您想做的事情(除非您想为每个要构建的目标写出明确的规则)。
你需要两件事:
- 告诉你的编译器你想做什么
- 告诉make你想做什么
对于 #1,默认情况下,编译器将生成输出,即输入文件名减去扩展名(例如 .c
)加上特定扩展名(例如 .as
)。由于您的输入文件是 lib/GPIO/gpio.c
,编译器生成 gpio.as
。大多数编译器支持 -o
选项,它允许您重命名输出:如果这不起作用,您必须检查编译器的文档。所以,你想写下你的规则:
%.as: %.c ${INC_DIR}
${CC} ${CPPFLAGS} ${CFLAGS} -S -o $@ $<
(等等)。现在,当您将 lib/GPIO/gpio.c
编译成 lib/GPIO/gpio.as
时,make 会将 $@
设置为 lib/GPIO/gpio.as
并调用您的编译器,以便它创建 lib/GPIO/gpio.as
而不是 gpio.as
。
但是您想将输出文件放在 build
子目录中。现在您已经说服您的编译器在 make 告诉它的地方写入文件,您必须告诉 make 把输出放在哪里。
所以首先,当您生成要创建的输出文件时,您必须使用正确的路径创建它们:
OBJS := $(SRCS:.c=.p1)
将 lib/GPIO/gpio.c
转换为 lib/GPIO/gpio.p1
,这不是您想要的。你需要这个:
OBJS := $(SRCS:%.c=build/%.p1)
现在,让 make 知道您想改为构建 build/lib/GPIO/gpio.p1
。但是现在你会得到一个错误,因为 make 不知道如何创建那个文件。您已经告诉它如何从 %.c
构建 %.p1
,但是 %
必须是目标和先决条件之间的精确文本匹配,而这里的目标 %
匹配build/lib/GPIO/gpio
但没有 build/lib/GPIO/gpio.c
所以规则不匹配。您需要像这样重写规则:
build/%.p1: %.c ${INC_DIR}
${CC} ${CPPFLAGS} ${CFLAGS} --pass1 -o $@ $<
现在应该可以了。您可能还想添加 mkdir
以确保目录存在:
build/%.p1: %.c ${INC_DIR}
@mkdir -p ${@D}
${CC} ${CPPFLAGS} ${CFLAGS} --pass1 -o $@ $<
我必须使用 makefile 在 Ubuntu 终端中创建一个 XC8 项目。 目录结构是这样的
Project/lib/GPIO/gpio.c
Project/lib/GPIO/gpio.h
Project/main.c
Project/Makefile
Project/build/lib/GPIO
makefile 正在项目目录本身中生成中间文件。实际上 makefile 将转到每个位置并为每个 .c
文件生成中间文件。
像这样
Project/gpio.d
Project/gpio.p1
Project/gpio.pre
Project/<other files>
但我想在 Project/build/lib/GPIO
中生成它们。
即
Project/build/lib/GPIO/gpio.d
Project/build/lib/GPIO/gpio.p1
Project/build/lib/GPIO/gpio.pre
Project/build/<other files>
生成文件:
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} $@ $<
我要说的第一件事是,这个答案依赖于您使用 GNU make。你不能肯定地说你是,但因为你使用的是模式规则,我会这样假设。请注意,使用标准 POSIX make 无法实现您想做的事情(除非您想为每个要构建的目标写出明确的规则)。
你需要两件事:
- 告诉你的编译器你想做什么
- 告诉make你想做什么
对于 #1,默认情况下,编译器将生成输出,即输入文件名减去扩展名(例如 .c
)加上特定扩展名(例如 .as
)。由于您的输入文件是 lib/GPIO/gpio.c
,编译器生成 gpio.as
。大多数编译器支持 -o
选项,它允许您重命名输出:如果这不起作用,您必须检查编译器的文档。所以,你想写下你的规则:
%.as: %.c ${INC_DIR}
${CC} ${CPPFLAGS} ${CFLAGS} -S -o $@ $<
(等等)。现在,当您将 lib/GPIO/gpio.c
编译成 lib/GPIO/gpio.as
时,make 会将 $@
设置为 lib/GPIO/gpio.as
并调用您的编译器,以便它创建 lib/GPIO/gpio.as
而不是 gpio.as
。
但是您想将输出文件放在 build
子目录中。现在您已经说服您的编译器在 make 告诉它的地方写入文件,您必须告诉 make 把输出放在哪里。
所以首先,当您生成要创建的输出文件时,您必须使用正确的路径创建它们:
OBJS := $(SRCS:.c=.p1)
将 lib/GPIO/gpio.c
转换为 lib/GPIO/gpio.p1
,这不是您想要的。你需要这个:
OBJS := $(SRCS:%.c=build/%.p1)
现在,让 make 知道您想改为构建 build/lib/GPIO/gpio.p1
。但是现在你会得到一个错误,因为 make 不知道如何创建那个文件。您已经告诉它如何从 %.c
构建 %.p1
,但是 %
必须是目标和先决条件之间的精确文本匹配,而这里的目标 %
匹配build/lib/GPIO/gpio
但没有 build/lib/GPIO/gpio.c
所以规则不匹配。您需要像这样重写规则:
build/%.p1: %.c ${INC_DIR}
${CC} ${CPPFLAGS} ${CFLAGS} --pass1 -o $@ $<
现在应该可以了。您可能还想添加 mkdir
以确保目录存在:
build/%.p1: %.c ${INC_DIR}
@mkdir -p ${@D}
${CC} ${CPPFLAGS} ${CFLAGS} --pass1 -o $@ $<