【Linux】Linux:sudo 白名单配置与 GCC/G++ 编译器使用指南
🔥 脏脏a的技术站 🔥
「在代码的世界里,脏脏的技术探索从不设限~」
🚀 个人主页:脏脏a-CSDN博客📌 技术聚焦:Linux 环境下 GCC/G++工具的实用技巧与深度解析
📊 文章专栏:Linux🔗 上篇回顾:Linux工具:yum和vim
在 Linux 世界里,
sudo
权限管理与 GCC/G++ 编译工具是绕不开的核心。对于开发者而言,既要能安全、精准地通过
sudo
白名单获取超级权限(避免权限滥用风险),又得熟练运用 GCC/G++ 编译 C/C++ 代码。本文先聚焦
sudo
白名单的极简配置逻辑,教你安全放开必要权限;再拆解 GCC/G++ 最核心的编译用法,让你快速掌握 Linux 下 C/C++ 程序编译的关键步骤。
目录
🔍一、sudo 白名单的配置详解
🎨二、C/C++ 开发环境的核心支撑 —— 头文件与库文件
🧪三、GCC 与 G++ 的本质区别
📋四、编译的四个核心阶段
4.1 预处理:宏替换与代码准备
4.2 编译:生成汇编代码
4.3 汇编:生成目标代码
4.4 链接:生成可执行文件
🚧五、函数库:静态库与动态库
5.1 基础概念与核心特性
5.2 GCC 编译时的链接行为
5.3 链接的特殊情况与混合链接
5.4 优缺点对比
5.5 扩展知识:可执行文件格式与调试构建
🔍一、sudo 白名单的配置详解
我们在使用普通用户时,若想用 root 权限创建文件等操作,又不想切换账号,就可以借助 sudo
临时获取 root 权限。但一般情况下,普通用户直接用 sudo
提权会失败,这是因为 sudo
的权限控制由 /etc/sudoers
文件(及相关配置)管理,普通用户尚未被拥有权限的用户(如 root)在该文件中配置进 “白名单”(即设置好对应的权限规则),所以操作会被拒绝。
【就像这样的场景】:
【如何将普通用户加入白名单】:
由于sudoers文件的拥有者是root所以得使用root用户添加,切换root账号,打开ect目录下的sudoers文件,在图片黄色格子圈的地方,按上述示例添加你的用户
保存并退出文件后,再次尝试:
上述图片可以看到,用root身份创建file文件创建成功
🎨二、C/C++ 开发环境的核心支撑 —— 头文件与库文件
我们能在 Windows 或 Linux 上开展 C/C++ 开发,核心原因在于系统中提前或后续安装了 C/C++ 开发相关的头文件和库文件。
C/C++ 开发环境不只是 Visual Studio(VS)、GCC、G++ 这些编译工具,语言本身的头文件和库文件才是更关键的支撑。像安装 VS2019、VS2022 时,选择对应的开发包,其实就是在同步下载 C 语言的头文件和库文件。对于编译型语言而言,安装开发包必然要下载并安装对应的头文件与库文件,而且 C 的头文件和库文件在 Windows 系统上也是存在的。
【软件版本的裁剪:条件编译的应用】:
以软件的社区版(免费)和专业版(付费,功能更丰富)为例,提供这些软件的公司并不需要维护两份完全独立的代码。
借助 条件编译 技术,公司可以根据不同的编译条件,对社区版不需要的功能进行裁剪。比如在代码中通过 #ifdef
#ifndef
等条件编译指令,判断当前编译的是社区版还是专业版,从而决定是否包含某些专业功能的代码段,这样大大减少了代码维护的成本。
🧪三、GCC 与 G++ 的本质区别
- GCC:是 GNU 编译器集合的总称,支持 C、C++、Java、Fortran 等多种语言,当编译 C 代码时,它会自动调用 C 编译器。
- G++:是 GCC 下专门用于编译 C++ 代码的工具,本质上是 GCC 的一个前端,会自动链接 C++ 标准库(如
libstdc++
)。
核心差异:编译 .c
文件时,GCC 会默认按 C 语言语法处理,而 G++ 会默认按 C++ 语法处理;编译 .cpp
文件时,两者都会按 C++ 语法处理,但 G++ 会自动链接 C++ 库,GCC 则需要手动指定 -lstdc++
选项才能链接 C++ 库。
第一次编译失败是因为没有链接到C++的库,第二次加入-lstdc++选项才链接成功
📋四、编译的四个核心阶段
要深入理解 GCC/G++ 的工作,首先得知晓代码从源码到可执行文件的四个关键阶段,每一步都在为最终生成可运行程序铺路。
4.1 预处理:宏替换与代码准备
预处理阶段主要负责对源码进行 “初步加工”,包括宏替换、头文件展开、条件编译执行以及注释删除等操作。
- 指令示例:
gcc -E test.c -o test.i
-E
选项的作用是让 GCC 在完成预处理后就停止后续的编译流程。-o
用于指定输出文件,这里生成的 test.i
文件就是经过预处理后的 C 原始程序,里面已经完成了宏替换、头文件包含等操作。
4.2 编译:生成汇编代码
这一阶段,GCC 会先严格检查代码的规范性,排查语法错误。若代码无误,就会将其翻译成汇编语言。
- 指令示例:
gcc -S test.i -o test.s
-S
选项能让 GCC 只进行编译,不执行后续的汇编步骤,最终生成汇编代码文件 test.s
,我们可以通过查看这个文件来了解代码对应的汇编指令。
4.3 汇编:生成目标代码
汇编阶段是把编译阶段生成的 .s
汇编文件转换成机器可识别的目标文件(.o
文件)。
- 指令示例:
gcc -c test.s -o test.o
-c
选项会让 GCC 完成汇编操作,生成二进制格式的目标文件 test.o
,不过这个目标文件还不能直接执行,需要后续的链接步骤。
4.4 链接:生成可执行文件
成功编译后,就进入链接阶段。链接的作用是将目标文件与所需的函数库(如 C 标准库)进行关联,最终生成可执行文件。
- 指令示例:
gcc test.o -o test
- 执行这条命令后,GCC 会把目标文件 test
.o
与系统库等资源链接起来,生成可执行文件 test,此时就可以直接运行这个程序了。
🚧五、函数库:静态库与动态库
5.1 基础概念与核心特性
【静态库】:
- 定义:编译链接时,会将库文件的全部代码嵌入可执行文件。
- 后缀:Linux 下通常为
.a
。 - 特点:生成的可执行文件体积大,但运行时不依赖外部库,可独立运行。例如,若程序链接了静态数学库,编译后库代码直接 “打包” 进程序,在无对应库的环境中也能运行。
【动态库】:
- 定义:编译链接时仅记录库引用,程序运行时由运行时链接器加载库。
- 后缀:Linux 下通常为
.so
(如libc.so.6
),Windows 下为.dll
。 - 特点:可执行文件体积小,多个程序能共享同一份库代码,但运行时依赖库存在。若动态库缺失,依赖它的所有程序可能都无法正常运行。
5.2 GCC 编译时的链接行为
【默认动态链接】:
GCC 编译生成可执行程序时,默认采用动态链接方式。例如:
gcc test.c -o test
生成的 test 是动态链接程序,可通过 file test
验证(输出含 “dynamic executable” 字样),再用 ldd test
可查看其依赖的动态库列表。
【静态链接的实现】:
若要强制静态链接,需添加 -static
选项:
gcc -static test.c -o test_static
此时程序会链接静态库(需系统安装对应静态库包,如 CentOS 下可通过 a
安装静态 C 标准库和 C++ 标准库)。用 ldd hello_static
验证,会显示 “not a dynamic executable”,说明无动态库依赖。
5.3 链接的特殊情况与混合链接
【无静态库时强制静态链接】
若系统没有所需静态库,却使用 -static
选项,编译会失败。因为静态链接必须找到对应的静态库文件才能完成 “代码嵌入” 操作。
【动态库与静态库共存时的链接优先级】
当系统同时存在动态库和静态库,且 GCC 都能找到时,默认优先动态链接。-static
的本质是改变链接优先级,强制优先选择静态库,但这种 “优先级改变” 是 “只适配一次” 的逻辑,并非所有依赖都强制静态链接。
【混合链接】
实际开发中,程序可采用混合链接(部分模块动态链接,部分静态链接)。比如,对核心功能模块链接静态库以保证独立性,对通用功能链接动态库以节省资源,但需通过复杂的编译选项或链接脚本精细控制,一般在对程序性能、体积和依赖有特殊要求的场景使用。
5.4 优缺点对比
【动态库】
- 优点:
- 资源共享:多个程序共享同一份库代码,节省磁盘空间、网络空间、和内存空间(运行时库只加载一次)。
- 更新便捷:库更新后,只需替换动态库文件,无需重新编译所有依赖程序。
- 缺点:
- 运行依赖:依赖的动态库缺失或版本不兼容时,程序无法运行。
- 加载开销:运行时加载库会带来一定性能开销(虽通常可忽略,但对极致性能场景有影响)。
【补充】:
【静态库】
- 优点:
- 独立性强:程序不依赖外部库,在纯净环境(无对应动态库)也能运行,适合嵌入式设备、严苛运行环境的程序。
- 运行稳定:无动态库加载的不确定性,运行行为更稳定。
- 缺点:
- 体积庞大:可执行文件包含库全部代码,占用更多磁盘和内存。
- 更新繁琐:库更新后,所有依赖程序都需重新编译链接。
【补充】:
5.5 扩展知识:可执行文件格式与调试构建
【可执行文件格式】
Linux 下可执行程序采用 ELF(Executable and Linkable Format) 格式,并非简单的二进制流,而是包含段表、符号表等结构,用于程序加载和链接。
【debug 与 release 构建】
- debug 构建:编译时添加
-g
选项(如gcc -g hello.c -o hello_debug
),生成的程序包含调试信息,可通过 GDB(gdb hello_debug
)进行单步调试、变量查看等操作。 - release 构建:默认不包含调试信息,且可添加优化选项(如
-O2
)提升性能(gcc -O2 hello.c -o hello_release
),生成的程序体积小、运行快,适合发布。