Linux工具使用指南:从apt管理、gcc编译到makefile构建与gdb调试

文章目录

  • 前言
    • 🍭一、Linux软件管理包apt(Ubuntu)
      • [🍬1.1 什么是一软件包?](#🍬1.1 什么是一软件包?)
      • [🍬1.2 关于rzsz](#🍬1.2 关于rzsz)
      • [🍬1.3 查看软件包](#🍬1.3 查看软件包)
      • [🍬1.4 如何安装软件](#🍬1.4 如何安装软件)
      • [🍬1.5 如何卸载软件](#🍬1.5 如何卸载软件)
    • 🍭二、Linux编译器-`gcc/g++`使用
      • [🍫2.1 安装 `gcc/g++`](#🍫2.1 安装 gcc/g++)
      • [🍫2.2 基本用法](#🍫2.2 基本用法)
      • [🍫2.3 常用选项](#🍫2.3 常用选项)
      • [🍫2.4 多文件编译](#🍫2.4 多文件编译)
      • [🍫2.5 生成目标文件和链接](#🍫2.5 生成目标文件和链接)
      • [🍫2.6 动态链接和静态链接](#🍫2.6 动态链接和静态链接)
      • [🍫2.7 调试](#🍫2.7 调试)
      • [🍫2.8 示例:编译 C/C++ 程序的完整流程](#🍫2.8 示例:编译 C/C++ 程序的完整流程)
    • 🍭三、项目自动化构建工具`make/makefile`
      • [🧁3.1 什么是 `make` 和 `Makefile`?](#🧁3.1 什么是 makeMakefile?)
      • [🧁3.2 Makefile 的基本语法](#🧁3.2 Makefile 的基本语法)
      • [🧁3.3 使用 `make`](#🧁3.3 使用 make)
      • [🧁3.4 Makefile 中的变量](#🧁3.4 Makefile 中的变量)
      • [🧁3.5 Makefile 中的特殊符号和自动变量](#🧁3.5 Makefile 中的特殊符号和自动变量)
      • [🧁3.6 Makefile 中的内置函数](#🧁3.6 Makefile 中的内置函数)
      • [🧁3.7 Makefile 的伪目标](#🧁3.7 Makefile 的伪目标)
    • 🍭四、Linux调试器-`gdb`使用
      • [🍮4.1 常用主要功能](#🍮4.1 常用主要功能)
      • [🍮4.2 常用指令](#🍮4.2 常用指令)
      • [🍮4.3 常用 GDB 指令表](#🍮4.3 常用 GDB 指令表)
      • [🍮4.4 指令总结与使用场景](#🍮4.4 指令总结与使用场景)
  • 结语

前言

Linux 是当今计算机领域最重要的操作系统之一,其强大的命令行工具和丰富的生态系统为开发者提供了极大的灵活性和效率。然而,对于新手和部分用户而言,如何使用这些工具高效管理软件、编译代码、自动化构建和调试程序仍然是一项挑战。这篇文章旨在为读者提供一站式的 Linux 工具指南,从软件包管理 (apt) 到编译器 (gcc/g++)、自动化构建工具 (make),再到调试器 (gdb),我们将以清晰、系统化的方式为您逐步解析这些工具的功能和使用方法。无论您是初学者还是有经验的开发者,这篇文章都能为您的 Linux 技能提升提供帮助。


🍭一、Linux软件管理包apt(Ubuntu)

🍬1.1 什么是一软件包?

软件包(Package)是一个包含软件程序及其相关文件的归档单元,用于在操作系统中安装、配置、更新和卸载软件。它通常包括程序的二进制文件、库文件、配置文件以及元数据(如依赖关系和版本信息)。

在 Linux 系统中,软件包是操作系统和用户软件的基础。通过软件包管理器,用户可以方便地管理和维护系统中的软件。

apt(Advanced Package Tool)是 Ubuntu 和其他基于 Debian 的 Linux 发行版中用于管理软件包的工具。它是一个功能强大的命令行工具,用于安装、更新、搜索和删除软件包。


🍬1.2 关于rzsz

rzsz 是 Linux 系统中的两个命令,用于通过 zmodem 协议在本地计算机和远程服务器之间上传和下载文件。它们通常用于终端工具,如 xterm 或基于 SSH 的终端模拟器(如 SecureCRTxshell)。

  • rz (receive zmodem): 用于从本地上传文件到远程服务器。
  • sz (send zmodem): 用于从远程服务器下载文件到本地。

安装 rzsz

在大多数 Linux 系统中可以通过以下命令安装:

  • Debian/Ubuntu:

    bash 复制代码
    sudo apt install lrzsz

使用 rz 时,会弹出文件选择框选择上传的文件;使用 sz 时,会直接下载文件。


🍬1.3 查看软件包

在 Linux 系统中,您可以通过以下方法查看已安装的软件包或查找特定的软件包:

Ubuntu/Debian:

  • 查看已安装的软件包:

    bash 复制代码
    dpkg -l
  • 搜索特定的软件包:

    bash 复制代码
    dpkg -l | grep <package_name>

APT(适用于 Ubuntu/Debian):

bash 复制代码
apt list --installed

🍬1.4 如何安装软件

使用 apt 安装:

bash 复制代码
sudo apt install <package_name>

🍬1.5 如何卸载软件

  • 使用 apt 卸载:

    bash 复制代码
    sudo apt remove <package_name>

清理残留文件

  • 在 Ubuntu/Debian 中,可以使用以下命令清理配置文件:

    bash 复制代码
    sudo apt purge <package_name>
    sudo apt autoremove

删除源码安装的软件

  • 如果是通过源码安装,可以进入安装目录并运行:

    bash 复制代码
    sudo make uninstall
  • 如果没有卸载脚本,需要手动删除安装文件。

🍭二、Linux编译器-gcc/g++使用

在 Linux 系统中,gccg++ 是常用的编译器,用于编译 C 和 C++ 程序。以下是 gccg++ 的使用方法和一些常见选项的说明:


🍫2.1 安装 gcc/g++

如果系统中没有安装 gcc/g++,可以通过包管理器进行安装:

  • Ubuntu/Debian 系列系统上:

    bash 复制代码
    sudo apt update
    sudo apt install build-essential

    build-essential 包会安装 gcc, g++ 和一些基本的构建工具。


🍫2.2 基本用法

编译 C 程序 (gcc)

  1. 编译一个简单的 C 程序:

    bash 复制代码
    gcc -o output_file source.c

    说明:

    • -o output_file:指定输出的可执行文件名。
    • source.c:C 源文件。
  2. 示例:

    bash 复制代码
    gcc -o hello hello.c
    ./hello

编译 C++ 程序 (g++)

  1. 编译一个简单的 C++ 程序:

    bash 复制代码
    g++ -o output_file source.cpp
  2. 示例:

    bash 复制代码
    g++ -o hello_cpp hello.cpp
    ./hello_cpp

🍫2.3 常用选项

选项 功能
-o 指定输出文件名。
-c 只编译,不链接生成目标文件(.o 文件)。
-g 生成调试信息,用于调试器(如 gdb)。
-Wall 启用所有常见的编译警告,帮助发现潜在错误。
-O-O2 优化代码,-O2 表示更高级的优化(还有 -O0 关闭优化,-O3 开启更激进的优化)。
-I 指定包含文件目录,例如 -I/usr/include/custom
-L 指定链接库路径,例如 -L/usr/lib
-l 指定链接的库,例如 -lm 表示链接数学库 libm.so
-std 指定标准版本,例如 -std=c99(C99 标准)或 -std=c++11(C++11 标准)。
-D 定义宏,例如 -DDEBUG 在代码中定义 #define DEBUG

🍫2.4 多文件编译

在项目中通常会有多个源文件,需要一起编译:

bash 复制代码
gcc -o output_file file1.c file2.c

示例:

gcc -o program main.c utils.c

对于 C++ 项目:

bash 复制代码
g++ -o output_file file1.cpp file2.cpp

🍫2.5 生成目标文件和链接

步骤 1:生成目标文件(.o 文件)

bash 复制代码
gcc -c file1.c
gcc -c file2.c

会生成 file1.ofile2.o

步骤 2:链接目标文件

bash 复制代码
gcc -o output_file file1.o file2.o

同理,对于 C++ 文件:

bash 复制代码
g++ -c file1.cpp
g++ -c file2.cpp
g++ -o output_file file1.o file2.o

🍫2.6 动态链接和静态链接

动态链接(默认)

动态链接会依赖动态库(如 .so 文件)。

bash 复制代码
gcc -o output_file source.c -lm

示例:链接数学库 libm.so

静态链接

静态链接会将所需的库文件直接嵌入到生成的可执行文件中。

bash 复制代码
gcc -o output_file source.c -static -lm

-static 表示使用静态链接。


🍫2.7 调试

编译时添加 -g 选项,生成包含调试信息的二进制文件:

bash 复制代码
gcc -g -o debug_program program.c

使用 gdb 调试:

bash 复制代码
gdb ./debug_program

🍫2.8 示例:编译 C/C++ 程序的完整流程

C 程序示例

  1. 源文件:main.c

    c 复制代码
    #include <stdio.h>
    
    int main() {
        printf("Hello, World!\n");
        return 0;
    }
  2. 编译和运行:

    bash 复制代码
    gcc -Wall -o hello main.c
    ./hello

C++ 程序示例

  1. 源文件:main.cpp

    cpp 复制代码
    #include <iostream>
    using namespace std;
    
    int main() {
        cout << "Hello, World!" << endl;
        return 0;
    }
  2. 编译和运行:

    bash 复制代码
    g++ -Wall -o hello_cpp main.cpp
    ./hello_cpp

🍭三、项目自动化构建工具make/makefile

🧁3.1 什么是 makeMakefile

  • make 是一个工具,用于根据指定的规则,自动化执行一系列命令(如编译代码)。
  • Makefile 是一个文本文件,定义了构建项目的规则、依赖关系和命令。

核心思想:如果某个目标文件依赖的源文件发生了变化,就重新生成目标文件。


🧁3.2 Makefile 的基本语法

基本结构

makefile 复制代码
目标: 依赖
    命令
  • 目标(target):最终生成的文件(如可执行文件)。
  • 依赖(dependencies):目标文件所依赖的源文件或其他目标。
  • 命令(commands) :为了生成目标而需要执行的命令(必须以 Tab 开头)。

示例

makefile 复制代码
hello: hello.o utils.o
    gcc -o hello hello.o utils.o

hello.o: hello.c
    gcc -c hello.c

utils.o: utils.c
    gcc -c utils.c

clean:
    rm -f *.o hello

说明

  1. hello 是最终的可执行文件,依赖于 hello.outils.o
  2. 如果 hello.cutils.c 修改了,则只会重新编译对应的 .o 文件。
  3. clean 是一个伪目标,用于清理构建产生的文件(没有依赖和目标文件)。

🧁3.3 使用 make

假设上面的 Makefile 保存为 Makefile 文件:

执行构建

bash 复制代码
make
  • 默认会执行第一个目标(hello)。
  • 如果源文件没有变化,make 会输出 make: 'hello' is up to date.

执行清理

bash 复制代码
make clean
  • 执行 clean 目标的命令,删除 .o 文件和可执行文件。

🧁3.4 Makefile 中的变量

为了减少重复,Makefile 支持变量定义和引用。

定义变量

makefile 复制代码
CC = gcc
CFLAGS = -Wall -g
TARGET = hello
OBJS = hello.o utils.o

使用变量

makefile 复制代码
$(变量名)

改进后的 Makefile

makefile 复制代码
CC = gcc
CFLAGS = -Wall -g
TARGET = hello
OBJS = hello.o utils.o

$(TARGET): $(OBJS)
    $(CC) -o $(TARGET) $(OBJS)

%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

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

说明

  • $<:表示第一个依赖项(如 hello.c)。
  • $@:表示当前目标(如 hello.o)。
  • %.o: %.c:通配规则,表示所有 .c 文件生成对应的 .o 文件。

🧁3.5 Makefile 中的特殊符号和自动变量

符号/变量 作用
$@ 当前目标的名字。
$^ 所有依赖项的名字(去重)。
$< 第一个依赖项的名字。
$? 所有比目标文件更新的依赖项。
$(VAR) 引用变量 VAR

🧁3.6 Makefile 中的内置函数

常用函数

函数 作用
$(wildcard *.c) 获取当前目录下所有 .c 文件。
$(patsubst %.c, %.o, $(SRC)) 将变量 SRC 中的所有 .c 替换为 .o
$(shell 命令) 执行 shell 命令并将输出存储到变量中。

示例

makefile 复制代码
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))

$(TARGET): $(OBJS)
    $(CC) -o $@ $^

clean:
    rm -f $(OBJS) $(TARGET)

🧁3.7 Makefile 的伪目标

伪目标是指不生成文件的目标,用于执行一些任务(如清理)。

定义伪目标

makefile 复制代码
.PHONY: clean all

伪目标的作用

  • 避免和实际文件重名。
  • 强制执行目标。

🍭四、Linux调试器-gdb使用

GDB(GNU Debugger)是GNU项目开发的一款功能强大的调试工具,用于调试C、C++、Fortran等编程语言编写的程序。它是Linux系统下最常用的调试工具之一,可以帮助开发者定位程序中的错误和问题,从而提高代码的质量和开发效率。

🍮4.1 常用主要功能

  1. 运行程序
    • 可以按用户指定的方式启动程序,设置参数和环境变量。
  2. 设置断点
    • 用户可以在程序的特定位置(如函数或行号)设置断点,程序运行到断点时会暂停,方便检查当前状态。
  3. 单步执行
    • 支持逐行或逐指令执行代码,便于分析程序逻辑和排查问题。
  4. 查看变量值
    • 可以查看和修改内存中变量的值,帮助了解程序的运行状态。

🍮4.2 常用指令

我将以下面代码为例,为大家演示gdb的常用方法,以下是mycode的主要内容,并且以及生成了一个debug模式的可执行程序mycode

cpp 复制代码
#include <iostream> 

int AddTop(int top)
{
    int res = 0;
    for (int i = 1; i <= top; i++) 
    {
        res += i;
    }

    return res;
}

int main()
{
    std::cout << "Debug begin" << std::endl; 

    int top = 100;
    int sum = AddTop(top);

    std::cout << "sum: " << sum << std::endl; 

    std::cout << "Debug end" << std::endl;

    return 0;
}
  • gdb binFile:进入gdb环境,其中binFile是一个可执行程序。
  • l(list):显示binFile的源代码,接着上次的位置往下列,每次10行。
  • l numlist num:其中num是行号,将源代码的第num行在中间位置显示。
  • r(run):运行程序。
  • b(break) 行号:在某一行设置断点。
  • info b(info break 或者 i b):查看断点信息。
  • d(delete) Num:删除一个断点,其中Num是断点编号。

注意:如果在调试过程中退出,那么再次进入调试环境,上一次的调试信息会丢失,即之前设置的断点都没了。

此时设置完断点之后我们再次运行程序(使用 r命令 ),它就会直接运行至第一个断点处并且停止运行。

    • n(next):逐过程,单条执行,当有函数调用时,不会进入函数内部。

我们接着上面的代码走。

  • s(step):逐语句,进入函数调用。

  • p 变量:打印变量的值。

    注意 :通过p来打印变量的值,不会根据我们调试的进行而实时变化。

  • display 变量名:跟踪查看一个变量,每次停下来都显示它的值,类似于Visual Studio中的监视窗口。

    可以随着代码的运行而显示变量的变化。

  • undisplay num:取消对先前设置的那些变量的追踪,其中num是先前设置的跟踪变量所对应的编号。

    此时有一个问题,假如我进入循环之后查看了几轮发现代码没有问题,想快速结束这个循环怎么办?

  • until x:跳至x行,可以让我们快速的运行代码块。

  • finish:执行完当前函数返回,然后停下来等待命令。

    注意finish指令可以快速的帮我们查看问题是不是出在当前函数中。

  • c(continue):从当前断点直接运行到下一个断点处。

  • disable Num:禁用断点,其中Num是断点编号。

    禁用完1,2两个断点之后,此时再次运行,程序直接跳转到了第三个断点处

  • enable Num:启用断点,其中Num是断点编号。

🍮4.3 常用 GDB 指令表

命令 缩写 功能描述 示例
运行与调试控制
run r 启动程序并运行 run arg1 arg2
start 从程序入口运行并暂停在main start
continue c 恢复程序运行直到下一个断点 continue
step s 单步执行(进入函数调用) step
next n 单步执行(跳过函数调用) next
finish 运行到当前函数返回 finish
until 运行到指定行或跳出循环 until 45
quit q 退出 GDB quit
断点操作
break b 设置断点(支持行号、函数、文件等) break main break 25
tbreak 设置临时断点,仅触发一次 tbreak my_function
info breakpoints i b 查看所有断点信息 info breakpoints
delete d 删除指定断点 delete 1
clear 删除某位置的断点(行号或函数) clear 30
enable 启用指定断点 enable 2
disable 禁用指定断点 disable 2
condition 为断点设置条件 condition 1 x > 5
变量与表达式
print p 打印变量值或表达式结果 print x print x + y
display 每次暂停时自动显示指定变量 display var
undisplay 停止显示指定编号的变量 undisplay 1
set var 修改变量值 set var x = 10
whatis 显示变量类型 whatis var
调用栈与线程
backtrace bt 显示调用栈 backtrace
frame f 切换到指定栈帧 frame 2
info threads 显示所有线程 info threads
thread 切换到指定线程 thread 3
内存操作
x/<n><fmt> 查看内存内容(支持格式化输出) x/4xw 0x123456
x/s 查看内存地址的字符串 x/s 0x7fff1234
info registers 查看所有寄存器内容 info registers
set 修改内存地址内容 set *(int *)0x123456 = 42
源码查看
list l 查看当前代码上下文 list
list <line> l 查看指定行代码 list 50
list <function> l 查看指定函数的源码 list my_function
文件与进程
file 加载可执行文件 file ./a.out
attach 附加到运行中的进程 attach 1234
detach 分离调试器和程序 detach

🍮4.4 指令总结与使用场景

程序控制

  • 常用的运行控制指令包括runcontinuestepnext
  • 当程序异常终止时,可以结合backtrace查看调用栈,分析错误。

断点管理

  • 通过break设置断点,info breakpoints查看断点状态。
  • 如果调试某段特定代码,可使用condition设置条件断点。

变量与内存调试

  • 使用print查看变量值,set var修改变量,快速验证修复效果。
  • 若需深入分析内存,结合x命令和格式化选项查看内存内容。

多线程调试

  • 对多线程程序,先用info threads查看线程列表,再切换到目标线程进行分析。

高级场景

  • 使用attach调试运行中的程序或core文件分析崩溃问题。

结语

Linux 工具链的丰富性和灵活性,为开发者提供了从项目开发到部署的全套解决方案。本篇文章介绍了 Linux 中的核心工具,从软件管理到编译、调试以及自动化构建,希望为您在开发工作中提供实用的参考。在掌握这些工具之后,您将能以更高效的方式处理日常开发任务,同时通过进一步挖掘这些工具的高级功能,解锁更多的 Linux 技能潜力。如果您遇到问题或有新的需求,欢迎继续探索并学习更多 Linux 相关知识,迈向更高的技术水平!

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连 支持一下,17的主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是17前进的动力!

相关推荐
老刘莱国瑞4 分钟前
STM32 与 AS608 指纹模块的调试与应用
python·物联网·阿里云
湫ccc7 分钟前
《Opencv》基础操作详解(3)
人工智能·opencv·计算机视觉
Linux运维技术栈11 分钟前
Ansible(自动化运维)环境搭建及ansible-vault加密配置
运维·自动化·ansible
乔巴不是狸猫15 分钟前
第11周作业
linux
Jack_pirate16 分钟前
深度学习中的特征到底是什么?
人工智能·深度学习
黑胡子大叔的小屋17 分钟前
基于springboot的海洋知识服务平台的设计与实现
java·spring boot·毕业设计
ThisIsClark20 分钟前
【后端面试总结】深入解析进程和线程的区别
java·jvm·面试
微凉的衣柜30 分钟前
微软在AI时代的战略布局和挑战
人工智能·深度学习·microsoft
GocNeverGiveUp43 分钟前
机器学习1-简单神经网络
人工智能·机器学习
Schwertlilien1 小时前
图像处理-Ch2-空间域的图像增强
人工智能