提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
结构
下面以我自己写的一个很小的工程代码为例!带你进入多目录、多文件下的makefile的编写:
-
1、首先我们需要创建一个test目录,然后在test目录下创建5个目录,分别为inc、lib、main、obj、src。和一个Makefile文件。
下面就主要介绍下这四个文件的主要存放的文件和作用
–inc:inc目录就是include的缩写,主要存放在一些头文件。
–lib: lib目录就是library的缩写,主要就是存放一些库文件。比如.a、.so等静态库和动态库文件。
–main: 该目录就是存放main函数的文件,程序的入口就是从该目录下的main函数下开始的。
–obj:obj目录就是object的缩写,主要存放的就是目标文件,一些可重定向文件,如.o等文件。
–src:src目录就是source的缩写,就是存放一些源文件,main函数主要调用src目录下的一个函数。
Makefile:主makefile文件,该makefile主要定义一些目录的路径然后跳到指定目录下的makefile中执行相应子目录下的makefile。 -
2、在main目录下有一个main.c文件和Makefile文件,二话不说,直接上代码吧!
main.c的代码
#include<stdio.h>
#include "test.h"
int main(void)
{
test1();
test2();
return 0;
}
main目录下的子Makefile
$(OBJ_DIR)/main.o:main.c
$(CC) -c $^ -o $@ $(CFLAG)
- 3、src目录下有三个文件,test1.c、test2.c、Makefile
test1.c
#include "test.h"
void test1()
{
printf("test1\n");
return;
}
test2.c
#include "test.h"
void test2()
{
printf("test2\n");
return;
}
src目录下的子Makefile:
.PHONY:all
all:$(OBJ_DIR)/test1.o $(OBJ_DIR)/test2.o
$(OBJ_DIR)/test1.o:test1.c
$(CC) -c $^ -o $@ $(CFLAG)
$(OBJ_DIR)/test2.o:test2.c
$(CC) -c $^ -o $@ $(CFLAG)
- 4、obj目录下就只有一个Makefile文件
OBJ=$(wildcard *.o)
$(PWD_DIR)/app:$(OBJ)
$(CC) -o $@ $^
- 5、inc目录下也只有一个文件test.h
#ifndef _TEST_H
#define _TEST_H
#include<stdio.h>
void test1();
void test2();
#endif
- 6、主目录下的Makefile
.PHONY:all clean
##
PWD_DIR=$(shell pwd)
SRC_DIR=$(PWD_DIR)/src
OBJ_DIR=$(PWD_DIR)/obj
MAIN_DIR=$(PWD_DIR)/main
LIB_DIR=$(PWD_DIR)/lib
INC_DIR=$(PWD_DIR)/inc
##
CC=gcc
CFLAG=-Wall -g -I$(INC_DIR)
##
export PWD_DIR SRC_DIR OBJ_DIR MAIN_DIR LIB_DIR INC_DIR CC CFLAG
##
all:
make -C $(SRC_DIR)
make -C $(MAIN_DIR)
make -C $(OBJ_DIR)
##
clean:
$(RM) -rf $(OBJ_DIR)/*.o
$(RM) app
执行解析
到现在为止,已经把所以的代码都呈现出来了!现在就来说说makefile的总体执行流程!
首先进入test目录下,看下主目录下的Makefile。如果你以前从来没有学过Makefile,也许你会觉得这是乱码!怎么会有这样一堆的东西呢?但是只要你细心去看,还是能找到规律的。
##
PWD_DIR=$(shell pwd) #这里是执行shell的pwd命令获取路劲作为PWD_DIR参数
SRC_DIR=$(PWD_DIR)/src
OBJ_DIR=$(PWD_DIR)/obj
MAIN_DIR=$(PWD_DIR)/main
LIB_DIR=$(PWD_DIR)/lib
INC_DIR=$(PWD_DIR)/inc
这些就是获取当前目录和其他子目录的路径,然后通过
##
export PWD_DIR SRC_DIR OBJ_DIR MAIN_DIR LIB_DIR INC_DIR CC CFLAG
这条语句把所以的目录路径导出,给子Makefile使用。
##
all:
make -C $(SRC_DIR)
make -C $(MAIN_DIR)
make -C $(OBJ_DIR)
make -C 目录 -------》 这就代表执行指定目录下的makefile
所以这几条语句就是依次执行以下几个目录下的makefile
##
clean:
$(RM) -rf $(OBJ_DIR)/*.o
$(RM) app
这几条语句删除编译生成的目标文件和可执行文件app
main目录下Makefile
$(OBJ_DIR)/main.o:main.c
$(CC) -c $^ -o $@ $(CFLAG)
将main.c文件编译成main.o放在obj目录下
src目录下的Makefile
.PHONY:all
all:$(OBJ_DIR)/test1.o $(OBJ_DIR)/test2.o
$(OBJ_DIR)/test1.o:test1.c
$(CC) -c $^ -o $@ $(CFLAG)
$(OBJ_DIR)/test2.o:test2.c
$(CC) -c $^ -o $@ $(CFLAG)
这里的意思是将test1.c和test2.c编译成目标文件存放在obj文件。
下面来看下obj目录下的Makefile文件了
OBJ=$(wildcard *.o)
$(PWD_DIR)/app:$(OBJ)
$(CC) -o $@ $^
将所以的目标文件编译成可执行文件app放在PWD_DIR目录下.wildcard解释如下
wildcard解释:用来明确表示通配符。因为在 Makefile 里,变量实质上就是 C/C++ 中的宏,也就是说,如果一个表达式如 objs = *.o ,则 objs 的值就是 *.o ,而不是表示所有的 .o 文件。若果要使用通配符,那么就要使用 wildcard 来声明 * 这个符号,使 * 符号具有通配符的功能。