多文件目录下makefile文件递归执行编译所有c文件

先上完整的文件,csdn下载,免积分

点击打开链接

先说下目录结构

linux@ubuntu:~/work/makefiledemo/makedemo$ tree
.
├── debug
│   ├── bin
│   ├── Makefile
│   └── obj
├── dir_a
│   ├── func_a.c
│   └── Makefile
├── dir_b
│   ├── dir_b_1
│   │   ├── func_b_1.c
│   │   ├── head_b_1.h
│   │   └── Makefile
│   ├── func_b.c
│   ├── head_b.h
│   └── Makefile
├── dir_c
│   ├── func_c.c
│   ├── head_c.h
│   └── Makefile
├── includes
│   ├── head_a.h
│   ├── head.h
│   └── mylib.h
├── main.c
└── Makefile

8 directories, 17 files
其中debug目录是存放中间文件和可执行文件的文件夹,这个文件夹不是必须的,可有可无,如果没有makefile会自动生成,其中includes文件夹是存放头文件的文件夹,这个文件夹的名字可以在最外层的makefile中定义,需要注意的是不能在这个文件夹中放要编译的c文件,因为这个文件夹中的makefile不会被执行。

下面说一下用来测试的文件

*.c文件

#include <stdio.h>
#include "head_b.h"

void func_b(void)
{
	printf("func_b\n");
}
*.h

#ifndef _HEAD_B_H_
#define _HEAD_B_H_

void func_b(void);

#endif
主要的文件只有这些,其中一些添加了动态库和静态库的调用,读者需要了解可以自己去看

main.c

#include <stdio.h>
#include "head_a.h"

int main(int argc, const char *argv[])
{
	printf("main\n");
	func_a();
	func_c();
	return 0;
}
下面说一下makefile

首先说说本次嵌套执行makefile文件的目的:只需make根目录下的makefile文件,即可编译所有c文件,包括子目录下的。
意义:自动化编译行为,以后编译自己的c文件时可把这些makefile文件直接复制到相应目录即可方便编译出所有文件。这些makefile文件是通用的,只需根据自己的工程情况改动少许内容即可。下面会说。
总体思路是:把目标文件放在debug文件夹下的obj目录下,把最终的二进制文件放在debug文件夹下的bin目录下;如何递归编译所有除了debug目录下的makefile文件呢:获得当前目录下的所有子目录,执行子目录下的makefile文件;获取当前目录下的所有c文件,编译c文件并放到指定的目标文件夹下。最后再执行debug目录下的makefile文件生成bin文件。
注意:除了debug文件夹比较特殊外,其他的子目录下都需要有Makefile文件,而且这些Makefile是相同的,除了根目录下的makefile文件有些不同外。即除了bin和obj目录以外的其他目录都需要Makefile文件,即使目录下没有c文件或者其他目录。
根目录下新建Makefile文件,根目录下也可能会有c文件,故也需处理根目录下的c文件,内容如下:

#输出文件夹
OUTFILE=debug
#可执行程序文件夹
OUTBIN=bin
#连接目标文件夹
OBJFILE=obj
#判断输出文件夹是否存在,如果不存在自动填充
ifneq ($(OUTFILE), $(wildcard $(OUTFILE)))
$(shell mkdir -p $(OUTFILE) $(OUTFILE)/$(OUTBIN) $(OUTFILE)/$(OBJFILE))
$(shell echo 'OBJS=*.o\nODIR=obj\n$$(ROOT_DIR)/$$(BIN_DIR)/$$(BIN):$$(ODIR)/$$(OBJS)\n\t$$(CC) -o $$@ $$^ $$(CFLAGS) $$(LDFLAGS)'>$(OUTFILE)/Makefile)
endif
#输出文件夹下Makefile文件是否存在
ifneq ($(OUTFILE)/Makefile, $(wildcard $(OUTFILE)/Makefile))
$(shell echo 'OBJS=*.o\nODIR=obj\n$$(ROOT_DIR)/$$(BIN_DIR)/$$(BIN):$$(ODIR)/$$(OBJS)\n\t$$(CC) -o $$@ $$^ $$(CFLAGS) $$(LDFLAGS)'>$(OUTFILE)/Makefile)
endif
#判断可执行程序文件夹是否存在
ifneq ($(OUTFILE)/$(OUTBIN), $(wildcard $(OUTFILE)/$(OUTBIN)))
$(shell mkdir -p $(OUTFILE)/$(OUTBIN))
endif
#判断连接目标文件夹是否存在
ifneq ($(OUTFILE)/$(OBJFILE), $(wildcard $(OUTFILE)/$(OBJFILE)))
$(shell mkdir -p $(OUTFILE)/$(OBJFILE))
endif



#设置编译器
CC=gcc
CPP=g++
#debug文件夹里的makefile文件需要最后执行,所以这里需要执行的子目录要排除debug文件夹,这里使用awk排除了debug文件夹,读取剩下的文件夹
SUBDIRS=$(shell ls -l | grep ^d | awk '{if($$9 != "debug") print $$9}')
#SUBDIRS删除includes文件夹,因为这个文件中是头文件,不需要make
SUBDIRS:=$(patsubst includes,,$(SUBDIRS))
#无需下一行的注释代码,因为我们已经知道debug里的makefile是最后执行的,所以最后直接去debug目录下执行指定的makefile文件就行,具体下面有注释
#DEBUG=$(shell ls -l | grep ^d | awk '{if($$9 == "debug") print $$9}')
#记住当前工程的根目录路径
ROOT_DIR=$(shell pwd)
#最终bin文件的名字,可以更改为自己需要的
BIN=myapp
#目标文件所在的目录
OBJS_DIR=debug/obj
#bin文件所在的目录
BIN_DIR=debug/bin
#获取当前目录下的c文件集,放在变量CUR_SOURCE中
CUR_SOURCE=${wildcard *.c}
#将对应的c文件名转为o文件后放在下面的CUR_OBJS变量中
CUR_OBJS=${patsubst %.c, %.o, $(CUR_SOURCE)}
#删除
RM=rm -rf
## debug flag
DBG_ENABLE   = 0
## need libs, add at here
LIBS := sqlite3 mylib
## used headers  file path
INCLUDE_PATH := $(ROOT_DIR)/includes/
#使用的库目录,静态库和动态库添加在这里
LIBRARY_PATH := /mnt/hgfs/vvv/
## debug for debug info, when use gdb to debug
ifeq (1, ${DBG_ENABLE}) 
	CFLAGS += -D_DEBUG -O0 -g -DDEBUG=1
endif
## get all include path
CFLAGS  += $(foreach dir, $(INCLUDE_PATH), -I$(dir))
## get all library path
LDFLAGS += $(foreach lib, $(LIBRARY_PATH), -L$(lib))
## get all librarys
LDFLAGS += $(foreach lib, $(LIBS), -l$(lib))
#将以下变量导出到子shell中,本次相当于导出到子目录下的makefile中
export CC BIN OBJS_DIR BIN_DIR ROOT_DIR LDFLAGS CFLAGS
#注意这里的顺序,需要先执行SUBDIRS最后才能是DEBUG
all:$(clean) $(SUBDIRS) $(CUR_OBJS) DEBUG
#递归执行子目录下的makefile文件,这是递归执行的关键
$(SUBDIRS):ECHO
	make -C $@
DEBUG:ECHO
#直接去debug目录下执行makefile文件
	make -C debug
ECHO:
	@echo $(SUBDIRS)
#将c文件编译为o文件,并放在指定放置目标文件的目录中即OBJS_DIR
$(CUR_OBJS):%.o:%.c
	$(CC) -c $^ -o $(ROOT_DIR)/$(OBJS_DIR)/$@ $(CFLAGS)
clean:
	@rm $(OBJS_DIR)/*.o
	@$(RM) $(BIN_DIR)/*
所有需要定义的变量都在这个文件中,也就是如果有和我给的例子不同的变量都在这个文件中修改即可。

其他子目录下的Makefile文件的内容如下:

#子目录的Makefile直接读取其子目录就行
SUBDIRS=$(shell ls -l | grep ^d | awk '{print $$9}')
#以下同根目录下的makefile的相同代码的解释
CUR_SOURCE=${wildcard *.c}
CUR_OBJS=${patsubst %.c, %.o, $(CUR_SOURCE)}
all:$(SUBDIRS) $(CUR_OBJS)
$(SUBDIRS):ECHO
	make -C $@
$(CUR_OBJS):%.o:%.c
	$(CC) -c $^ -o $(ROOT_DIR)/$(OBJS_DIR)/$@ $(CFLAGS)
ECHO:
	@echo $(SUBDIRS)
最后只需在根目录下,我的是我的根目录makefile目录下,执行make命令即可:
linux@ubuntu:~/work/makefiledemo/makedemo$ make
dir_a dir_b dir_c
make -C dir_a
make[1]: Entering directory `/home/linux/work/makefiledemo/makedemo/dir_a'
gcc -c func_a.c -o /home/linux/work/makefiledemo/makedemo/debug/obj/func_a.o  -I/home/linux/work/makefiledemo/makedemo/includes/
make[1]: Leaving directory `/home/linux/work/makefiledemo/makedemo/dir_a'
make -C dir_b
make[1]: Entering directory `/home/linux/work/makefiledemo/makedemo/dir_b'
dir_b_1
make -C dir_b_1
make[2]: Entering directory `/home/linux/work/makefiledemo/makedemo/dir_b/dir_b_1'
gcc -c func_b_1.c -o /home/linux/work/makefiledemo/makedemo/debug/obj/func_b_1.o  -I/home/linux/work/makefiledemo/makedemo/includes/
make[2]: Leaving directory `/home/linux/work/makefiledemo/makedemo/dir_b/dir_b_1'
gcc -c func_b.c -o /home/linux/work/makefiledemo/makedemo/debug/obj/func_b.o  -I/home/linux/work/makefiledemo/makedemo/includes/
make[1]: Leaving directory `/home/linux/work/makefiledemo/makedemo/dir_b'
make -C dir_c
make[1]: Entering directory `/home/linux/work/makefiledemo/makedemo/dir_c'
gcc -c func_c.c -o /home/linux/work/makefiledemo/makedemo/debug/obj/func_c.o  -I/home/linux/work/makefiledemo/makedemo/includes/
make[1]: Leaving directory `/home/linux/work/makefiledemo/makedemo/dir_c'
gcc -c main.c -o /home/linux/work/makefiledemo/makedemo/debug/obj/main.o  -I/home/linux/work/makefiledemo/makedemo/includes/
make -C debug
make[1]: Entering directory `/home/linux/work/makefiledemo/makedemo/debug'
gcc -o /home/linux/work/makefiledemo/makedemo/debug/bin/myapp obj/func_a.o obj/func_b_1.o obj/func_b.o obj/func_c.o obj/main.o  -I/home/linux/work/makefiledemo/makedemo/includes/  -L/mnt/hgfs/vvv/  -lsqlite3  -lmylib
make[1]: Leaving directory `/home/linux/work/makefiledemo/makedemo/debug'
结果目录结果为:
linux@ubuntu:~/work/makefiledemo/makedemo$ tree
.
├── debug
│   ├── bin
│   │   └── myapp
│   ├── Makefile
│   └── obj
│       ├── func_a.o
│       ├── func_b_1.o
│       ├── func_b.o
│       ├── func_c.o
│       └── main.o
├── dir_a
│   ├── func_a.c
│   └── Makefile
├── dir_b
│   ├── dir_b_1
│   │   ├── func_b_1.c
│   │   ├── head_b_1.h
│   │   └── Makefile
│   ├── func_b.c
│   ├── head_b.h
│   └── Makefile
├── dir_c
│   ├── func_c.c
│   ├── head_c.h
│   └── Makefile
├── includes
│   ├── head_a.h
│   ├── head.h
│   └── mylib.h
├── main.c
└── Makefile

8 directories, 23 files
然后执行". /debug/bin/myapp"即可;最后可以执行make clean清楚掉所有的目标文件和bin文件。

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值