Linux常见工具使用方法

🎬 个人主页Vect个人主页

🎬 GitHubVect的代码仓库
🔥 个人专栏 : 《数据结构与算法》《C++学习之旅》《Linux

⛺️Per aspera ad astra.



文章目录

Makefile

0. 简单代码演示

cpp 复制代码
// add.h
#pragma once 

int add(int a, int b);
cpp 复制代码
// add.cpp

#include "add.h"

int add(int a, int b) { return a + b;}
cpp 复制代码
// main.cpp

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

int main(){
    std::cout<<add(1,2)<<std::endl;
    return 0;
}

1. Makefile结构及规则

这里先提前有个认知:

  • Makefile是文件
  • make是指令

先来看代码,然后解读:

bash 复制代码
# 变量定义部分
SRC = main.cpp add.cpp 
OBJ = $(SRC:.cpp=.o)
BIN = myapp

# 默认目标
$(BIN): $(OBJ)
	g++ -o $@ $^
	
# 编译目标
%.o: %.cpp
	g++ -c $< -o $@
	
# 清理目标
.PHONY: clean
clean:
	rm -f $(OBJ) $(BIN)
	

变量定义部分

SRC = main.cpp add.cpp

  • 作用:定义源文件变量,包含所有.cpp的源文件
  • 解释:SRC是一个包含需要编译的源文件的列表

OBJ = $(SRC:.cpp=.o)

  • 作用:通过模式替换,将SRC中的.cpp全部转换成.o文件
  • 解释:$(VAR)用来引用一个变量的值,$(SRC:.cpp=.o)利用替换模式 得到OBJ = main.o add.o

BIN = myapp

  • 作用:定义最终生成的目标文件名(最后的可执行文件)

默认目标部分

$(BIN):$(OBJ)

  • 作用:表示目标$(BIN) 依赖于$(OBJ)中的main.o add.o

g++ -o $@ $^

  • 作用:使用g++.o文件链接成最终可执行文件myapp
  • 解释:
    • $@:代表当前规则中的目标文件,这里是$(BIN)
    • $^:代表所有的依赖文件(去除重复的),这里是$(OBJ)

编译目标部分

%.o: %.cpp

  • 作用:表示一条通用规则,告诉make如何将.cpp文件编译成.o文件
  • 解释:%是通配符,代表一个任意的字符序列,这里表示会匹配所有的.cpp文件,将它们全部编译为对应的.o文件

g++ -c &< -o $@

  • 作用:使用g++.cpp文件编译成.o文件
  • 解释:
    • $<:代表当前规则中的第一个依赖文件,在这里就是 .cpp 文件
    • $@:表示当前规则中的目标文件,在这里是 .o 文件

清理目标部分

.PHONY: clean

  • 作用:声明clean是一个伪目标,而不是文件名
  • 解释:make 会认为 clean 是一个任务,而不是文件,因此即使当前目录下存在名为 clean 的文件,make 也会执行 clean 规则的命令

clean: rm -f $(OBJ) $(BIN)

  • 作用:clean 目标的命令部分,删除所有生成的目标文件和最终的可执行文件。

2. 过程推导

目标文件.o和依赖关系

  • main.o依赖于main.cpp
  • add.o依赖于add.cpp

在Makefile中,$OBJ 是要生成的目标文件,它的生成依赖于.cpp文件

规则推导过程

make会从默认目标 myapp开始,通过依赖关系逐步推导出需要做的工作

  1. make看到myapp

    myapp的形成依赖于main.oadd.omake会从main.oadd.o开始推导

  2. 生成main.o

    main.o的生成又依赖于main.cpp,所以make会执行:g++ -c main.cpp -o main.o

  3. 生成add.o

    同理add.o的生成依赖于add.cpp,所以make会执行: g++ -c add.cpp -o add.o

  4. 链接成myapp

    当生成了main.oadd.omake会执行:g++ -o mayapp main.o add.o

推导是一个出栈入栈的过程

  • 出栈: make开始时看到myapp,出栈myapp,处理它的依赖main.oadd.o
  • **入栈:**当 main.oadd.o 处理完后,它们的目标文件会 入栈 ,然后 make 执行生成 myapp 的命令

我们梳理清楚依赖链:

目标 直接依赖 构建规则
myapp main.o add.o g++ -o myapp main.o add.o
main.o main.cpp g++ -c main.cpp -o main.o
add.o add.cpp g++ -c add.cpp -o add.o
clean 伪目标 rm -f main.o add.o myapp

时间戳

make在做依赖关系推导的时候,会用时间戳来决定哪些目标需要重新构建

时间戳的作用

make会比较每个目标文件和它的依赖文件的时间戳

  • 如果依赖文件比目标文件新,make会重新构建目标文件
  • 如果目标文件存在且没有被更新,make会跳过编译过程
bash 复制代码
[vect@VM-0-11-centos make_file]$ stat main.cpp
  File: 'main.cpp'
  Size: 102       	Blocks: 8          IO Block: 4096   regular file
Device: fd01h/64769d	Inode: 1051720     Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1002/    vect)   Gid: ( 1002/    vect)
Access: 2025-12-14 20:12:03.883557588 +0800
Modify: 2025-12-14 20:12:01.955499062 +0800
Change: 2025-12-14 20:12:01.955499062 +0800
 Birth: -

看一下三种时间:

  • Acesstime:访问时间,文件内容被读取/访问的时间
  • Modifytime:修改时间,文件时间内容被修改的时间(文件大小、内容变化)
  • Changetime:状态改变时间,文件**元数据(属性)**改变的时间(文件属性)

过程演示:

  1. 第一次运行make

    make的行为:

    bash 复制代码
    [vect@VM-0-11-centos make_file]$ make
    g++ -c main.cpp -o main.o
    g++ -c add.cpp -o add.o
    g++ -o myapp main.o add.o

    此时目标文件和可执行文件都生成了,时间戳被记录

  2. 修改源文件并运行make

    假设修改了 add.cpp 文件中的代码,例如:

    cpp 复制代码
    int add(int a, int b) {
        return a * b;  // 修改了加法为乘法
    }

    现在,make会根据文件时间戳决定是否重新编译:

    • main.o时间戳未变化,main.cpp不重新编译
    • add.o文件的时间戳比add.cpp新,make会发现add.o的依赖文件add.cpp发生变化

    运行指令得到:

    bash 复制代码
    [vect@VM-0-11-centos make_file]$ make
    g++ -c add.cpp -o add.o
    g++ -o myapp main.o add.o
  3. 不做任何修改,直接运行make

    bash 复制代码
    [vect@VM-0-11-centos make_file]$ make
    make: `myapp' is up to date.

总结:

  1. 目标文件不存在 :如果目标文件(.o)或依赖文件(.cpp)不存在,make 会强制编译并生成目标文件。

  2. 依赖文件更新 :如果依赖文件的时间戳比目标文件更新,make 会重新编译依赖文件并更新目标文件。

  3. 无更新时跳过编译 :如果目标文件和依赖文件的时间戳都没有变化,make 会跳过编译过程,避免重复工作。

伪目标

伪目标:没有对应文件的目标文件,用来执行命令而不关心文件的存在

伪目标不会检查时间戳,每次执行都会运行相关指令

bash 复制代码
.PHONY: clean

clean:
    rm -f $(OBJ) $(BIN)

.PHONY 告诉 make clean 是伪目标,即使当前目录下有一个 clean 文件,make 也不会认为它是一个文件,而是会执行 rm 命令

gdb和cgdb

相关推荐
晚枫歌F5 小时前
Dpdk介绍
linux·服务器
工程师老罗8 小时前
龙芯2k0300 PMON取消Linux自启动
linux·运维·服务器
千百元8 小时前
centos如何删除恶心定时任务
linux·运维·centos
oMcLin11 小时前
如何在Manjaro Linux上配置并优化Caddy Web服务器,确保高并发流量下的稳定性与安全性?
linux·服务器·前端
济61711 小时前
linux(第七期)--gcc编译软件-- Ubuntu20.04
linux·运维·服务器
corpse201011 小时前
Linux监控软件Monitorix 安装部署
linux·安全
wdfk_prog11 小时前
[Linux]学习笔记系列 -- [fs]super
linux·笔记·学习
姚青&11 小时前
四.文件处理命令-文本编辑
linux
oMcLin11 小时前
如何在 Red Hat Linux 8 上实现 Kubernetes 自定义资源管理器(CRD)扩展,支持微服务架构
linux·架构·kubernetes
济61712 小时前
linux(第十一期)--Makefile 语法简述-- Ubuntu20.04
linux