【Linux】8.Linux基础开发工具使用(2)

news/2025/1/16 3:34:23 标签: linux, excel, 运维

文章目录

  • 1. Linux编译器-gcc/g++使用
    • 关于sudo
    • 1.1 背景知识
    • 1.2 gcc如何完成
      • 1.2.1 预处理(进行宏替换)
      • 1.2.2 编译(生成汇编)
      • 1.2.3 汇编(生成机器可识别代码)
      • 1.2.4 连接(生成可执行文件或库文件)
      • 1.2.5 总结
    • 1.3 函数库(重要概念)
      • 我们的`.o`和库是怎么链接的呢?
      • 函数库一般分为静态库和动态库两种。
      • 动静态链接的优缺点
      • gcc选项
  • 2. Linux项目自动化构建工具-make/Makefile
    • 2.1 背景
    • 2.2 区分


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

关于sudo

之前的文章里面,我们无法使用sudo,会显示没有权限。

1f3a80a8a2c559ceacd9fdc5e582fde0

当时讲的是权限提升,但是这里输入的是自己的密码,感觉有点不合理,为什么不用root密码呢?

这样设计有几个重要原因:

  1. 安全性
  • 避免多人共享root密码,降低密码泄露风险
  • 每个用户使用自己的密码,便于追踪谁在什么时候执行了特权命令
  • 即使一个用户的密码泄露,影响范围也仅限于该用户被授予的权限
  1. 权限管理
  • 可以精确控制每个用户可以执行哪些特权命令
  • 不需要给用户完整的root权限,只给必要的权限
  • 管理员可以随时添加或撤销某个用户的sudo权限
  1. 审计追踪
  • 系统日志可以记录谁在什么时候使用了sudo
  • 每个用户使用自己的密码,便于确认身份
  • “This incident will be reported” 就是这个审计系统的一部分

这种设计比直接共享root密码更加安全和可控。这也是为什么现代Linux系统默认禁用root直接登录,推荐使用sudo进行权限提升。

我们可以登录root用户,输入vim /etc/sudoers,进入文件,在文件最末尾输入指令,把ydk_108添加到sudo组。

46fa973395d5bd04f7a157e71cd43822

添加好后,我们通过sudo创建的文件拥有者和所属组就是root了。

b820238ce7b379b2a729e5e260212337


我们先回到108目录,创建lesson7文件夹,进去后创建mycode.c文件

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson4$ cd ..
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108$ mkdir lesson7
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108$ cd lesson7
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson7$ ll
total 8
drwxrwxr-x 2 ydk_108 ydk_108 4096 Jan 13 10:21 ./
drwxrwxr-x 5 ydk_108 ydk_108 4096 Jan 13 10:21 ../
ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson7$ touch mycode.c

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson7$ ll
total 8
drwxrwxr-x 2 ydk_108 ydk_108 4096 Jan 13 10:21 ./
drwxrwxr-x 5 ydk_108 ydk_108 4096 Jan 13 10:21 ../
-rw-rw-r-- 1 ydk_108 ydk_108    0 Jan 13 10:21 mycode.c

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson7$ vim mycode.c

写好程序后退出,使用gcc命令编译

a21e72a99c2ed9423818f09b402ab38b

gcc:编译C语言

g++:编译C++/C语言(建议编译C++

为什么我们能在Windows或者Linux上进行C/C++或者其他形式的开发呢?

我们人生中第一行代码就是#include<stdio.h>

是不是说明我们的系统中一定要提前或者后续安装上,C/C++开发的相关头文件,库文件。

C/C++开发环境不仅仅指的是vs,gcc,g++,更重要的是语言本身的头文件和库文件。

那么Linux里面的头文件装在哪里了呢?

我们输入:ll /usr/include/

2e85867db0740e4fa2f6bc3de27d6eba

就可以看到一大堆的头文件。

我们使用的stdio.h文件也在里面。

bbc45011c40347d5fe2a9e8b4173c486


1.1 背景知识

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

    1. 去注释
    2. 头文件展开
    3. 条件编译
    4. 宏替换
  2. 编译(生成汇编)

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

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


1.2 gcc如何完成

格式:gcc [选项] 要编译的文件 [选项] [目标文件]

84e20d6e1e0acc7a9a20251addd0bd3b


1.2.1 预处理(进行宏替换)

  • 预处理功能主要包括宏定义,文件包含,条件编译,去注释等。

  • 预处理指令是以#号开头的代码行。

  • 实例: gcc –E hello.c –o hello.i

  • 选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。

  • 选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序。

f7c3d36ece1dfaa4082240e9db634cb5

bdd295894c9d973a887a54df9e23eb41


1.2.2 编译(生成汇编)

  • 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc 把代码翻译成汇编语言。

  • 用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。

  • 实例: gcc –S hello.i –o hello.s

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson7$ gcc -S mycode.i -o mycode.s
# 这里的mycode.i也可以写成mycode.c,不过这么写就是从头开始了,而不是从预处理结束开始。

7d443510b75631565b3d2f1581a80d29


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

  • 汇编阶段是把编译阶段生成的“.s”文件转成目标文件

  • 读者在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了

  • 实例: gcc –c hello.s –o hello.o

ydk_108@iZuf68hz06p6s2809gl3i1Z:~/108/lesson7$ gcc -c mycode.s -o mycode.o

c9ed9976f7a6a288e6e813ee0e3d3328

然后我们进去看一下:

d8a71e03f465f2cc544e808b6923dbdb

这里面

8ac1596d158801f3b29842eb70e781eb

mycode.o:这个文件不可以独立执行 ,虽然已经是二进制了,但还是需要经过链接才能执行。

下面有的人可能认为我这里没有给可执行权限,所以不能执行,然后我加了可执行权限也不可以执行。

所以我们要明白一个点:拥有可执行权限和拥有执行可执行权限的能力是两码事。

ac4b726f1dcd57401a14e8446421d3da


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

  • 在成功编译之后,就进入了链接阶段。

  • 实例: gcc hello.o –o hello

  • 将可重定位目标二进制文件,和库进行链接形成可执行程序。

2be143c9f93b7b8a19dd4c21ba32afc9


1.2.5 总结

-E:告诉gcc,从现在开始进行程序的翻译,将预处理工作做完就停下来,不要往后走了。

-S:从现在开始进行程序的翻译,将编译工作做完,就停下来。

-c:从现在开始进行程序的翻译,将编译工作做完,就停下来。

mycode.o:可重定位目标二进制文件,简称目标文件,.obj文件。这个文件不可以独立执行 ,虽然已经是二进制了,但还是需要经过链接才能执行。

键盘左上角有个esc键,可以这么来记忆。


1.3 函数库(重要概念)

我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?

最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。

库实际上就是把源文件(.c),经过一定的翻译,然后打包 – 只给你提供一个文件即可,不用给你提供太多的源文件,也可以达到隐藏源文件的目的。

头文件提供方法的声明,库文件提供方法的实现 + 你的代码 = 你的软件

库存在的价值就是不让我们做重复工作,站在巨人的肩膀上。


我们的.o和库是怎么链接的呢?

有两种链接:

  1. 动态链接
  2. 静态链接

我们可以举个例子:

比如周末,你给自己规划了好多日程,你按照日程一个一个执行,

  1. 写作业
  2. 玩电脑
  3. 洗澡
  4. 睡觉

你先写了作业,然后要去玩电脑,但是家里没有电脑,你就要去网吧。

网吧是你朋友告诉过你位置的。

你玩完游戏后回来,然后洗澡,睡觉。


你一步一步按顺序执行就是可执行程序

当可执行程序一步一步执行到自己无法完成的地方的时候,就要跳转到库中执行库当中的方法。这个过程叫做跳转到库中执行

执行完了之后返回。这个过程叫做返回我的代码调用处

然后继续按顺序做下面的日程。这个过程叫做继续向后运行

这个网吧就相当于动态库

告诉你网吧位置的朋友就相当于是编译器

这个的运作方式链接方式就叫做动态链接

上网的肯定不止你一个人,所以这个动态库是被很多程序所共享的,动态库也被称为共享库

如果有一天,这个网吧有人带炸药了,被警察封锁了,那么就不能去玩电脑了,你和你朋友就不能一起打游戏了。

所以,动态库不能缺失,一旦对应的动态库缺失,影响的不止一个程序,可能很多程序都会无法正确运行。

我们可以先把之前的一堆东西删掉,然后重新编译mycode.c,然后使用ldd命令查看这个可执行程序的动态库。

他依赖的是libc.so.6

5b6bcc91bfaa78adc9d2cc91509749ee

如果上面,你爸去二手市场给你买了台电脑,那我就不用去网吧了。

这种把动态库拥有的功能拷贝到自己这里的实现手段叫做静态链接

拷贝到自己这里的这个东西(例子中自己的电脑)就叫做静态库

这个时候就算二手市场倒闭了,也没关系了,自己可以在自己的电脑里上网。

在编译器使用静态库进行静态链接的时候会将自己的方法拷贝到目标程序中,该程序以后就不用再依赖静态库了。

Linux中,如果要按照静态链接的方法形成可执行程序,需要添加-static选项来提供静态库。

这里的静态链接和动态链接形成的文件大小也不一样,虽然实现效果可能一样。

7cbff258a4497ecdc7243c9ea8e64edc

这里输入ldd查询,他也会提示你不是动态链接。

a9f4b9d87b6d3e3cf0c49afe2634032e


函数库一般分为静态库和动态库两种。

  • 静态库是指编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大,但在运行时也就不再需要库文件了。其后缀名一般为“.a

  • 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销。动态库一般后缀名为“.so”,如前面所述的 libc.so.6 就是动态库。gcc 在编译时默认使用动态库。完成了链接之后,gcc 就可以生成可执行文件,如下所示。 gcc hello.o –o hello

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

  • 动态库和静态库不是一个东西,你不能说你跑到网吧去买电脑,也不能说去二手市场里面花钱玩电脑。

  • 关于静态库的下载可以自行百度,下载的时候注意版本和系统。

  1. 如果我们没有静态库,但是我们就要-static,行不行?

    不行。

  2. 如果我们没有动态库,只有静态库,并且gcc能够找到我们的静态库,那么直接gcc会报错吗?

    不会,gcc默认优先动态链接,但是没有动态链接就用静态库了。-static的本质就是改变优先级。

  3. 我们形成的可执行程序不一定是纯的动态链接或者静态链接,混合的。

    但是如果加了-static那么就会把所有的静态要求变成静态链接。


动静态链接的优缺点

动态库

优点:因为是共享库,可以有效地节省资源(节省磁盘空间,节省内存空间,节省网络空间)。

缺点:动态库一旦缺失,就会导致各个程序都无法运行

静态库

优点:不依赖库,程序可以独立运行

缺点:体积大,比较消耗资源


gcc选项

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

-S:编译到汇编语言不进行汇编和链接

-c:编译到目标代码

-o:文件输出到 文件

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

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

-shared:此选项将尽量使用动态库,所以生成文件比较小,但是需要系统由动态库.

-O0,-O1,-O2,-O3:编译器的优化选项的4个级别,-O0表示没有优化,-O1为缺省值,-O3优化级别最高

-w:不生成任何警告信息。

-Wall:生成所有警告信息。


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

2.1 背景

  • 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力

  • 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作

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

  • make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:DelphimakeVisual C++nmakeLinuxGNUmake。可见,makefile都成为了一种在工程方面的编译方法。

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


2.2 区分

make:是一条指令

makefile:是一个当前目录下的文件

bcd51f8fe5bbd186234a4035fc024525

然后写下面两行,注意第二行是Tab开头

bc600738745181f40342c2bccd384ac9

保存退出后我们就可以直接make

a602805d6c2ec8c8e0fd6edc193f493a

我们也可以进去再次修改一下,给一个清理的命令

ee130661c4db75433fea0c3f51f9b502

mytest.exe:mycode.c # 依赖关系
        gcc -o mytest.exe mycode.c # 依赖方法
#mytest.exe 依赖于 mycode.c
#意思是:要生成mytest.exe,必须先有mycode.c
#如果mycode.c有更新,再次make时会重新生成mytest.exe

.PHONY:clean
clean:
        rm -f mytest.exe
  1. mytest.exe:mycode.c

    • 这是一个目标规则
    • 表示 mytest.exe 是目标文件
    • mycode.c 是依赖文件
    • 意思是:要生成mytest.exe,需要用到mycode.c
  2. gcc -o mytest.exe mycode.c

    • 这是命令行(注意:前面必须是Tab,不能是空格)
    • 用gcc编译器将mycode.c编译成mytest.exe可执行文件
    • -o 选项指定输出文件的名称
  3. .PHONY:clean

    • 这是一个特殊标记
    • 告诉make命令,clean不是一个文件名,而是一个标签
    • 即使当前目录下有一个名为clean的文件,make clean命令仍然会执行
  4. clean:

    • 这是一个清理目标
    • 用于清理编译产生的文件
  5. rm -f mytest.exe

    • 删除编译生成的可执行文件
    • -f 表示强制删除,即使文件不存在也不会报错

使用方法:

make        # 编译生成mytest.exe
make clean  # 清理,删除mytest.exe

3695b6b05e71aa15151dcd39e4b52603

可以把我们从一些冗余的命令里面解放出来。


我们也可以深度解释一下依赖关系和依赖方法:

4c4349d1ba1251369a97b0f9405fd972

mycode:mycode.o
        gcc -o mycode mycode.o
mycode.o:mycode.s
        gcc -c mycode.s -o mycode.o
mycode.s:mycode.i # 依赖关系
        gcc -S mycode.i -o mycode.s
mycode.i:mycode.c
        gcc -E mycode.c -o mycode.i #依赖方法
  1. mycode.i:mycode.c

    • 依赖关系:mycode.i依赖于mycode.c
    • 依赖方法:gcc -E mycode.c -o mycode.i
    • -E选项表示只做预处理
    • 这一步会展开所有的宏定义和头文件包含
  2. mycode.s:mycode.i

    • 依赖关系:mycode.s依赖于mycode.i
    • 依赖方法:gcc -S mycode.i -o mycode.s
    • -S选项表示编译到汇编代码
    • 这一步会将预处理后的代码转换成汇编语言
  3. mycode.o:mycode.s

    • 依赖关系:mycode.o依赖于mycode.s
    • 依赖方法:gcc -c mycode.s -o mycode.o
    • -c选项表示编译成目标文件
    • 这一步将汇编代码转换成机器码
  4. mycode:mycode.o

    • 依赖关系:最终的可执行文件mycode依赖于mycode.o
    • 依赖方法:gcc -o mycode mycode.o
    • 这一步是链接,生成最终的可执行文件

整个过程是:

源文件(.c) -> 预处理文件(.i) -> 汇编文件(.s) -> 目标文件(.o) -> 可执行文件

每一步都依赖于前一步的结果,这就是依赖关系。而用gcc命令将一个文件转换成另一个文件的过程,就是依赖方法。

89712c370c644a3db0a19a91ff4dfb66

上面的依赖关系删掉一条的话就会报错。

上面的操作说明make会自动推导makefile中的依赖关系,是栈式结构。

然后我们添加clean

mycode:mycode.o
        gcc -o mycode mycode.o
mycode.o:mycode.s
        gcc -c mycode.s -o mycode.o
mycode.s:mycode.i # 依赖关系
        gcc -S mycode.i -o mycode.s
mycode.i:mycode.c
        gcc -E mycode.c -o mycode.i #依赖方法

clean:
        rm -f mycode.i mycode.s mycode.o mycode

daddc2b2eabe2d1aaf508a81a77a10d9

make默认是从上往下执行的,所以不建议把clean放到makefile文件的开头。

make如果执行了一次后,没有更新文件内容,那么他就不会执行第2次了,因为没有必要。可以提高编译效率。

4cb30e913377da296a9707418091e3ec

可是这个操作是怎么做到的?

一定是源文件形成可执行文件,先有源文件,才有可执行。

一般而言,源文件的最近修改时间比可执行文件要老。

如果我们更改了源文件,历史上曾经还有可执行,那么源文件的最近修改时间一定比可执行程序要新。

所以只需要比较我们可执行程序的最近修改时间和源文件的最近修改时间就可以达成这个操作了。

make会根据源文件和目标文件的新旧,判断是否需要重新执行。

那么我们如果一定要编译呢?不管时间如何,我就是要编译。

我们可以在 开头加上这个

c0432b29d221cae8a0820cc1d364425b

99bfea37c19b055e6178a50470c4825a

这样就可以了。

.PHONY 的作用是声明"假目标"

不过一般不写这个。一般可以修饰清理的命令.PHONY:clean

makefile里面还可以这么写:

mycode:mycode.c
        gcc -o $@ $^
# $@ 表示目标文件名,这里就是mycode
# $^ 表示所有依赖文件,这里就是mycode.c
# 所以这行等同于:gcc -o mycode mycode.c

.PHONY:clean
clean:
        rm -f mycode.i mycode.s mycode.o mycode

make clean的时候会显示clean里面的东西,怎么把那个东西不显示呢?

mycode:mycode.c
        gcc -o $@ $^

.PHONY:clean
clean:
        @rm -f mycode.i mycode.s mycode.o mycode

加一个@在前面就好了


http://www.niftyadmin.cn/n/5824607.html

相关文章

爬虫逆向学习(十五):Akamai 3.0反爬分析与sensor-data算法逆向经验

此分享只用于学习用途&#xff0c;不作商业用途&#xff0c;若有冒犯&#xff0c;请联系处理 Akamai 3.0反爬分析与sensor-data算法逆向经验 Akamai开始正题前须知站点信息接口分析反爬点反爬点定位_abck定位结果 逆向前准备工作sensor_data生成位置本地替换文件 请求体sensor…

在kubernetes中部署Nacos集群

在kubernetes中部署Nacos集群 1.Nacos介绍1.1 什么是Nacos1.2 主要功能1.3 应用场景 2.部署Nacos集群实践2.1 NFS动态提供Kubernetes后端存储卷2.2 Nacos集群 1.Nacos介绍 1.1 什么是Nacos Nacos&#xff08;全称为"Dynamic Naming and Configuration Service"&…

环境搭建——Mysql、Redis、Rocket MQ部署

前言 在搭建分布式系统时&#xff0c;MySQL、Redis 和 RocketMQ 是常用的基础服务。每个服务各自的功能不同&#xff0c;但它们在数据存储、缓存、消息队列等方面不可或缺。如果你是初学者&#xff0c;别担心&#xff0c;本文会一步步详细教你如何在服务器上通过 Docker 部署这…

redis acl

redis acl redis 安全访问控制 官网 本文基于redis 6.2.17 版本进行测试验证 使用方式 redis 使用 acl 的配置有2种方式&#xff1a;使用 redis.conf 文件配置&#xff0c;和在 redis.conf 文件中配置 aclfile path 指定外部 aclfile 文件路径 使用 redis.conf 文件配置 …

基于R语言的现代贝叶斯统计学方法(贝叶斯参数估计、贝叶斯回归、贝叶斯计算实践过程

专题一 贝叶斯统计学的思想与概念 1.1 信念函数与概率 1.2 事件划分与贝叶斯法则 1.3 稀少事件的概率估计 1.4 可交换性 1.5 预测模型的构建 专题二 单参数模型 2.1 二项式模型与置信域 2.2 泊松模型与后验分布 2.3 指数族模型与共轭先验 专题三 蒙特卡罗逼近 3.…

Windows 正确配置android adb调试的方法

下载适用于 Windows 的 SDK Platform-Tools https://developer.android.google.cn/tools/releases/platform-tools?hlzh-cn 设置系统变量&#xff0c;路径为platform-tools文件夹的绝对路径 点击Path添加环境变量 %adb%打开终端输入adb shell 这就成功了&#xff01;

phpstorm jetbrain 配置review code

禁用Unused CSS selector 步骤&#xff1a; 在 PhpStorm 中&#xff0c;点击顶部菜单 File > Settings&#xff08;Windows/Linux&#xff09;或 PhpStorm > Preferences&#xff08;macOS&#xff09;。在 Inspections 界面左侧的搜索框中输入 CSS。展开 CSS 部分&…

测试模型安全的一些高级手段

1. 模型后门攻击&#xff08;Model Backdoor Attack&#xff09; 定义&#xff1a; 在训练过程中或部署阶段引入后门&#xff08;backdoor&#xff09;&#xff0c;攻击者通过触发特定条件让模型产生不符合预期的行为。 实现方式&#xff1a; 在输入中嵌入特定的触发器&…