make命令和makefile文件

make命令

make命令是用于程序编译的工具, 当需要通过多个输入文件来生成输出文件时, 可以利用它来完成。

make命令的一些可选参数:
-B 无条件编译所有目标
-c dir 读取makefile之前切换到指定的目录dir
-f 告诉make命令将哪个文件作为makefile文件;
-n 让make命令输出将要执行的操作步骤,但不是真的执行这些操作。
具体可以通过man make查看。

makefile文件

makefile文件是由一组依赖关系和规则构成。 每个依赖关系和由一个目标(即将要创建的文件)和一组该目标所依赖的源文件组成。 规格描述了如何通过这些依赖来创建文件。

make命令会读取makefile文件的内容, 先确定目标文件或者要创建的文件, 然后比较该目标所依赖的日期和时间以决定应该采用哪条规则来构建目标。make命令会根据makefile文件来确定目标文件的创建顺序以及正确的规则调用顺序。

依赖关系

依赖关系定义了最终应用程序里面的每个文件与源文件之间的关系。
依赖关系的写法是: 先写目标的名称, 然后紧跟一个冒号, 接着是空格或者制表符tab, 最后用空格或者制表符隔开的文件列表。

main: main.o
    gcc -o main.o
main.o: main.c a.h
    gcc -c main.c

下面就按照这种写法来写一个简单的makefile文件
先准备几个源文件和头文件
sum.h

#ifndef _SUM_H
#define _SUM_H
#endif

int Sum(int a, int b);

sum.c

#include "sum.h"

int Sum(int a, int b)
{
    return a + b;
}

minus.h

#ifndef _MINUS_H
#define _MINUS_H
#endif

int Minus(int a, int b);

minus.c

#include "minus.h"

int Minus(int a, int b)
{
    return a - b;
}

main.c

#include <stdio.h>
#include <stdlib.h>
#include "sum.h"
#include "minus.h"

extern int Sum(int a, int b);
extern int Minus(int a, int b);

int main()
{
    int a = 3;
    int b = 2;
    printf("%d + %d = %d\n", a, b, Sum(a,b));
    printf("%d - %d = %d\n", a, b, Minus(a,b));
}

makefile1

all: main
main: main.o sum.o minus.o
    gcc -o main main.o sum.o minus.o
main.o: main.c minus.h sum.h
    gcc -c main.c
sum.o: sum.c sum.h
    gcc -c sum.c
minus.o: minus.c minus.h
    gcc -c minus.c

make命令执行makefile1文件,并运行main程序,输出如下结果:

$ make -f makefile1
gcc -c main.c
gcc -c sum.c
gcc -c minus.c
gcc -o main main.o sum.o minus.o
$ ./main
3 + 2 = 5
3 - 2 = 1

其中, all指定一个目标, 在未指定特定目标进行make时,可以指定应该创建哪些目标。若没有all, make命令将试图创建列在makefile文件中的第一个目标。

gcc -MM命令

这个命令可以用于产生一个适用于make命令的依赖关系清单。下面就试一下,还是用上面准备的源文件, 在源文件目录下,输入如下命令:

$ gcc -MM *.c
main.o: main.c sum.h minus.h
minus.o: minus.c minus.h
sum.o: sum.c sum.h

几个源文件之间的依赖关系一目了然。

makefile中的注释和宏

注释以#号开头,直到这行末尾。

# test makefile
main: main.o

makefile文件中的宏长用与设置编译器的选项。 宏可以用来收集不同系统相关内容。
宏通常是在makefile中定义的, 但是也可以在使用make时在命令行上给出宏定义。 此时,命令行上的宏定义将覆盖掉在makefile文件中定义的宏定义。当在makefile文件之外使用宏定义时, 要注意宏定义必须以单个参数的形式传递, 避免在宏定义中使用空格或者应该给宏定义加上双引号。

继续使用前面的源文件来实验。 写一个使用宏定义的makefile2

all: main

# 使用的编译器
CC = gcc

# 包含文件
INCLUDE = .

# development
CFLAGS = -g -Wall -ansi

# release
# CFLAGS = -O -Wall -ansi

main: main.o sum.o minus.o
    $(CC) -o main main.o sum.o minus.o
main.o: main.c sum.h minus.h
    $(CC) -I$(INCLUDE) $(CFLAGS) -c main.c
sum.o: sum.c sum.h
    $(CC) -I$(INCLUDE) $(CFLAGS) -c sum.c
minus.o: minus.c minus.h
    $(CC) -I$(INCLUDE) $(CFLAGS) -c minus.c

关于$^ $@ $<的使用

make命令内置了一些特殊的宏命令,利用它们可以使makefile文件变得很简洁。

$^:代表所有的依赖文件
$@:代表目标
$<:代表第一个依赖文件

其他技巧

-: -(减号)可以放在命令之前,告诉make命令忽略所有错误。
比如可以在makefile2最后加上如下命令, 可以将编译过程中的*.o文件删除。

clean:
    -rm main.o sum.o minus.o

执行的时候可以按照如下方式进行

make -f makefile2 clean

@: @告诉make在执行某条命令前不要将该命令显示在标准输出上,如果想用echo命令给出一些说明信息。

对于大型的项目, 如果希望把构成一个函数库的几个文件从主文件中分离出来, 并将它们保存到一个子目录中。 有两种使用make命令的方法来完成这个工作(还没有试过)。
1. 第一种方法
在子目录中编写第二个makefile文件, 其作用是编译该子目录下的源文件,并将它们保存到一个函数库中, 然后将该库文件复制到上一级的主目录中。在主目录中的makefile文件包含一条用于制作函数库的规则, 该规则会调用第二个makefile文件。

mylib.a:
    (cd mylibdirectory;$(MAKE))

当用make命令调用这条规则来创建函数库时, 它将切换到子目录mylibdirectory中,然后调用一个新的make命令来管理函数库。
cd切换目录前面的括号是必须的, 这样可以确保它们只被一个单独shell处理。
2. 第二种方法
在原来的makefile中增加一些宏, 将新添加的宏通过在已见过的宏的尾部追加一个字幕得到, 字母D代表目录, 字母F代表文件名。

.c.o:
    $(CC) $(CFLAGS) -c $(@D)/$(<F) -o $(@D)/$(@F)

参考博客

* makefile下 (wildcard ^), , @, ?, <, (@D), (@F)义 *

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值