Makefile快速入门

news2024/11/29 8:02:42

介绍

这里以一个例子来演示利用Makfile进行多文件编译

一共有四个源程序:main.cpp,printhello.cpp,factorial.cpp,functions.h

首先是main.cpp内容

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

using namespace std;

int main()
{
    printhello();

    cout << "This is main:" << endl;
    cout << "The factorial of 5 is: " << factorial(5) << endl;
    return 0;
}

调用两个函数

printhello.cpp内容

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

using namespace std;

void printhello()
{
    int i;
    cout << "Hello World!" << endl;
}

定义了一个函数,输出hello

factorial.cpp内容

#include"functionals.h"

int factorial(int n)
{
    if(n == 0 || n == 1){
        return 1;
    }
    else{
        return n * factorial(n - 1);
    }
}

定义了一个函数,用于计算阶乘

functions.h内容

#ifndef _FUNCTIONALS_H_
#define _FUNCITIONALS_H_
void printhello();
int factorial(int n);
#endif

在这个文件里写了函数的声明

首先是可以在命令行直接用g++编译:

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

Hello World!

This is main:

The factorial of 5 is: 120

但如果源文件很多,这样编译要花费很多时间

一个省时间的方式就是我们可以逐个编译,修改了哪个文件就编译哪个文件(只编译不链接),其他文件不编译

g++ .\main.cpp -c
g++ .\factorial.cpp -c
g++ .\printhello.cpp -c

这样生成了三个.o文件,然后用命令g++ *.o -o main链接在一起。

不知道为什么,Windows这样写会报错g++: error: *.o: Invalid argumentg++: error: *.o: Invalid argument,不能用通配符,所以我每个都写出来的g++ .\factorial.o .\printhello.o .\main.o -o main(Windows不能用通配符这种,需要单独写出,Linux可以)

那么这样会带来一个问题,当文件特别多的时候,每次手动去输入这个命令会特别麻烦,所以在命令行输入g++编译的这些命令,完全可以写到一个脚本文件里,这个脚本文件有个固定的格式,叫Makefile,注释用 #。

version 1

## version 1
hello: main.cpp printhello.cpp factorial.cpp
	g++ -o hello main.cpp printhello.cpp factorial.cpp

前面hello表示生产的可执行程序叫hello,冒号后面的文件表示:hello的生成依赖于后面那些文件

g++前面有个tab,不能用空格,表示使用后面这个命令生成上面的hello文件

使用的方法就是在命令行输入make,make命令会自动去找当前目录下Makefile文件,如果名字不是Makefile,可以用命令make -f Makefile

生成后,如果再make一次,会提示:make: 'hello' is up to datemake: “hello”已是最新。)表示hello已经很新了,就是hello比那三个cpp文件都新,是在三个文件后生成的,没必要再生成了,除非对其中一个文件做了修改,那么被修改的文件日期新于hello,这时候再make,它会查规则,发现它所依赖的文件在hello生成后被修改了,就会用第二行命令重新生成。(Windows不会检查,Linux会检查)

缺点:如果文件特别多,每次编译时间很长

version 2

CXX指定编译器

TARGET指定目标

TARGET这个变量依赖于OBJ这些文件,如果OBJ相比TARGET更新的话,那么就会用下面命令

make后,Makefile去读第一个碰到的目标TARGET,就是要生成的目标,因为hello不存在,就要去生成,生成要依赖OBJ文件,而OBJ文件又去找依赖的cpp文件

如果某个文件修改了它只会去编译更改了的cpp文件

# version 2
CXX = g++
TARGET = hello
OBJ = main.o printhello.o factorial.o

$(TARGET): $(OBJ)
	$(CXX) -o $(TARGET) $(OBJ)

main.o: main.cpp
	$(CXX) -c main.cpp

printhello.o: printhello.cpp
	$(CXX) -c printhello.cpp

factorial.o: factorial.cpp
	$(CXX) -c factorial.cpp

version 3

加了一个编译选项CXXFLAGS = -c -Wall(Warning all)就是所有的warning都显示出来

不同的一个地方是加了个$@,其实就是冒号前面的东西,就是$(TARGET)$^是冒号后面的东西,就是$(OBJ)这样又少写了一些变量

刚才每个cpp都写了规则生成.o,这里写了个统一的规则%.cpp就是每个cpp文件,$<是指所依赖的,^往上指是指所有的,<往左指是指第一个,在这里只有一个,所以一样。

clean那两行,有个目标叫clean,要生成的话,不管依赖是什么,删除所有.o文件和目标文件。

当文件夹下有一堆.o文件和目标文件,可以用make clean命令,make命令就回去Makefile中找clean目标,然后执行命令。在很多集成开发环境中有个clean,做的就是这件事。

那为什么要有个隐藏的PHONY呢?就是为了防止有个文件叫clean。因为当恰好有个叫clean的文件时,会产生歧义,文件已经有了,就不会产生这个文件了,会提示已经是最新了。这时候就要用.PHONY: clean.PHONY文件永远不会存在,它依赖clean,clean就会删除所有那些文件。

这个版本更加模块化,后面如果有新的文件,只要在OBJ那行写上即可,例如加上file.o

# version 3
CXX = g++
TARGET = hello
OBJ = main.o printhello.o factorial.o

CXXFLAGS = -c -Wall

$(TARGET): $(OBJ)
	$(CXX) -o $@ $^

%.o: %.cpp
	$(CXX) $(CXXFLAGS) $< -o $@

.PHONY: clean

clean:
	rm -f *.o $(TARGET)

会出现一条警告,因为加了-Wall,可以在CXXFLAGS加一些选项,修改起来很方便

version 4

前面还有个麻烦的,要写文件名,这个版本就不用写了

SRC那行是所有当前目录下cpp都放到SRC变量里,就像ls一样,把所有cpp扩展名的文件,满足这个条件的都放到里面。

做一个path路径的替换,把cpp全换成o,就得到了OBJ列表。

# version 4
CXX = g++
TARGET = hello
SRC = $(wildcard *.cpp)
OBJ = $(patsubst %.cpp, %.o, $(SRC))

CXXFLAGS = -c -Wall

$(TARGET): $(OBJ)
	$(CXX) -o $@ $^

%.o: %.cpp
	$(CXX) $(CXXFLAGS) $< -o $@

.PHONY: clean

clean:
	rm -f *.o $(TARGET)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/152796.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Apache与Nginx虚拟机的三种访问+非简单请求+跨域知识点整理

Apache 在D:\project\web\index.html中写入 <h1>welcome useing apache!</h1>基于ip访问 打开phpstudy_pro\Extensions\Apache2.4.39\conf\extra\httpd-vhosts.conf写入 <VirtualHost 192.168.1.4:80>ServerAdmin 88888888163.com #管理员邮箱DocumentRoo…

【BP靶场portswigger-服务端7】访问控制漏洞和权限提升-11个实验(全)

前言&#xff1a; 介绍&#xff1a; 博主&#xff1a;网络安全领域狂热爱好者&#xff08;承诺在CSDN永久无偿分享文章&#xff09;。 殊荣&#xff1a;CSDN网络安全领域优质创作者&#xff0c;2022年双十一业务安全保卫战-某厂第一名&#xff0c;某厂特邀数字业务安全研究员&…

【手写 Vue2.x 源码】第十五篇 - 生成 ast 语法树 - 构造树形结构

一&#xff0c;前言 上篇&#xff0c;主要介绍了生成 ast 语法树 - 模板解析部分 使用正则对 html 模板进行解析和处理&#xff0c;匹配到模板中的标签和属性 本篇&#xff0c;生成 ast 语法树 - 构造树形结构 二&#xff0c;构建树形结构 1&#xff0c;需要描述什么 前面…

文本相似度

传统方法 基于TF-IDF、BM25、Jaccord、SimHash、LDA等算法抽取两个文本的词汇、主题等层面的特征&#xff0c;然后使用机器学习模型&#xff08;LR, xgboost&#xff09;训练分类模型优点&#xff1a;可解释性较好缺点&#xff1a;依赖人工寻找特征&#xff0c;泛化能力一般&a…

linux有用技巧:使用ntfs-3g挂载ntfs设备

1.几种文件系统的比较 (1)在linux系统中支持以下文件系统&#xff1a; Ext2 第二扩展文件系统&#xff08;简称 ext2&#xff09;很多年前就已经成为 GNU/Linux 默认的文件系统了。ext2 取代了扩展文件系统(这是 “第二代” 的前身)。它纠正了它前身的一些错误并突破了…

【工具篇】41 # 常用可视化工具集整理(完结)

说明 【跟月影学可视化】学习笔记。 可视化场景主体需求 主体需求示例绘制基本图形根据数据绘制一些二维、三维的几何图形&#xff0c;它们不一定是完整的图表&#xff0c;通常是具有灵活性和视觉冲击力的小图形&#xff0c;例如粒子效果绘制基础图表通常是指绘制常见的饼图…

让开发人员偷懒的正则表达式

正则表达式是一种基于特殊模式符号系统的文本处理系统。简而言之&#xff0c;它为程序员提供了轻松处理和验证字符串的能力。它代表了DRY&#xff08;Dont Repeat Yourself&#xff09;原则的实现&#xff0c;在几乎所有支持的语言中&#xff0c;正则表达式模式根本不会改变形式…

【信管7.2】质量保证与质量控制

质量保证与质量控制项目质量管理的两个核心过程就是实施质量保证和控制质量。关于它们两个的区别我们在上一课已经讲了&#xff0c;实施质量保证其实保证的是过程&#xff0c;就是我们的开发过程是不是遵循了质量计划&#xff0c;也就是说&#xff0c;这是保证过程有质量的一个…

视频录制软件有哪些?4款录制视频软件,免费下载

对于不了解录屏的用户&#xff0c;肯定会有这些视频是如何制作出来的疑惑&#xff1f;其实录制视频一件很容易的事情&#xff0c;只需要找到一个可以在录视频的软件就可以了。哪有什么录制视频软件可以录制的呢&#xff1f;下面小编给大家分享4款就可以录制视频的软件&#xff…

ORB-SLAM3算法和代码学习—跟踪恒速运动模型TrackWithMotionModel()

0总述 跟踪运动模型核心思想&#xff1a;假设在极短时间内&#xff0c;相机的运动相同。设相邻时刻的三帧图像分别为k-2帧&#xff0c;k-1帧&#xff0c;k帧&#xff0c;则认为k-2帧到k-1帧相机的运动T_delta1和k-1帧到k帧相机的运动T_delta2相等&#xff0c;如下图所示。当相…

K8S概述及用途

K8S概述 1.K8S说明 K8S(Kubernetes) 是一个可移植的、可扩展的开源平台&#xff0c;用于管理容器化的工作负载和服务&#xff0c;可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态系统。Kubernetes 的服务、支持和工具广泛可用。 Kubernetes 这个名字源…

海量数据存储面临的问题

海量数据存储面临的问题海量数据存储面临的问题成本高性能低可扩展性差如何实现分布式文件存储如何支撑高效率的计算分析如何解决海量数据存储的问题如何解决海量数据文件查询便捷问题如何解决大文件传输效率慢的问题如何解决硬件故障数据丢失问题如何解决用户查询视角统一规整…

pyhon把程序打包为whl

首先需要一个库&#xff1a;setuptools如果是conda环境的话&#xff0c;这个包是自带的&#xff0c;不需要另外安装。首先把需要打包的py文件放在一个文件夹内&#xff08;我的文件夹名为coordTrans&#xff0c;记住这个名字&#xff0c;后面要用&#xff09;。同时&#xff0c…

dll修复工具下载,dll修复工具注意事项

Dll文件的缺失相信很多人都遇见过吧&#xff0c;只要缺失了一个这样的dll文件&#xff0c;我们的游戏或者软件程序就启动不了了&#xff0c;所以我们就需要去修复它&#xff0c;目前修复有几种方法&#xff0c;最简单的&#xff0c;最适合电脑小白的&#xff0c;那就是dll修复工…

Vue3——第四章(响应式基础:reactive、ref)

一、用reactive()声明响应式状态 我们可以使用 reactive() 函数创建一个响应式对象或数组&#xff1a; 响应式对象其实是 JavaScript Proxy&#xff0c;其行为表现与一般对象相似。不同之处在于 Vue 能够跟踪对响应式对象属性的访问与更改操作。 要在组件模板中使用响应式状…

java后端第六阶段:SpringMVC

1、Spring IoC&#xff08;Inversion of Controller&#xff09;控制反转 使用对象时&#xff0c;由主动new产生对象转换为由外部提供对象&#xff0c;此过程中对象中创建控制权由程序转移到外部&#xff0c;此思想称为控制反转 Spring技术对IoC思想进行了实现 Spring提供了一…

第四十九讲:神州路由器IPv6 OSPFv3和RIPng路由的配置

神州路由器支持IPv6的内部网关路由协议常用的有OPSFv3和RIPng。 实验拓扑图如下所示 配置要求&#xff1a;在两台路由器上启用IPv6 routing&#xff0c; 在接口上配子ipv6协议后&#xff0c;通过配置RIPng和OSPFv3相关命令&#xff0c;观察学习到的路由。 配置步骤&#xff1…

产品试用记录

某产品试用记录 还可以选屏哦

【PWA学习】3. 让你的 WebApp 离线可用

引言 PWA 其中一个令人着迷的能力就是离线(offline)可用 即使在离线状态下&#xff0c;依然可以访问的 PWA离线只是它的一种功能表现而已&#xff0c;具体说来&#xff0c;它可以&#xff1a; 让我们的Web App在无网(offline)情况下可以访问&#xff0c;甚至使用部分功能&#…

Redis哨兵模式搭建

以下配置机器部署ip为 a、b、c&#xff0c;其中a为master节点 需提前创建 /app/user/oms/redis/data 目录 1.1上传 redis-5.0.5.zip 到对应目录&#xff0c;解压 unzip redis-5.0.5.zip # 生成 redis-5.0.5 目录 1.2 修改配置文件 maxclients 10000 #20000 &#xff0…