【Linux】Linux上代码的编译与调试

本文详细介绍了在Linux上使用gcc/g++编译器进行C++程序的预处理、编译、汇编和链接过程,包括函数库的分类、gcc选项以及Linux项目自动化构建工具Makefile的应用。还展示了如何利用这些知识实现一个简单的进度条程序。
摘要由CSDN通过智能技术生成

目录

Linux上常用的编译器gcc\g++

如何使用gcc/g++

编译过程:

如何使用gcc编译?

进行预处理

进行编译

进行汇编

进行链接

函数库

函数库的分类

gcc选项

Linux调试器-gdb的使用

gdb的常用参数

Linux项目自动化构建工具make/Makefile

原理

利用上述知识做一个简单的进度条程序

Makefile

进度条函数的实现(.c文件)

进度条的头文件

进度条的主函数


Linux上常用的编译器gcc\g++

  • GCC(GNU Compiler Collection):GCC 是一个功能强大且广泛使用的编译器套件,在 Linux 系统中被广泛采用。它支持多种编程语言,如 C、C++、Objective-C、Fortran 等,是许多开源项目和软件的首选编译工具。

  • G++:G++ 实际上是 GCC 的 C++ 编译器版本,专门用于编译 C++ 代码。它提供了对 C++ 标准的良好支持,并且与 GCC 一起安装在许多 Linux 发行版中。

如何使用gcc/g++

  • 在了解如何使用gcc和g++编译代码之前,我们先了解一下编译的过程

编译过程:

  1. 预处理阶段:预处理阶段的主要任务是宏定义、文件包含、条件编译、去除注释(展开头文件、去注释、条件编译、宏替换)等。这时候会生成以.i为后缀的文件

  2. 编译阶段(生成汇编代码):这个阶段首先检查代码的规范性、是否有语法错误等,确定无误后将代码翻译为汇编语言。这时会将.i文件转换成.s文件

  3. 汇编(将汇编代码转换成机器码):将编译生成的.s文件转成目标文件。

  4. 链接:编译成功之后就进入链接阶段,这时会生成可执行文件或者库文件。

如何使用gcc编译?

  • 通用格式

gcc 【选项】 要编译的文件 【选项】 目标文件
  • 未编译前的状态,此时只有一个我们写好的.c文件

进行预处理

  • 我们使用下面的命令对文件进行预处理,其中选项【-E】的作用是让gcc在预处理结束后停止编译过程,【-o】是指目标文件,【.i】文件为已经预处理过的文件

gcc -E test.c -o test.i

进行编译

  • 我们使用下面的命令对文件进行编译,其中选项【-S】的作用是让gcc在编译结束后停止汇编过程,【-o】是指目标文件,【.s】文件为已经预处理过的文件

gcc -S test.i -o test.s

进行汇编

  • 我们使用下面的命令对文件进行汇编

gcc -c test.s -o test.o

进行链接

  • 我们使用下面的命令对文件进行链接

gcc test.o -o test

  • 如此我们便完成了程序的编译,文件后缀的变更顺序为iso(和摄影中的感光的一样)

函数库
  • 不知道大家有没有发现一个问题,我们的c程序中可并没有printf的函数实现,头文件stdio中也只有它的声明,并没有它的实现,它是在哪里实现的呢?

  • 系统把这些函数实现都放在libc.so.6的库文件中去了,在没有特别指定的情况下gcc回去系统默认的搜索路径/usr/lib下进行查找,这便是链接。

  • 通过ldd命令查看可执行程序所以来的库

函数库的分类
  • 函数库分为两类:静态库和动态库。

  • 静态库是指在编译链接时,把库文件的代码全部加入到可执行文件当中去,这样做的结果就是生成的文件会比较大,但运行时也不再需要库文件了,静态库一般后缀为.a

  • 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序资兴市有运行时链接文件加载库,这样可以节省系统开销。动态库一般后缀为.so。gcc在编译时默认使用动态库。

gcc选项

  • 【-E】:只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面

  • 【-S】:编译到汇编语言而不进行汇编和连接操作

  • 【-c】:编译到目标代码

  • 【-o】:文件输出到文件

  • 【-static】:此选项对生成的文件采用静态链接

  • 【-g】:生成调试信息。GNU调试器可利用该信息

  • 【-shared】:此选项将尽量使用动态库,生成文件较小,但要保证有动态库

  • 【-O0/-O1/-O2/-O3】:编译器的四个优化选项,-O0表示没有优化,默认优化级别是O1,O3是级别最高的优化

  • 【-w】:不生成任何警告信息

  • 【Wall】:生成所有警告信息

Linux调试器-gdb的使用

  • 使用gcc/g++编译出来的程序默认是release版本

  • 想对一个文件使用gdb进行调试的话,首先要保证该文件是可以被调试的(编译的时候要带上【-g】)

gdb的常用参数

Linux项目自动化构建工具make/Makefile

  • Makefile的书写格式

  • target也就是一个目标文件,可以是Object File,也可以是执行文件。还可以是一个标签(Label),对于标签这种特性,在后续的“伪目标”章节中会有叙述。prerequisites就是,要生成那个target所需要的文件或是目标。command也就是make需要执行的命令。(任意的Shell命令)这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容。

  • 一个工程中的源文件不计其数,按照类型、功能、模块分别放在若干个目录中,按照上文所讲的方法,无疑是对程序员的酷刑。

  • makefile定义了一系列规则来指定,那些文件需要被先编译,那些文件现需要后编译,甚至与进行更复杂的功能操作

  • makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大地提高了软件开发效率

  • make是一个命令工,makefile是一个文件,两者搭配使用,完成项目的自动化构建

原理

  1. make会在当前目录下找名字叫“Makefile”或“makefile”的文件。

  2. 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“hello”这个文件,并把这个文件作为最终的目标文件。

  3. 如果hello文件不存在,或是hello所依赖的后面的hello.o文件的文件修改时间要比hello这个文件新(可以用 touch 测试),那么,他就会执行后面所定义的命令来生成hello这个文件。

  4. 如果hello所依赖的hello.o文件不存在,那么make会在当前文件中找目标为hello.o文件的依赖性,如果找到则再根据那一个规则生成hello.o文件。(这有点像一个堆栈的过程)

  5. 当然,你的C文件和H文件是存在的啦,于是make会生成 hello.o 文件,然后再用 hello.o 文件声明make的终极任务,也就是执行文件hello了。

  6. 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。

  7. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。

  8. make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。

利用上述知识做一个简单的进度条程序

Makefile

progress_v2: progress_v2.c test_v2.c
 gcc $^ -o $@
.PHONY:clean
clean:
 rm -f progress_v2

进度条函数的实现(.c文件)

#include"progress_v2.h"

void download()
{
  int haveDownload  = 0;
  while(haveDownload < ALLBYTE)
  {
    progress_v2((haveDownload*100.0)/ALLBYTE);
    usleep(95000);
    haveDownload += PERDOWNLOAD;
  }
  progress_v2(100);
  printf("\n");
}

void progress_v2 (double rate)
{
  
 static  char arr1[4]="/-\\";//模拟进度条运行
 static  char arr[101] = {0};//作为进度条显示数组
 arr[(int)rate] = '#';
 fflush(stdout);
 printf("[%-101s][%.1lf%%][%c]\r",arr,rate,arr1[(int)rate%4]);
}

进度条的头文件

#include<stdio.h>
#include<unistd.h>

#define ALLBYTE 1000
#define PERDOWNLOAD 7
void download();

void progress_v2(double rate);

进度条的主函数

#include"progress_v2.h"

int main()
{
  download();
  return 0;
}
  • 27
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值