多目录时Makefile 的编写方法

多级目录结构的Makefile

本文主要以例程的方式展示了二级目录结构下的Makefile的写法(详细注释);对于更加纷杂的多级目录,大家可在此基础上进行修改
在这里插入图片描述

#定义变量
#ARCH默认为x86,使用gcc编译器,否则使用arm编译器
ARCH ?= x86
TARGET = hello_main

#存放中间文件的路径 :./build_x86
BUILD_DIR = build_$(ARCH)
#存放源文件的文件夹 :./sources
SRC_DIR = sources
#存放头文件的文件夹: ./includes 
INC_DIR = includes 

#源文件.c
#在sources目录下有hello_func.c、hello_main.c、test.c文件
#执行如下函数 $(wildcard sources/*.c)函数的输出为:
#sources/hello_func.c sources/hello_main.c sources/test.c
SRCS = $(wildcard $(SRC_DIR)/*.c)

#notdir函数用于去除文件路径中的目录部分 例如输入参数”./sources/hello_func.c”,函数执行后 
#”hell_func.c”,也就是说它会把输入中的”./sources/”路径部分去掉,保留文件名
#OBJS变量用于存储所有要生成的的.o文件,它的值为patsubst函数 的输出,本例子中该函数是把所有c文件名
#替换为同名的.o文件,并添加build目录,即函数的输 出为”build/hello_func.o build /hello_main.o build /test.o”。
#目标文件(*.o)
OBJS = $(patsubst %.c, $(BUILD_DIR)/%.o, $(notdir $(SRCS)))
#DEPS变量存储所有依赖的头文件,它的值为wildcard函数的输出,本例子中该函数的输出为”includes/hello_func.h “。
#头文件
DEPS = $(wildcard $(INC_DIR)/*.h)

#指定头文件的路径
#用于存储包含的头文件路径,它的值为patsubst函数的输出,
#本例子中该函数是把includes目录添加到”-I”后面,函数的输出为”-Iincludes”。
CFLAGS = $(patsubst %, -I%, $(INC_DIR))

#根据输入的ARCH变量来选择编译器
#ARCH=x86,使用gcc
#ARCH=arm,使用arm-gcc
ifeq ($(ARCH),x86)
CC = gcc
else
CC = arm-linux-gnueabihf-gcc
endif

#目标文件
#build_x86/hello_main: build/hello_func.o build /hello_main.o build /test.o
$(BUILD_DIR)/$(TARGET): $(OBJS)
# gcc -o build_x86/hello_main  build/hello_func.o build/hello_main.o build/test.o -Iincludes
$(CC) -o $@ $^ $(CFLAGS)
#-Idir 
#在你是用 #include "file" 的时候, gcc/g++ 会先在当前目录查找你所制定的头文件,
#如果没有找到, 他回到默认的头文件目录找, 如果使用 -I 制定了目录,他会先在你所制定的目录查找, 
#然后再按常规的顺序去找。
#对于 #include<file>, gcc/g++ 会到 -I 制定的目录查找, 查找不到, 然后将到系统的默认的头文件目录查找 。

#*.o文件的生成规则
#例:build/hello_func.o : sources/hello_func.c includes/hello_func.h
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c $(DEPS)
#创建一个编译目录,用于存放过程文件
#命令前带"@",表示不在终端上输出
@mkdir -p $(BUILD_DIR)
#gcc -c -o build/hello_main.o sources/hello_main.c -Iincludes
$(CC) -c -o $@ $< $(CFLAGS) 

#伪目标
.PHONY: clean cleanall
#按架构删除
clean:
rm -rf $(BUILD_DIR)

#全部删除
cleanall:
rm -rf build_x86 build_arm

一、多目标

.PHONY:clean all
 
CC= gcc
CFLAGS= -Wall -g
 
LOCAL_PATH=$(shell pwd)
 
BIN=test01 test02
all:$(BIN)
 
#%.o:%.c
.c.o:
	$(CC) $(CFLAGS) -c $< -o $@
 
test01:test01.o sub.o
	$(CC) $(CFLAGS) -o $@ $^
 
test02:test02.o add.o
	$(CC) $(CFLAGS) -o $@ $^
 
clean:
	echo  "$(LOCAL_PATH)"
	rm -f $(BIN) *.o

二、多级目录

.PHONY:clean
 
CC=gcc
CFLAGS= -Wall -g
 
BIN=main_exe
ROOTSRC=$(wildcard *.c)
ROOTOBJ=$(patsubst %.c, %.o, $(ROOTSRC))
SUBDIR=$(shell ls -d */)
SUBSRC=$(shell find $(SUBDIR) -name '*.c')
SUBOBJ=$(SUBSRC:%.c=%.o)
 
$(BIN):$(ROOTOBJ) $(SUBOBJ)
	$(CC) $(CFLAGS) $^ -o $@
 
%.o:%.c
	$(CC) $(CFLAGS) -c $< -o $@
 
clean:
	rm -rf $(BIN) $(ROOTOBJ) $(SUBOBJ)

实际当中程序文件比较大,这时候对文件进行分类,分为头文件、源文件、目标文件、可执行文件。文件分类如下(推荐使用)
在这里插入图片描述
完整的Makefile如下所示:

DIR_INC = ./include
DIR_SRC = ./src
DIR_OBJ = ./obj
DIR_BIN = ./bin

SRC = $(wildcard ${DIR_SRC}/*.c)
OBJ = $(patsubst %.c,${DIR_OBJ}/%.o,$(notdir ${SRC}))

TARGET = main

BIN_TARGET = ${DIR_BIN}/${TARGET}

CC = gcc
CFLAGS = -g -Wall -I${DIR_INC}

${BIN_TARGET}:${OBJ}
	$(CC) $(OBJ)  -o $@

${DIR_OBJ}/%.o:${DIR_SRC}/%.c
	$(CC) $(CFLAGS) -c  $< -o $@
.PHONY:clean
clean:
	find ${DIR_OBJ} -name *.o -exec rm -rf {} \;
  • 8
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
对于多目录的情况,我们可以使用一个主makefile来管理整个项目,然后在每个子目录下再编写各自的makefile。以下是一个示例: 首先,我们创建一个名为`Makefile`的主makefile,并在其中定义一些变量和规则: ```makefile # 定义子目录 SUBDIRS := dir1 dir2 dir3 # 定义编译器和编译选项 CC := gcc CFLAGS := -Wall -Werror # 定义目标文件存放的目录 OBJDIR := obj # 定义目标文件和可执行文件 TARGET := myprogram OBJS := $(addprefix $(OBJDIR)/, file1.o file2.o file3.o) .PHONY: all clean $(SUBDIRS) all: $(TARGET) $(TARGET): $(OBJS) $(CC) $(CFLAGS) $^ -o $@ # 在每个子目录下执行make命令 $(SUBDIRS): $(MAKE) -C $@ # 生成目标文件的规则 $(OBJDIR)/%.o: %.c | $(OBJDIR) $(CC) $(CFLAGS) -c $< -o $@ # 创建目标文件存放的目录 $(OBJDIR): mkdir -p $@ clean: rm -rf $(TARGET) $(OBJDIR) ``` 然后,在每个子目录下创建各自的makefile,例如`dir1/Makefile`: ```makefile # 定义当前子目录下的源文件 SRCS := file1.c # 生成当前子目录下的目标文件 OBJS := $(addprefix $(OBJDIR)/, $(SRCS:.c=.o)) all: $(OBJS) $(OBJS): $(SRCS) | $(OBJDIR) $(CC) $(CFLAGS) -c $< -o $@ $(OBJDIR): mkdir -p $@ clean: rm -rf $(OBJS) ``` 其他子目录的`Makefile`可以类似地创建。 这样,通过在主makefile中定义需要编译的子目录,并在其中执行各自的make命令,可以实现多目录的编译。同,每个子目录下的makefile会将编译生成的目标文件放入统一的目标文件存放目录中。 使用`make`命令执行主makefile即可开始编译整个项目。使用`make clean`命令可以清除编译生成的目标文件和可执行文件。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C君莫笑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值