1.开发背景
linux 下编译程序需要用到对应的 Makefile,用于编译应用程序。
2.开发需求
编写 Makefile 编译应用程序
1)支持多个源文件
2)支持多个头文件
3)支持只编译修改的文件,包括源文件和头文件
4)支持交叉编译
3.开发环境
ubuntu 20.04
4.实现步骤
4.1 准备源码文件
准备了一个串口通讯的 app 程序,其中包括 2 个头文件和 3 个源文件,当然还是少不了 Makefile文件,如下图所示:
4.2 编写 Makefile
# 定义目标文件名
TARGET := app_uart
# 关键路径 ##############################################
INC_DIR = ./inc
INC_DIR_COM = ../../00_com/inc
SRC_DIR = . ./src ${SRC_DIR_COM}
SRC_DIR_COM = ../../00_com/src
OBJ_DIR = ./obj
TAR_DIR = ./install
# 定义编译器和编译选项 ###################################
CC := aarch64-linux-gnu-gcc
CFLAGS :=
# CFLAGS += -fPIC # 生成动态库
# CFLAGS += -O2 # 优化等级
CFLAGS += -Wall # 显示警告
CFLAGS += -Werror # 显示错误
CFLAGS += -I${INC_DIR} # 添加.h路径
CFLAGS += -I${INC_DIR_COM} # 添加.h路径
CFLAGS += -lpthread # 多线程编译
# CFLAGS += -DNDEBUG # 关闭断言
# 定义源文件和目标文件 srcs:*.c 遍历添加
SRCS := $(foreach dir, $(SRC_DIR), $(wildcard $(dir)/*.c))
SRCS_FILE = $(notdir $(SRCS)) # 去除路径,剩下文件名
OBJS := $(SRCS:.c=.o)
# OBJS := $(patsubst %.c, $(OBJ_DIR)/%.o, $(SRCS_FILE))
MMDS := $(OBJS:.o=.d)
# IP 地址 和 路径
IP_ADDRESS := 172.16.0.188
IP_PATH := /home/linaro/auto_start
# 默认目标 $< 表示第一个依赖 $@ 目标文件
app: $(TARGET)
# -MMD 生成 *.d 文件 记录 .o 文件对 .c 和 .h 文件的依赖
-include ${MMDS} # -include 带 - 前缀第一次编译不会出错
%.o: %.c
# $(OBJ_DIR)/%.o: %.c
$(CC) $(CFLAGS) $< -c -MMD -o $@
# 生成可执行文件
$(TARGET): $(OBJS)
$(CC) $(CFLAGS) $^ -o $@
# mv ${OBJS} ${OBJ_DIR}
# mv ${MMDS} ${OBJ_DIR}
# if 判断需要顶格编写 如果不存在路径则创建
ifeq ($(wildcard ${TAR_DIR}), )
mkdir ${TAR_DIR}
endif
mv ${TARGET} ${TAR_DIR}/${TARGET}
# 清理生成的文件
clean:
rm -f $(OBJS) ${MMDS} $(TARGET) ${OBJ_DIR}/*
ifneq ($(wildcard ${TAR_DIR}/*), )
rm ${TAR_DIR}/*
endif
prebuild:
# if 判断需要顶格编写 如果不存在路径则创建
ifeq ($(wildcard ${OBJ_DIR}), )
mkdir ${OBJ_DIR}
endif
# -cp ${INC_DIR_COM}/*.h ${INC_DIR}
# -cp ${SRC_DIR_COM}/*.c ${SRC_DIR}
all:
make prebuild
make
rebuild:
make clean
make
# 打包文件
pack:
make clean
# 发送文件 需要先手动连接一次
scp:
sshpass -p root scp ${TAR_DIR}/${TARGET} linaro@${IP_ADDRESS}:${IP_PATH}
test:
$(warning $(SRC_DIR))
$(warning $(SRCS))
$(warning $(SRCS_FILE))
$(warning $(OBJS))
$(warning $(OBJ_DIR)/%.o)
4.3 编译程序
其中,使用了交叉编译工具:aarch64-linux-gnu-gcc,编译生成的文件移动到 install,方便查看,需要注意的是这里指定了多个源文件和头文件路径。
4.4 修改文件重新编译
其中只修改了 main.c 文件,所以重新编译 main.c 文件
4.5 主要修改点
4.5.1 头文件修改重新编译
如果只是一般操作,Makefile 在.o文件存在的情况下是不会重新编译的,这就意味着一般的修改.h 文件不会重新编译.c文件的。
解决方法:使用 -MMD 编译生成中间链接关系文件,再调用-include,带前缀‘-’,否者 第一次编译会报没有.d文件。
-include $(OBJS:.o=.d)
%.o: %.c
$(CC) $(CFLAGS) $< -c -MMD -o $@
5. 参考链接
Makefile-只修改了.h头文件,编译为什么不起作用? - 码农教程
makefile一般格式,自动更新头文件_makefile头文件更新-CSDN博客
Makefile编译目录下多个文件以及函数wildcard用法_src=$(wildcard *.cpp)-CSDN博客
多目录时Makefile 的编写方法_makefile中一个变量对应了多个绝对路径-CSDN博客