简单编写makefile

1. 为什么需要编写makefile

  • 1.一个工程中的源文件不计其数,按类型、功能、模块分别放在若干目录中,若尝试一个个文件编译,未免效率太低,而编写一个良好的makefile则会提高我们编译的效率
  • 2.在makefile中,我们可以定义一系列的规则,指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译。甚至于进行更复杂的功能操作,给我们在编译过程中带来极大的便利
  • 3.makefile带来的好处即是实现了“自动化编译”,只需一个make操作就能自动将一个具有多目录的大项目编译完成,大大提高了开发的效率

2. "初级"makefile编写

一个makefile基本的规则:

A: B
(tab)<command>
(tab)<command>

A为目标文件,B为依赖文件(可能含有多个),接下来为命令(必须含有tab),操作依赖文件得到目标文件

以一个简单的示例来演示如何编写一个基础的makefile:

//file1.h
#ifndef FILE1_H
#define FILE1_H
#ifdef __cplusplus
        extern "C" {
                #endif
                void File1Print();
                #ifdef __cplusplus
        }
        #endif
#endif
//file1.cpp
#include <iostream>
#include "file1.h"
using namespace std;
void File1Print() {
        cout << "Print file1**************************" << endl;
}
//file2.cpp
#include <iostream>
#include "file1.h"
using namespace std;
int main()
{
        cout << "Print file2***********************" << endl;
        File1Print();
        return 0;
}

根据上述的规则,我们可以写出如下的makefile:

helloworld: file1.o file2.o
	g++ file1.o file2.o -o helloworld
file2.o: file2.cpp
	g++ -c file2.cpp -o file2.o
file1.o: file1.cpp file1.h
	g++ -c file1.cpp -o file1.o
clean:
	rm -rf *.o helloworld

在这里可以看出基本基于规则来写的,而且先执行file2.cpp,同时在这里加了一条clean语句,方便清除文件(*.o即匹配所有后缀为.o的文件并清除)

来简单测试一下,得到如下的结果:
在这里插入图片描述
可以看到make之后执行的是我们在makefile中编写的几条命令,接着我们编译得到的可执行文件helloworld,同时测试所编写的clean语句,得到如下结果:
在这里插入图片描述

到这里就可以简单编写一下makefile了,再上一层楼,简单使用变量!

3. “进阶”makefile

为什么需要在makefile中引入变量呢?有时出现在makefile中的参数重复出现或依赖项太长等原因,导致makefile编写效率低,这个时候引入变量就可以让我们的makefile看着更为简洁,编写也更为方便

要设定一个变量,只要在一行的前端写下这个变量的名字,后面跟一个“=”号,后面跟要设定的这个变量的值即可。以后要引用这个变量,只写一个“$”符号,后面是在括号里的变量名即可

那我们将上面的makefile简单修改一下,引入变量,如下:

OBJS = file1.o file2.o
XX = g++
CFLAGS = -Wall -O -g
helloworld : $(OBJS)
        $(XX) $(OBJS) -o helloworld
file2.o:file2.cpp file1.h
        $(XX) $(CFLAGS) -c file2.cpp -o file2.o
file1.o:file1.cpp file1.h
        $(XX) $(CFLAGS) -c file1.cpp -o file1.o
clean:
        rm -rf *.o helloworld

在这里可以发现,g++这一操作重复出现,可以以变量代替,在这里我们还添加了一个变量CFLAGS,这个变量被加入到g++操作中,可以简单分析一下这个变量

CFLAGS = -Wall -O -g:配置编译器设置,并把它赋值给CFLAGS变量,其中每个部分含义为:1. -Wall:输出所有的警告信息;2.-O:编译时进行优化;3.-g:表示编译debug版本

来make一下,得到以下结果(可以看到变量在运行时被替换):
在这里插入图片描述

添加变量也比较简单及容易理解,但我们很容易发现其缺点,即当我们添加一个文件到我们的项目中时,我们就得修改我们的makefile,这样也显得较为繁杂,所以尝试引入内嵌函数及内部变量来让我们编写的makefile有较好的兼容性

4. “高级”makefile

先将上述的makefile改写,然后再来详细解析:

CC = gcc
XX = g++
TARGET = helloworld
CFLAGS = -Wall -O -g
%.o : %.c
        $(CC) $(CFLAGS) -c $< -o $@
%.o : %.cpp
        $(XX) $(CFLAGS) -c $< -o $@
SOURCES = $(wildcard  *.c  *.cpp)
OBJS = $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCES)))

$(TARGET) : $(OBJS)
        $(XX) $(OBJS) -o $(TARGET)
clean:
        rm -rf *.o helloworld

1.首先来看看其中的两个内嵌函数:

  • $(wildccard PATTERN…),在makefile中,它被展开为已经存在的、使用空格分开的、匹配此模式的所有文件列表。如果不存在任何符合此模式的文件,函数会忽略模式字符并返回空;在本例中这个函数代表着匹配所有后缀为.c或.cpp的文件并存入SOURCES
  • patsubst函数,用于匹配替换,有3个参数。第一个是一个需要匹配的字样,第二个表示用什么来替换它,第三个是一个变量需要被处理的由空格分隔的列表
    本例中第一个patsubst函数表示将所有.c后缀的文件替换为.o后缀的文件,而第三个参数又是一个函数,表示将所有.cpp后缀的文件替换为.o后缀的文件,这样子形成的一个列表作为第一个patsubst的参数,所以整句话表示了将SOURCES中所有.c或.cpp后缀的文件替换为.o文件
    关于更多内嵌函数Makefile所有内嵌函数

2.接着来认识其中的几个内部变量:

  • $@,表示目标文件
%.o : %.c
        $(CC) $(CFLAGS) -c $< -o $@

在上述语句中表示以.o为后缀的文件

  • $<,表示第一个依赖文件,即要生成目标文件需要多个依赖文件,则选取其中的第一个
//例
helloworld: file1.o file2.o

则表示file1.o

  • $^,表示全部依赖文件,即上述示例中的file1.o file2.o

更多的了解内部变量关于内部变量

了解了这些,可以来编译此makefile:
在这里插入图片描述
到这里我们的简单makefile编写就算结束了,想要编写极为出色的makefile,还需潜心学习!!!

--------------------------------------------get------------------------------------------

简单makefile的编写

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值