Makefile-例程讲解

来源:互联网 发布:什么软件是写小说的 编辑:程序博客网 时间:2024/06/05 16:10

我们已经在Makefile语法和Makefile常用函数这两篇文章中讲解了makefile编写的一些基本语法和规则,下面就让我们实战一下吧。
今天我们主要讲一下makefile文件递归式写法。
我们先看一下我们将要用到的源码:
1.主文件test/main.c:

//path: ..src/main.c#include <stdio.h>#include "add.h"#include "sub.h"int main(){    int a=10,b=12;    float x=1.23456,y=9.87654;    printf("int a+b IS:%d\n",add_int(a,b));    printf("int a-b IS:%d\n",sub_int(a,b));    printf("float x+y IS:%f\n",add_float(x,y));    printf("float x-y IS:%f\n",sub_float(x,y));    return 0;}

2.减法的头文件

//path: ../inc/sub/sub.h#ifndef _SUB_H_#define _SUB_H_extern float sub_float(float a, float b);extern int sub_int(int a, int b);#endif

3.浮点数减法的实现

//path: ../src/sub/sub_float.cfloat sub_float(float a, float b){    return a-b;}

4.实现int型的减法函数定义文件:

//path: ../src/sub/sub_int.cint sub_int(int a, int b){    return a-b;}

5.加法声明的头文件:

//path: ../inc/add/add.h#ifndef _ADD_H_#define _ADD_H_extern int add_int(int a, int b);extern float add_float(float a, float b);#endif

6.浮点数加法的实现

//path: ../src/add/add_float.cfloat add_float(float a, float b){    return a+b;}

7.整数加法的实现

//path: ../src/add/add_int.cint add_int(int a, int b){    return a+b;}

我们的目录结构如下:

.├── inc│   ├── add│   │   └── add.h│   └── sub│       └── sub.h├── Makefile└── src    ├── add    │   ├── add_float.c    │   ├── add_int.c    │   └── Makefile    ├── main.c    ├── Makefile    └── sub        ├── Makefile        ├── sub_float.c        └── sub_int.c

我们可以看到顶层目录有两个文件夹inc和src,分别用来包含头文件和源文件;还有一个顶层Makefile。inc目录就不细说了。src子目录下有2个深层子目录用来分别存储不同模块的源代码,还有一个main.c和Makefile文件:main.c实现该工程的入口以及主要功能;Makefile是用来管理src/目录下编译的文件。两个子目录./sub
和./add分别实现加法和减法,也有自己独立的Makefile。
接下来看看怎么写Makefile文件。

递归式

为了实现每个目录下的代码具有独立的Makefile,且根目录下的Makefile可以一次执行子目录下的Makefile,就有了递归式的方法来写父目录下的Makefile了,该方法的实现是使用的$(MAKE)变量,使用格式如下:

dd:    cd add &&  $(MAKE)

也可以这样写:

add:    $(MAKE)  -C add

这样就可以递归调用子目录add下面make命令来执行add目录下的Makefile文件,我们先把add和sub两个子目录下的makefile文件写好来,如下:
./add/Makefile

OBJS = add_int.o add_float.oCFLAGS = -O2all:$(OBJS)$(OBJS):%.o:%.c    $(CC) -c $< -o $(OBJS_DIR)/$@ $(CFLAGS)
OBJS = sub_int.o sub_float.oCFLAGS = -O2all:$(OBJS)$(OBJS):%.o:%.c    $(CC) -c $< -o $(OBJS_DIR)/$@ $(CFLAGS)

./src/Makefile内容:

# 取得当前子目录深度为1的所有目录名称SRC_DIRS := $(shell find . -maxdepth 1 -type d)SRC_DIRS := $(basename $(patsubst ./%,%,$(SRC_DIRS)))SRC_DIRS := $(filter-out $(EXCLUDE_DIRS),$(SRC_DIRS)).PHONY: $(SRC_DIRS)# 子目录执行默认make target$(SRC_DIRS): $(SRC_DIRS) main.o    $(MAKE) -C $@main.o: %.o:%.c    $(CC) -c $< -o $(OBJS_DIR)/$@ $(CFLAGS) $(INCS_DIRS)

接下来就是写主目录makefile_common_project下面的Makefile文件了,使用前面递归调用格式,Makefile文件如下:

CC = gccCFLAGS = -O2CXXFLAGS =TARGET = outfileBIN_DIRS := binINCS_DIRS := inc# 需要排除的目录EXCLUDE_DIRS := inc bin# INCLUDE DIRECTORYINCS_DIRS := $(shell find $(shell pwd)/$(INCS_DIRS) -maxdepth 1 -type d)INCS_DIRS := $(basename $(patsubst ./%,%,$(INCS_DIRS)))INCS_DIRS := $(foreach inc_tmp,$(INCS_DIRS),-I $(inc_tmp))export INCS_DIRS# 取得当前子目录深度为1的所有目录名称ALL_DIRS := $(shell find . -maxdepth 1 -type d)ALL_DIRS := $(basename $(patsubst ./%,%,$(ALL_DIRS)))ALL_DIRS := $(filter-out $(EXCLUDE_DIRS),$(ALL_DIRS))# 避免clean子目录操作同名,加上 _clean_ 前缀SUB_DIRS := $(ALL_DIRS)CLEAN_DIRS := $(addprefix _clean_,$(SUB_DIRS))export OBJS_DIR = ${shell pwd}/.objs.PHONY: $(TARGET) $(SUB_DIRS) clean# 执行默认make target$(SUB_DIRS):    mkdir -p $(OBJS_DIR)    $(MAKE) -C $@    $(CC) -o $(TARGET) $(OBJS_DIR)/*.o$(TARGET): $(SUB_DIRS)# 执行clean#$(CLEAN_DIRS):#   $(MAKE) -C $(patsubst _clean_%,%,$@) clean# @,为不回显的命令#clean: $(CLEAN_DIRS)#   find ./#   /( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' /#   -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' /#   -o -name '*.symtypes' /) /#   -type f -print | xargs rm -f#clean: $(CLEAN_DIRS)clean:    -$(RM) -r $(OBJS_DIR) $(OBJS_DIR)/*.o

(MAKE)C@” 这句实现的就是在执行下面的命令前先遍历执行子目录下的makefile文件。
递归式的测试结果:

aaron@aaron-Inspiron-5520:~/tmp/makefile_test/makefile_common_project$ makemkdir -p /home/aaron/tmp/makefile_test/makefile_common_project/.objsmake -C srcmake[1]: 正在进入目录 `/home/aaron/tmp/makefile_test/makefile_common_project/src'make[1]: 放弃循环依赖 sub <- sub 。make[1]: 放弃循环依赖 add <- sub 。make[1]: 放弃循环依赖 add <- add 。cc -c main.c -o /home/aaron/tmp/makefile_test/makefile_common_project/.objs/main.o  -I /home/aaron/tmp/makefile_test/makefile_common_project/inc -I /home/aaron/tmp/makefile_test/makefile_common_project/inc/sub -I /home/aaron/tmp/makefile_test/makefile_common_project/inc/addmake -C addmake[2]: 正在进入目录 `/home/aaron/tmp/makefile_test/makefile_common_project/src/add'cc -c add_int.c -o /home/aaron/tmp/makefile_test/makefile_common_project/.objs/add_int.o cc -c add_float.c -o /home/aaron/tmp/makefile_test/makefile_common_project/.objs/add_float.o make[2]:正在离开目录 `/home/aaron/tmp/makefile_test/makefile_common_project/src/add'make -C submake[2]: 正在进入目录 `/home/aaron/tmp/makefile_test/makefile_common_project/src/sub'cc -c sub_int.c -o /home/aaron/tmp/makefile_test/makefile_common_project/.objs/sub_int.o cc -c sub_float.c -o /home/aaron/tmp/makefile_test/makefile_common_project/.objs/sub_float.o make[2]:正在离开目录 `/home/aaron/tmp/makefile_test/makefile_common_project/src/sub'make[1]:正在离开目录 `/home/aaron/tmp/makefile_test/makefile_common_project/src'gcc -o outfile /home/aaron/tmp/makefile_test/makefile_common_project/.objs/*.o

总结:
本人也是初学Makefile的编写,上面的Makefile虽然能够遍历所有目录,并最终生成可执行代码。但是看编译过程还是有问题,先记录下,再改进吧!

0 0
原创粉丝点击