当前位置: 首页 > news >正文

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;elsereturn n * factorial(n - 1);
}

1.2. 最简单的编译命令:

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

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

main: main.cpp printhello.cpp factorial.cppg++ -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字讲解:详细讲解


http://www.mrgr.cn/news/27357.html

相关文章:

  • C2000 F280049 Timer模块开发
  • Windows 的 docker 删除容器后 WSL2 磁盘空间不释放的问题
  • Java 21的Enhanced Deprecation的笔记
  • nacos和eureka的区别
  • 数据集 wider person 户外密集行人检测 >> DataBall
  • node.js精品课程网站—计算机毕业设计源码27724
  • JNI编程实现原理
  • 三维点云处理(C++)学习记录——PDAL
  • 技术周总结 09.09~09.15周日(C# WinForm WPF)
  • 使用Flux以文生图
  • [产品管理-16]:NPDP新产品开发 - 14 - 产品创新流程 - 产品创新流程模型比较:门径、IPD、精益生产、敏捷、系统工程、设计思维、精益创业
  • Java 全面指南:从入门到精通
  • PMP--一模--解题--61-70
  • re题(19)BUUCTF[ACTF新生赛2020]easyre
  • 【MySQL-初级】mysql基础操作(账户、数据库、表的增删查改)
  • 【C#生态园】选择最适合你的工具:C# GUI库完整比较及指南
  • 大模型大侦探-一次丝滑的探图记录
  • MyBatis系统学习(二)——MyBatis 核心配置与对象解析
  • 知识竞赛活动舞台搭建要多少钱
  • stm32单片机个人学习笔记3(GPIO输出)