makefile的介绍与使用

1. 简单示例:

1.1. 代码结构:

main.cpp

#include <iostream>
#include "functions.h"

using namespace std;

int main()
{
  printhello();
  cout << "here is main" << endl;
  cout << "factorial 5 is : " << factorial(5) << endl;
  return 0;
}

functions.h

#pragma once
// 输出hello
void printhello();
// 获得阶乘
int factorial(int n);

printhello.cpp

#include <iostream>
#include "functions.h"

using namespace std;

void printhello()
{
    int i = 1;
    cout << "hello!" << endl;
}

factorial.cpp

#include "functions.h"
int factorial(int n)
{
    if (n == 1)
        return 1;
    else
        return n * factorial(n - 1);
}

1.2. 最简单的编译命令:

g++ main.cpp printhello.cpp factorial.cpp -o main

1.3. 与最简单的编译命令相同的Makefile

main: main.cpp printhello.cpp factorial.cpp
    g++ -o main main.cpp printhello.cpp factorial.cpp

1.4. 普通版本的Makefile版本:

所有文件名称都手写,且每次都写两个过程:

  1. 可执行文件的编译命令
  2. 每一个链接文件的生成命令
## 指定编译器版本
CXX = g++
## 目标文件,即最后的可执行文件名称
TARGET = main
## 目标文件的依赖文件变量定义
OBJ = main.o printhello.o factorial.o
## 目标文件的依赖文件关系
## 如果需要重新生成依赖文件,那么需要执行的命令
$(TARGET): $(OBJ)
	$(CXX) $(OBJ) -o $(TARGET)
## 每一个依赖文件的依赖文件关系和重新生成需要执行的命令
main.o: main.cpp
	$(CXX) -c main.cpp -o main.o
printhello.o: printhello.cpp
	$(CXX) -c printhello.cpp -o printhello.o
factorial.o: factorial.cpp
	$(CXX) -c factorial.cpp -o factorial.o

好处:每次只会重新编译修改了的那一个文件,而不像1.3一样每次都需要将项目的每一个文件都重新编译一次。极大的提高了编译效率。

1.5. 优化1.4链接文件生成的Makefile版本:

优化内容:

又少了一些需要固定写死的内容。

比如之前的链接文件每一个都需要写出来,现在只需要一行就能写出来了

## 指定编译器版本
CXX = g++
## 目标文件,即最后的可执行文件名称
TARGET = main
## 目标文件的依赖文件变量定义
OBJ = main.o printhello.o factorial.o
## 编译命令的可配参数
CXXFLAGS = -c -Wall
## 目标文件的依赖文件关系
## 如果需要重新生成依赖文件,那么需要执行的命令
$(TARGET): $(OBJ)
	$(CXX) $^ -o $@
## 每一个依赖文件的依赖文件关系和重新生成需要执行的命令
%.o: %.cpp
	$(CXX) $(CXXFLAGS) $< -o $@
## 如果当前目录下不存在一个名称为clean可执行文件,那么给make添加一个clean命令
.PHONY: clean
# clean命令的内容
clean:
	rm -f *.o $(TARGET)

参数解释:

  • $^ 是冒号后面的内容,即 $(OBJ)
  • $@ 是冒号前面的内容,即 $(TARGET)
  • $< 是冒号后面的后面的内容,即 %.cpp
  • $^ 与 < 的区别是: < 的区别是: <的区别是:^ 取的是字符串整个文本,而 $< 取的是字符串内的第一个元素。比如字符串为 main.cpp hello.cpp func.cpp,那么使用 $^ 取的就是:main.cpp hello.cpp func.cpp,而使用 $< 取的就是 main.cpp
  • % :通配符
    • %.o : 当前代码【Makefile】中每一个以 .o结尾的变量名称
    • %.cpp : 取前面.o的名称
  • 但是 % 会将每一个变量分别执行一次,而不是说 % 是将所有变量都填写的这里。
  • .PHONY:判断当前文件的目录下是否存在该可执行文件

1.6. 最灵活的Makefile版本

## 指定编译器版本
CXX = g++
## 目标文件,即最后的可执行文件名称
TARGET = main
## 获取当前文件夹下的所有*.cpp文件名称
SRC = $(wildcard *.cpp)
## 将所有*.cpp名称替换为*.o
## 目标文件的依赖文件变量定义
OBJ = $(patsubst %.cpp, %.o, $(SRC))
## 编译命令的可配参数
CXXFLAGS = -c -Wall
## 目标文件的依赖文件关系
## 如果需要重新生成依赖文件,那么需要执行的命令
$(TARGET): $(OBJ)
	$(CXX) $^ -o $@
## 每一个依赖文件的依赖文件关系和重新生成需要执行的命令
%.o: %.cpp
	$(CXX) $(CXXFLAGS) $< -o $@
## 如果当前目录下不存在一个名称为clean可执行文件,那么给make添加一个clean命令
.PHONY: clean
# clean命令的内容
clean:
	rm -f *.o $(TARGET)
  • wildcard:获取当前目录下的内容
  • patsubst:进行替换操作

2. 问题解决:

2.1. Makefile: *** missing separator. Stop.

原因:Vim可能默认会将 Tab 换成 空格

解决办法:

  1. 修改 /etc/vimrc
  2. 添加一行内容:set noexpandtab
  3. 然后重新回到Makefile文件中,删除空格重新打Tab即可。

3. 借鉴文章:

Makefile 20分钟入门,简简单单,展示如何使用Makefile管理和编译C++代码_哔哩哔哩_bilibili

3W字讲解:详细讲解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值