Linux基础环境开发工具gcc/g++ make/Makefile

news2024/11/15 11:09:21

1.Linux编译器-gcc/g++使用

1. 预处理(进行宏替换)

预处理功能主要包括宏定义,文件包含,条件编译,去注释等。
预处理指令是以#号开头的代码行。
实例: gcc –E hello.c –o hello.i
选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。
选项“-o”是指目标文件,后面是编译好的文件名 “.i”文件为已经过预处理的C原始程序

[wws@hcss-ecs-d531 ~]$ vim hello.c
[wws@hcss-ecs-d531 ~]$ gcc -E hello.c -o hello.i
[wws@hcss-ecs-d531 ~]$ cat hello.i

2.编译(生成汇编)

在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。
用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。
实例: gcc –S hello.i –o hello.s

[wws@hcss-ecs-d531 ~]$ gcc -S hello.i -o hello.s
[wws@hcss-ecs-d531 ~]$ vim hello.s

3.汇编(生成机器可识别代码)

汇编阶段是把编译阶段生成的“.s”文件转成目标文件
在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了
实例: gcc –c hello.s –o hello.o

[wws@hcss-ecs-d531 ~]$ gcc -c hello.s -o hello.o
[wws@hcss-ecs-d531 ~]$ vim hello.o

4.连接(生成可执行文件或库文件)

在成功编译之后,就进入了链接阶段。
实例: gcc hello.o –o hello

生成可执行文件hello

函数库

我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?
最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用.

函数库一般分为静态库和动态库两种。
1.静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了其后缀名一般为“.a”
2.动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,如下所示。 gcchello.o –o hello

gcc默认生成的二进制程序,是动态链接的,这点可以通过 file 命令验证。

gcc -o code_static code.s -static 用static选项链接静态库

yum install -y glibc-static 安装静态库C

yum install -y libstdc++-static  C++静态库

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

makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。

makefile使用

首先先创建两个文件 code.c makefile

-bash-4.2$ ll
total 8
-rw-r--r-- 1 wws wws 81 Aug 19 11:20 code.c
-rw-rw-r-- 1 wws wws 64 Aug 19 11:19 makefile



-bash-4.2$ ll
total 8
-rw-r--r-- 1 wws wws 81 Aug 19 11:20 code.c
-rw-rw-r-- 1 wws wws 64 Aug 19 11:19 makefile
-bash-4.2$ vim code.c
-bash-4.2$ vim makefile
//编译生成可执行程序code
-bash-4.2$ make
gcc -o code code.c
-bash-4.2$ ll
total 20
-rwxrwxr-x 1 wws wws 8360 Aug 19 11:26 code
-rw-r--r-- 1 wws wws   81 Aug 19 11:20 code.c
-rw-rw-r-- 1 wws wws   64 Aug 19 11:19 makefile
-bash-4.2$ ./code
hello Makefile!
//删除code
-bash-4.2$ make clean
rm -f code
-bash-4.2$ ll
total 8
-rw-r--r-- 1 wws wws 81 Aug 19 11:20 code.c
-rw-rw-r-- 1 wws wws 64 Aug 19 11:19 makefile

makefile原理

我们先了解一下各行代码作用

1.code(目标文件 要生成的文件):code.c (依赖文件列表 可以有多个文件)

                  gcc -o code code.c 

依赖关系:

(Tab键)依赖方法

2. .PHONY(声明一个伪目标):clean(伪目标名称)

     clean:(依赖文件列表为空)

                 rm -f code (要生成clean文件,就要执行它的依赖方法。但它的依赖方法不会生成文件,只是执行了删除文件的操作)

了解了这些我们看看几个问题

1.为什么make 就可以直接生成code文件呢?

(1)makefile文件会被make从上到下扫描,第一个目标名是缺省形成的。执行其他组的依赖关系和依赖方法,make+目标名。

把clean放第一个位置也可以make 默认执行。但不建议

2.PHONY:clean 有什么作用?

让目标文件的依赖方法每次都可执行。

-bash-4.2$ ll
total 8
-rw-r--r-- 1 wws wws 81 Aug 19 11:20 code.c
-rw-rw-r-- 1 wws wws 64 Aug 19 11:19 makefile
-bash-4.2$ make
gcc -o code code.c
-bash-4.2$ make
make: `code' is up to date.
-bash-4.2$ make
make: `code' is up to date.
-bash-4.2$ make
make: `code' is up to date.

可以看到code:code.c 执行一次就不能执行了。

当我们给code加上.PHONY后,

-bash-4.2$ vim makefile
-bash-4.2$ make
gcc -o code code.c
-bash-4.2$ make
gcc -o code code.c
-bash-4.2$ make clean
rm -f code
-bash-4.2$ make clean
rm -f code
-bash-4.2$ make clean
rm -f code

3.可以看到code:code.c可以被多次执行了,但为什么clean: 也可以被多次执行呢?

 让我们先修改一下makefile文件

首先我们要明白什么时候要重新编译文件,当然是文件内容被修改的时候。

根据对比code.c 和 code的Mtime(Modify)就可以判断文件内容有没有被修改。

.PHONY就是忽略Mtime时间的对比,来让目标文件的依赖方法每次都可执行。

stat 查看文信息

-bash-4.2$ ll
total 20
-rwxrwxr-x 1 wws wws 8360 Aug 19 12:32 code
-rw-r--r-- 1 wws wws   81 Aug 19 11:20 code.c
-rw-rw-r-- 1 wws wws   63 Aug 19 12:32 makefile
//stat 查看文件的详细信息
-bash-4.2$ stat code.c
  File: ‘code.c’
  Size: 81              Blocks: 8          IO Block: 4096   regular file
Device: fd01h/64769d    Inode: 1703942     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/     wws)   Gid: ( 1000/     wws)
//Access 文件最近访问时
Access: 2024-08-19 11:23:32.023200919 +0800
//Modify 最新文件内容被修改的时间
Modify: 2024-08-19 11:20:19.100243259 +0800
//Change 最新文件属性被修改的时间
Change: 2024-08-19 11:20:19.102243300 +0800
 Birth: -
-bash-4.2$ stat code
  File: ‘code’
  Size: 8360            Blocks: 24         IO Block: 4096   regular file
Device: fd01h/64769d    Inode: 1703940     Links: 1
Access: (0775/-rwxrwxr-x)  Uid: ( 1000/     wws)   Gid: ( 1000/     wws)
Access: 2024-08-19 12:32:42.882419012 +0800
Modify: 2024-08-19 12:32:42.882419012 +0800
Change: 2024-08-19 12:32:42.882419012 +0800
 Birth: -

让我们修改code.c文件的内容(因为文件属性也包含文件大小,内容改变,文件属性也会改变,所以Ctime和Mtime会一起改变)

-bash-4.2$ vim code.c
-bash-4.2$ stat code.c
  File: ‘code.c’
  Size: 180             Blocks: 8          IO Block: 4096   regular file
Device: fd01h/64769d    Inode: 1703950     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/     wws)   Gid: ( 1000/     wws)
Access: 2024-08-19 12:38:49.429946666 +0800
Modify: 2024-08-19 12:38:49.429946666 +0800
Change: 2024-08-19 12:38:49.431946707 +0800
 Birth: -
-bash-4.2$ stat code
  File: ‘code’
  Size: 8360            Blocks: 24         IO Block: 4096   regular file
Device: fd01h/64769d    Inode: 1703940     Links: 1
Access: (0775/-rwxrwxr-x)  Uid: ( 1000/     wws)   Gid: ( 1000/     wws)
Access: 2024-08-19 12:32:42.882419012 +0800
Modify: 2024-08-19 12:32:42.882419012 +0800
Change: 2024-08-19 12:32:42.882419012 +0800
 Birth: -

可以看到code.c的Mtime的时间在code Mtime的后面,说明code的内容已经不是最新的,就可以make 重新编译。

-bash-4.2$ make
gcc -o code code.c
-bash-4.2$ stat code
  File: ‘code’
  Size: 8360            Blocks: 24         IO Block: 4096   regular file
Device: fd01h/64769d    Inode: 1703940     Links: 1
Access: (0775/-rwxrwxr-x)  Uid: ( 1000/     wws)   Gid: ( 1000/     wws)
Access: 2024-08-19 12:41:24.546132682 +0800
Modify: 2024-08-19 12:41:24.546132682 +0800
Change: 2024-08-19 12:41:24.546132682 +0800
 Birth: -

最后回到为什么clean:可以重复执行,就是因为clean:的依赖方法rm没有时间概念,所以可以重复执行。

4.我们想输出1111,但不想输出echo "1111"(echo 和字符间的空格不能省),怎么关闭命令回显呢?

可以用前加@关闭

-bash-4.2$ make
echo "1111"
1111
echo "1111"
1111
echo "1111"
1111
echo "1111"
1111
gcc -o code code.c

-bash-4.2$ make
1111
1111
1111
1111
gcc -o code code.c

虽然看着只是用了一行代码就实现了对code.c的编译,其实展开来说这是一个递归实现的过程。

(2)make解析makefile时,如果code所依赖的code.o文件不存在,那么make会在当前文件中找目标为code.o文件的依赖性,以此类推,直到如找到再自下而上生成code(这有点像一个堆栈的过程)

-bash-4.2$ vim makefile
-bash-4.2$ make
gcc -E code.c -o code.i
gcc -S code.i -o  code.s
gcc -c code.s -o  code.o
gcc code.o -o code
-bash-4.2$ ll
total 48
-rwxrwxr-x 1 wws wws  8360 Aug 20 10:37 code
-rw-r--r-- 1 wws wws   180 Aug 19 12:59 code.c
-rw-rw-r-- 1 wws wws 16978 Aug 20 10:37 code.i
-rw-rw-r-- 1 wws wws  1680 Aug 20 10:37 code.o
-rw-rw-r-- 1 wws wws   538 Aug 20 10:37 code.s
-rw-rw-r-- 1 wws wws   205 Aug 20 10:37 makefile
-bash-4.2$ ./code
hello Makefile!
hello Makefile!
hello Makefile!
hello Makefile!
-bash-4.2$ make clean
rm -f code.i code.s code.o code
-bash-4.2$ ll
total 8
-rw-r--r-- 1 wws wws 180 Aug 19 12:59 code.c
-rw-rw-r-- 1 wws wws 205 Aug 20 10:37 makefile

makefile语法

1.% 通配符 $<

%.c 把当前目录中后缀.c文件放入依赖文件列表

$< :将依赖文件列表的文件一个一个交给gcc -c 配合 %.o生成同名的.o文件

2.定义变量名

我们可以给目标文件 依赖文件列表定义变量名。

$( ) 用来标记里面内容是变量名,不是文件。

3.$^ $@

$^:代表依赖文件列表 

$@:代表目标文件

(3)make默认只生成一个可执行程序

-bash-4.2$ ll
total 12
-rw-rw-r-- 1 wws wws 112 Aug 20 11:40 code.c
-rw-rw-r-- 1 wws wws 181 Aug 20 12:13 makefile
-rw-rw-r-- 1 wws wws  51 Aug 20 12:12 test.c
-bash-4.2$ make
gcc code.c -o code
-bash-4.2$ ll
total 24
-rwxrwxr-x 1 wws wws 8360 Aug 20 12:03 code
-rw-rw-r-- 1 wws wws  112 Aug 20 11:40 code.c
-rw-rw-r-- 1 wws wws 181 Aug 20 12:13 makefile
-rw-rw-r-- 1 wws wws  51 Aug 20 12:12 test.c

可以看到上面这种写法只生成了一个可执行程序,怎么才能生成两个呢?
我们可以用原理(2),让make默认生成all目标文件,生成all又需要实现依赖文件列表$(bin1) $(bin2) , 实现后all文件什么都不用做,就可以同时生成多个可执行程序。

-bash-4.2$ make
gcc code.c -o code
gcc test.c -o test
-bash-4.2$ ll
total 36
-rwxrwxr-x 1 wws wws 8360 Aug 20 12:13 code
-rw-rw-r-- 1 wws wws  112 Aug 20 11:40 code.c
-rw-rw-r-- 1 wws wws  181 Aug 20 12:13 makefile
-rwxrwxr-x 1 wws wws 8360 Aug 20 12:13 test
-rw-rw-r-- 1 wws wws   51 Aug 20 12:12 test.c

补充:回车/换行 缓冲区

首先回车和换行是同一个东西吗?
回车是把光标移动到一行的开头位置,换行是把光标从当前位置向下移一格,到下一行。

平时我们写程序\n 就是先进行回车再进行换行。

这与缓冲区有什么关系呢?

这两段代码生成的程序有什么不同吗?

很明显,第二段代码输出hello后不会换行。但除此以外第一段代码hello是一开始就会输出,但第二段代码会先等2秒再输出。

编译器肯定是自上而下来读代码,printf("hello")后hello去哪了?
其实它是被存在缓冲区了,只不过\n可以立刻输出缓冲区的内容,立刻输出hello。第二段代码没有\n,只能等代码结束或者缓冲区满后输出。

如果我们想让第二段代码缓冲区内容立刻输出,有什么办法吗?

可以加上fflush(stdout)可以立即将缓冲区内容刷新到输出设备。

注意下面代码输出 i 后进行\r回车操作,下一次输出时就会覆盖原位置内容。

但如果覆盖完后,后面还有上次留下的内容,就会连同新内容一起输出。

比如说上面输出10,经过回车操作,下次输出的9会覆盖1的位置,但后面0仍存在,导致后面一直有0。

-2%d 输出两位并左对齐进行解决

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

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

相关文章

第2章-01-网站中的资源介绍

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年CSDN全站百大博主。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 🏆本文已收录于专栏:Web爬虫入门与实战精讲。 🎉欢迎 👍点赞✍评论⭐收…

代码随想录算法训练营第二十一天| 669. 修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树

669. 修剪二叉搜索树 题目&#xff1a; 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即&#xff0c;如果没有被移除&…

类与对象(中(2))

开头 大家好啊&#xff0c;上一期内容我们介绍了类与对象中六大默认成员函数中的两种--->构造函数与析构函数&#xff0c;相信大家多少都形成了自己的独到见解。那么今天&#xff0c;我将继续就拷贝构造函数与运算符重载函数来展开讲解&#xff0c;话不多说&#xff0c;我们…

在 Vue.js 中使用 Ant Design 实现表格开关功能:详细教程

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

秃姐学AI系列之:池化层 + 代码实现

目录 池化层 二维最大池化层 Max Pooling 池化层超参数 平均池化层 Mean Pooling 总结 代码实现 池化层 卷积对位置非常敏感的&#xff0c;但是我们在实际应用中我们需要一定程度的平移不变性。比如照明、物体位置、比例、外观等因素会导致图片发生变化。所以卷积对未…

【WebSocket】websocket学习【二】

1.需求&#xff1a;通过websocket实现在线聊天室 2.流程分析 3.消息格式 客户端 --> 服务端 {"toName":"张三","message":"你好"}服务端 --> 客户端 系统消息格式&#xff1a;{"system":true,"fromName"…

pygame开发课程系列(5): 游戏逻辑

第五章 游戏逻辑 在本章中&#xff0c;我们将探讨游戏开发中的核心逻辑&#xff0c;包括碰撞检测、分数系统和游戏状态管理。这些元素不仅是游戏功能的关键&#xff0c;还能显著提升游戏的趣味性和挑战性。 5.1 碰撞检测 碰撞检测是游戏开发中的一个重要方面&#xff0c;它用…

【C语言】字符函数与字符串函数(下)

字符函数与字符串函数&#xff08;下&#xff09; 文章目录 字符函数与字符串函数&#xff08;下&#xff09;1.strncpy的使用和模拟实现1.1使用示例&#xff1a;1.2模拟实现 2.strncat的使用和模拟实现2.1使用示例&#xff1a;2.2模拟实现 3.strncmp的使用和模拟实现3.1使用示…

方法汇总 | Pytorch实现常见数据增强(Data Augmentation)【附源码】

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发…

目标检测 | yolov10 原理和介绍

相关系列&#xff1a; 目标检测 | yolov1 原理和介绍 目标检测 | yolov2/yolo9000 原理和介绍 目标检测 | yolov3 原理和介绍 目标检测 | yolov4 原理和介绍 目标检测 | yolov5 原理和介绍 目标检测 | yolov6 原理和介绍 目标检测 | yolov7 原理和介绍 目标检测 | yolov8 原理和…

JS TypeError: Cannot read properties of null (reading ‘getAttribute’) 解决

JS TypeError: Cannot read properties of null (reading ‘getAttribute’) 解决 在JavaScript开发中&#xff0c;TypeError: Cannot read properties of null (reading getAttribute) 是一个常见的错误&#xff0c;它表明你尝试从一个值为null的对象上调用getAttribute方法。…

【AI学习】人工智能的几种主义

无意翻开了杨立昆的《科学之路》&#xff0c;书前有好多人作序&#xff0c;数了一下&#xff0c;八个人的序言&#xff0c;说明&#xff0c;至少有八个人读过这本书。其中黄铁军教授讲到了机器学习的发展历程。 人工智能发展历程中的各种主义&#xff0c;对于外行人大概都是如我…

微信好友恢复,分享4大技巧,快速恢复微信好友

在微信的社交网络中&#xff0c;好友关系的维护至关重要。但有时候&#xff0c;由于误操作或其他原因&#xff0c;我们可能会不小心删除了某些重要联系人。那么&#xff0c;如果想再度找回这些好友&#xff0c;我们应该使用什么方法呢&#xff1f; 别担心&#xff0c;本文将分…

4-1-4 步进电机原理1(电机专项教程)

4-1-4 步进电机原理1&#xff08;电机专项教程&#xff09; 4-1-4 步进电机原理1步进基本工作原理步进电机优点步进电机主要部件步进电机基本原理步进电机分类双极性单极性步进电机 4-1-4 步进电机原理1 如何使用arduino控制步进电机 步进电机从原理和工作方法上都更加复杂一些…

打靶记录13——doubletrouble

靶机&#xff1a; https://www.vulnhub.com/entry/doubletrouble-1,743/ 难度&#xff1a; 中 目标&#xff1a; 取得两台靶机 root 权限 涉及攻击方法&#xff1a; 主机发现端口扫描Web信息收集开源CMS漏洞利用隐写术密码爆破GTFObins提权SQL盲注脏牛提权 学习记录&am…

CSP-CCF 202305-1 重复局面

一、问题描述 【题目背景】 国际象棋在对局时&#xff0c;同一局面连续或间断出现3次或3次以上&#xff0c;可由任意一方提出和棋。 【问题描述】 国际象棋每一个局面可以用大小为 88 的字符数组来表示&#xff0c;其中每一位对应棋盘上的一个格子。六种棋子王、后、车、象、…

STL六大组件

STL&#xff08;Standard Template Library&#xff0c;标准模板库&#xff09;是C标准库的一部分&#xff0c;提供了丰富且高效的数据结构和算法。STL主要由6大组件构成&#xff0c;分别是容器、算法、迭代器、适配器、仿函数和空间配置器。 容器&#xff08;Containers&#…

Midjourney进阶-反推与优化提示词(案例实操)

​ Midjourney中提示词是关键&#xff0c;掌握提示词的技巧直接决定了生成作品的质量。 当你看到一张不错的图片&#xff0c;想要让Midjourney生成类似的图片&#xff0c;却不知道如何描述画面撰写提示词&#xff0c;这时候Midjourney的/describe指令&#xff0c;正是帮助你推…

AIoTedge边缘计算平台V1.0版本发布

AIoTedge边缘计算平台V1.0&#xff0c;一款创新的AIoT解决方案&#xff0c;现已正式发布。该产品集成了NodeRED软网关、边缘物联网平台和边缘AI能力&#xff0c;为企业提供强大的边云协同能力。它支持设备管理和泛协议接入&#xff0c;确保不同设备间的无缝连接。AIoTedgeV1.0还…

SQL-事务与并发问题

在数据库管理系统中&#xff0c;事务是一个重要的概念&#xff0c;它确保了一组数据库操作要么全部成功&#xff0c;要么全部失败&#xff0c;从而维护数据的完整性和一致性。随着多个用户同时访问数据库&#xff0c;事务的并发处理变得尤为重要。 1. 事务的定义 事务是指一组…