目录
一、make的使用
当执行make命令时,make会在当前的目录下搜索Makefile文件,Makefile文件里面记录了源码如何编译的详细信息。其实make会按序去寻找当前目录下的GNUmakefile、makefile、Makefile,然后取最靠前的文件执行,忽略后面的文件。可以使用 -f 强制指定make所搜寻的文件。强烈建议,始终使用 Makefile文件。
make根据Makefile文件中的数据和每个文件更改的时间戳决定哪些文件需要更新。对于这些需要更新的文件,make会基于Makefile文件发布命令进行更新,更新的方式由提供的命令行参数控制。
1.1 make命令格式定义
1.2 make命令常用参数
-C dir:从当前目录切换到dir目录下执行make命令。
-C dir1 -C dir2 :切换到 dir1/dir2 目录下执行make命令;指定了多个-C选项,则每个选项都相对于前一个选项进行解释。
-f file:指定file文件作为makefile,参与make命令的执行。
二、Makefile的规则
target 1(目标1) : prerequisites(先决条件)
<Tab> command 1(命令1)
target 2(目标2) : prerequisites(先决条件)
<Tab> command 2(命令2)
# 目标可以是一个要产生的文件,也可以是一个标签。
# prerequisites为要生成目标所需要的依赖,可以为空。注意,目标和依赖之前必须使用 ':' 分隔开来。
# 命令是make执行的动作,一个规则可以含有几个命令,每个命令单独占一行,每个命令行前面必须是一个Tab字符。
# 以 '#' 字符开头的内容表示注释内容。
2.1 内置-预定义变量
使用make命令的时候,只要不附带参数 -R ,就会默认启用内置的预定义变量。常见的预定义变量如下:
变量名 | 描述 | 缺省值 |
CC | C语言编译程序 | cc,指向gcc |
CFLAGS | C编译器的额外标志 | 空 |
RM | 删除文件的命令 | rm -f |
2.2 内置-特殊目标
在Makefile文件中,一些名字作为目标使用是具有特殊含义的。常见的特殊目标如下:
目标名 | 描述 | |
.PHONY | 目标的依赖是假想目标。假想目标是这样一些目标,make无条件的执行该命令,和目录下是否存在该文件以及它最后一次更新的时间没有关系。 | |
.DEFAULT | 用于那些没有找到规则(具体规则或隐含规则)更新的目标。make如果无法匹配到指定目标,那么就会去执行该缺省目标。 |
2.3 内置-文本函数
在Makefile文件中,有一些内置的文本函数可以有效提高编码效率。常见的文本函数如下:
函数名(带下划线) | 描述 | |
${wildcard ./*.c} | 可以在Makefile文件的任何地方使用该字符串,应用时该字符串被一列在指定目录下存在的并且文件名和给出文件名的格式相符合的文件所代替,文件名中间由空格隔开。如果没有和指定格式一致的文件,则函数 wildcard 的输出将会省略。 | |
${patsubst %.c, %.o, text} | 将 text 字符串中所有的 '.c' 后缀变为 '.o',转换为目标文件名字符串。如果没有匹配并转换成功,则函数 patsubst 的输出为 text 的原本内容。 |
三、工程示例
3.1 目录结构
3.2 文件内容
3.2.1 源文件
/* ./src/main/main.c */
#include "add.h"
#include "sub.h"
#include "print.h"
int main()
{
printInt("1+1=", add(1,1));
printInt("1-1=", sub(1,1));
printStr("wangsong");
return 0;
}
/* ./src/math/add.c */
#include "add.h"
int add(int a, int b)
{
return a + b;
}
/* ./src/math/sub.c */
#include "sub.h"
int sub(int a, int b)
{
return a - b;
}
/* ./src/util/print.c */
#include <stdio.h>
#include "print.h"
void printStr(char* s)
{
printf("%s\n", s);
}
void printInt(char* prefix , int n)
{
printf("%s %d\n", prefix, n);
}
3.2.2 头文件
/* ./inc/math/add.h */
#ifndef __ADD_H__
#define __ADD_H__
#ifdef __cplusplus
extern "C"
{
#endif
int add(int a, int b);
#ifdef __cplusplus
}
#endif
#endif
/* ./inc/math/sub.h */
#ifndef __SUB_H__
#define __SUB_H__
#ifdef __cplusplus
extern "C"
{
#endif
int sub(int a, int b);
#ifdef __cplusplus
}
#endif
#endif
/* ./inc/util/print.h */
#ifndef __PRINT_H__
#define __PRINT_H__
#ifdef __cplusplus
extern "C"
{
#endif
void printStr(char* s);
void printInt(char* prefix, int n);
#ifdef __cplusplus
}
#endif
#endif
3.2.3 Makefile文件
# ./Makefile
BIN = ./bin/main.exe
build:
${MAKE} -C ./src build
gcc -o ${BIN} ./src/*/*.o
.PHONY: clean
clean:
${MAKE} -C ./src clean
rm -f ${BIN}
# ./src/Makefile
INCLUDES = -I./../inc/math \
-I./../inc/util
DIRECTORY = ./*
SOURCES = ${wildcard $(DIRECTORY)/*.c}
OBJECTS = ${patsubst %.c, %.o, $(SOURCES)}
CC = gcc
CFLAGS = -Wall ${INCLUDES}
build:${OBJECTS}
@echo \## src: ${SOURCES}
@echo \## obj: ${OBJECTS}
.PHONY: clean
clean:
rm -f ${OBJECTS}
.DEFAULT:
@echo \#### target error, please attention!!!
3.3 执行结果
3.3.1 make
3.3.2 make clean