⌛️
文章目录
- 一、GNU 概述
- 二、GNU C 编辑器
- 2.1 目标代码的生成过程
- 2.2 GNU 概述
- 2.3 GNU C 编译链接工具——gcc
- 2.4 GNU C 编译链接工具——as
- 2.5 GNU C 编译链接工具——ld
- 三、项目管理工具——GNU make
- 3.1 项目管理概述
- 3.2 基于 make 工具的项目管理
- 3.3 Makefile中的变量
- 3.3.1 自定义变量
- 3.3.2 环境变量
- 3.3.3 预定义变量
- 3.3.4 自动变量
- 3.4 Makefile文件中的潜规则
- 3.4.1 隐含规则
- 3.4.2 后缀规则
- 3.4.3 模式规则
- 四、创建和使用函数库
- 4.1 静态库
- 4.1.1 静态库管理工具
- 4.1.2 创建静态库
- 4.2 共享库
- 4.3 动态链接库
- 五、参考附录:
GNU ☁️
上一篇文章链接: 【Linux学习笔记④】——Shell程序设计【变量 输入与输出 条件表达式 判断语句 循环语句 Shell函数】.
下一篇文章链接: …
一、GNU 概述
● GNU 的全称为 GNU’s Not Unix,这是官方的递归定义,永远找不到本义,是开源软件的幽默。
● GNU工程已经开发了一个被称为 “GNU”(GNU是“不是UNIX”的缩写)的、对 Unix 向上兼容的完整的自由软件系统 (free software system) 。由 Richard Stallman【自由软件运动的精神领袖、GNU计划以及自由软件基金会的创立者、著名黑客】完成的最初的 GNU 工程的文档被称为 ‘GNU宣言’,该宣言已经被翻译成多种其它语言。
● 你可以也可以不用为获取 GNU 软件而支付费用。不论是否免费,一旦你得到了软件,你在使用中就拥有三种特定的自由:
① 首先是复制程序并且把它送给你的朋友或者同事的自由。
② 而后是通过获取完整的源代码,按照你的意愿修改程序的自由。
③ 最后是发布软件的改进版并且有助于创建自由软件社团的自由。
二、GNU C 编辑器
● GUN C 是在 Linux 系统下的 C语言。
● 用高级语言编写的代码必须经过编译和链接,最终生成可执行的目标代码。
① 首先,C/C++源代码会经过编译器,汇编源代码经过汇编器,生成目标文件(.o文件)。
② 如果有多个文件需要编译,为了便于管理,可将具体 *** 作按一定规则写入makefile文件,make工具根据makefile文件的要求执行相关命令生成目标文件。
③ 如果这些目标代码中的函数需要在其他应用中重复使用,可通过归档文件.ar将这些.o文件归档为函数库。
④ 最后,通过链接器将目标文件及相关函数库链接成为共享库、可链接文件或可执行文件。
2.2 GNU 概述
● GCC(GNU Compiler Collection)是 GNU 下编译器及其相关工具的集合。
● GCC 原名为 “ GNU C 语言编译器 ”,因为它原本只能处理 C 语言。但随着 GCC 的发展,在功能上得到了不断的扩充,现在它具有一下特点:
① 支持多种高级语言(如 C++、Java等)
② 支持多种硬件处理器(例如:x86、ARM等)
③ 支持多种 *** 作系统平台(例如:Linux、Windows等)
■ 语法:gcc [选项] 目标文件 源文件
▶功能:将 C 语言编译为目标代码或可执行文件。
● 常用选项如下:
● 例如:
gcc -c test.c # 生成目标代码 test.o gcc -o test test.o # 将目标文件 test.o 链接为可执行文件 test
■ 语法:as [选项] 汇编文件
▶功能:将汇编语言源代码汇编为目标代码。
● 常用选项如下:
● 例如:
ld -T linkcmds -o test test.o # 指定链接命令文件
■ 语法:ld [选项] 目标文件列表
▶功能:将若干目标文件和函数库链接在一起,重定位符号引用和数据。(在默认情况下,无须定义链接命令文件,链接器 ld 会使用默认的链接命令文件)
● 例如:
as -o test.o test.s # 将汇编语言源代码 test.s 汇编为目标代码 test.o # 由于 gcc 是编译工具的集成器, 因此汇编器 as 可以用 gcc -S 代替
三、项目管理工具——GNU make 3.1 项目管理概述
● 在开发规模较大的应用项目时,常采用模块化设计方法,即将系统分解为若干个模块。各模块完成各自特定的功能。
● 此时,系统中存在多个源代码文件。当生成最终的可执行文件时,必须逐个编译这些源代码文件,并在最后将所有的目标代码链接为可执行程序…如果这些步骤都需要手工 *** 作就很耗时间。
● 为此 GNU 项目开发了一个用于自动完成这些 *** 作的项目管理工具make,用户只需将这些步骤按一定的语法规则以命令的方式写入文本文件,一般命名为Makefile。此后用户只需在命令提示符下输入make命令,make工具会根据Makefile文件中的定义,自动执行一些列编译和链接工作。这便节省了时间。
■ Makefile文件的语法:
目标文件: 依赖文件1 依赖文件2 ... 依赖文件n命令1 命令2 ... 命令n
◆ 说明:① 只有当所依赖的文件被更新时,make才执行相应的命令更新目标文件。② “命令” 指的是产生目标文件需要执行的命令。
■ make命令的语法:make [选项] [目标]
▶功能:创建指定的目标,如果没有指定目标,则创建第一个目标。make使用的默认的规则定义文件是 GNUmakefile、makefile、Makefile。
● 常用选项如下:
● 样例如下:【首先编写一个 Makefile 文件,准备对其进行项目管理】
# test_script appexam: main.o app.o mod.o lib.o gcc -o appexam main.o app.o mod.o lib.o main.o: main.c app.h gcc -c main.c app.o: app.c app.h gcc -c app.c mod.o: mod.c gcc -c mod.c lib.o: lib.c lib.h gcc -c lib.c clean: rm -f*.o # 移除所有后缀为 .o 的文件。因为已经链接好程序了,不再需要这些文件了。
● 然后我们对该脚本进行调用:
make appexam # 指定要创建的目标为 appexam 这个文件
● 然后,我们将得到各目标之间的依赖关系如下图所示:【当某个目标被修改时,则依赖它的所有上级目标(包括上级祖先等)都会被重新编译】
◆ 注:最下面一排的,“main.o” 改为 “main.c”、“app.o” 改为 “app.c”。
● 为了使在 Makefile 中规则的书写更为简洁,也为了能适应不同的开发环境,可在定义 Makefile 定义变量,变量可用于保存文件名列表、命令和命令参数等。make 工具支持 4 种类型的变量:自定义变量、环境变量、预定义变量、自动变量。
● 这类变量有用户自定义,一般用大写字母表示。
■ 语法:变量名=字符串
▶功能:将 “字符串” 赋值给 “变量名”。注:在 Makefile 中无数据类型。
★调用:$(变量名)
● 样例如下:【即把 3.2 的例子改写如下】
# test_script OBJS=main.o app.o mod.o lib.o appexam: $(OBJS) gcc -o appexam $(OBJS) # 相当于命令 gcc -o appexam main.o app.o mod.o lib.o main.o: main.c app.h gcc -c main.c app.o: app.c app.h gcc -c app.c mod.o: mod.c gcc -c mod.c lib.o: lib.c lib.h gcc -c lib.c clean: rm -f*.o # 移除所有后缀为 .o 的文件。因为已经链接好程序了,不再需要这些文件了。
● make在运行过程中,会将环境变量转化为同名同值的make变量,用户也可在Makefile中对这些变量进行重新定义。
● GNU make预定义了一些变量(就像英语中的固定搭配的语法),它们在Makefile文件中可以直接使用。也可以对这些变量进行重新定义。一些常用的预定义变量如下表:
● 样例如下:【即可把 3.3.1 的例子改写如下】
# test_script OBJS=main.o app.o mod.o lib.o appexam: $(OBJS) $(CC) -o appexam $(OBJS) # 相当于命令 gcc -o appexam main.o app.o mod.o lib.o main.o: main.c app.h $(CC) -c main.c app.o: app.c app.h $(CC) -c app.c mod.o: mod.c $(CC) -c mod.c lib.o: lib.c lib.h $(CC) -c lib.c clean: rm -f*.o # 移除所有后缀为 .o 的文件。因为已经链接好程序了,不再需要这些文件了。
● 自动变量由make工具预先定义,具有特定的含义,它的值与规则中的目标和依赖对象有关。下面给出部分常用的自动变量及其定义。
● 样例如下:【即可把 3.3.3 的例子改写如下】
# test_script OBJS=main.o app.o mod.o lib.o appexam: $(OBJS) $(CC) -o $@ $^ # 相当于命令 gcc -o appexam main.o app.o mod.o lib.o main.o: main.c app.h $(CC) -c -o $@ $< # 相当于 gcc -c -o main.c app.o: app.c app.h $(CC) -c -o $@ $< mod.o: mod.c $(CC) -c -o $@ $< lib.o: lib.c lib.h $(CC) -c -o $@ $< clean: rm -f*.o # 移除所有后缀为 .o 的文件。因为已经链接好程序了,不再需要这些文件了。
● 通常为了产生目标文件,需要在目标文件和依赖对象之间建立明确的规则,定义如何生成目标的流程,但有时可简化这些 *** 作。即用以下三种规则。
● GNU make 定义了内置的隐含规则,在不给出产生目标文件的命令时,由make自动添加。
● 样例如下:【即可把 3.3.4 的例子改写如下】
# test_script OBJS=main.o app.o mod.o lib.o appexam: $(OBJS) $(CC) -o $@ $^ # 相当于命令 gcc -o appexam main.o app.o mod.o lib.o main.o: main.c app.h app.o: app.c app.h mod.o: mod.c lib.o: lib.c lib.h clean: rm -f*.o # 移除所有后缀为 .o 的文件。因为已经链接好程序了,不再需要这些文件了。
● 定义:将具有某后缀的文件(例如.c文件)转换为具有另外一种后缀的文化(例如 .o文件)的方法。使用方法是将每个以两个成对出现的后缀名定义。
● 样例如下:【即可把 3.4.1 的例子改写如下】
# test_script .c.o: gcc -c $< OBJS=main.o app.o mod.o lib.o appexam: $(OBJS) $(CC) -o $@ $^ # 相当于命令 gcc -o appexam main.o app.o mod.o lib.o main.o: main.c app.h app.o: app.c app.h mod.o: mod.c lib.o: lib.c lib.h clean: rm -f*.o # 移除所有后缀为 .o 的文件。因为已经链接好程序了,不再需要这些文件了。
● 模式规则是对具体规则的进一步抽象,定义了一类具有相同行为特点的规则,例如用%表示通配符号。
● 样例如下:【即可把 3.4.2 的例子改写如下】
# test_script %.c: %.o gcc -c $< OBJS=main.o app.o mod.o lib.o appexam: $(OBJS) $(CC) -o $@ $^ # 相当于命令 gcc -o appexam main.o app.o mod.o lib.o clean: rm -f*.o # 移除所有后缀为 .o 的文件。因为已经链接好程序了,不再需要这些文件了。
四、创建和使用函数库
● 函数库:由若干目标文件按某种格式构成的集合,目标文件是由源文件经过编译生成的中间代码。在进行软件开发的过程中,往往会积累许多可复用代码。为了提高软件的开发效率,可将这些代码编译,并分类打包成函数库,供其他项目使用。
● 函数库可分为两类:静态库和共享库。它们俩在与应用程序的链接方式上具有不同的特点。
① 在链接静态库时,会将使用的静态库对象嵌入到可执行映像文件中。
② 在链接共享库时,仅当可执行映像文件中保留加载目标对象所需的信息后,在调用时,才真正将目标对象加载至内存。
● 静态库由ar工具创建。经编译的应用程序和静态库链接时,链接器将静态库中被调用的对象嵌入到可执行映像文件中,这样在没有静态库的环境下,应用程序也能独立运行。
● 静态库文件的命名规则是libxxx.a,以lib开头,.a作为文件名后缀
■ 语法:ar [选项] [归档文件] 目标文件列表
▶功能:用于创建、修改和查询归档文件。
● 常用的一些选项如下:
● 样例如下:【用两个 C 源文件创建静态库】
第一个命名为 “test_1.c” 的 C 语言源文件:
// test_1.c int add(int x, int y) { return x + y; }
第二个命名为 “test_2.c” 的 C 语言源文件:
// test_2.c int func(int count) { int sum = 0; for(int i = 1; i < count; i++) sum += i; return sum; }
创建静态库的步骤如下:
(1) 编译 test_1.c 和 test_2.c, 生成目标文件 gcc -c -Wall test_1.c # 生成目标文件 test_1.o gcc -c -Wall test_2.c # 生成目标文件 test_2.o (2) 创建静态库 ---> 并将库命名为 test_lib.a ar -cru lib_test.a test_1.o test_2.o // 注: 选项 c 告诉了 ar 创建一个新的静态库, 除非该静态库已存在 // 选项 r 告诉了 ar 替换已经存在的目标文件 // 选项 u 告诉了 ar 被替换的目标文件必须是最新的 (3) 为了使用静态库, 首先需定义静态库的应用接口, 代码如下: // test_interface.h #ifndef _DEMOLIB_API_H #define _DEMOLIB_API_H extern int add(int x, int y); // 外部函数声明(即说明该函数的实现在外部) extern int func(int count); #endif
下面是使用lib_test.a的测试程序(该文件命名为test_file.c),代码如下:
// test_file.c #incldue#incldue"lib_test.a" int main() { int val, x, y; x = 2; y = 18; val = add(x, y); printf("The mult of x and y is %d.n", val); val = func(100); printf("The sum is %d.n", val); return 0; }
利用静态库test_lib.a编译生成可执行文件test的具体方法如下:
gcc test_file.c -L. lib_test.a -o test // -L. 表示静态库在当前目录下
● 具体运行结果如下:
◆ 说明:上面的倒数第二个箭头的命令行 “vi test_file,c” 写错了,改成 “vi test_file.c”
● 静态库的特点:
① 运行时无需外部库的支持。
② 较高的运行速度。
③ 可执行文件具有较大的体积。
④ 不容易维护。
● 经过编译后的应用程序在和共享库链接时,与静态库不同,没有将共享库中的目标对象嵌入至映像文件,而是只在生成的可执行映像文件时嵌入。因此,离开了共享库的支持,应用程序就无法运行。
● 共享库文件的命名规则是libxxx.so。
● 共享库的创建、使用和加载和静态库类似,这里不在赘述。
● 注意:若在当前目录下同时存在lib_test.a和lib_test.so,在默认情况下首先会使用共享库,若需要使用静态库则需要加上选项-static,示例如下:
gcc -static test_file.c -L. -lib_test.a -o test
● 共享库的特点:
① 可执行的文件体积小。
② 容易维护
③ 不能离开动态库独立运行
④ 运行速度比较慢
● 动态链接库是运用共享库的一种方式,在运行的任何时刻都可以动态加载共享库。与一般使用的共享库不同,通常应用程序在启动时,不立即加载共享库,而是在需要时,动态加载共享库。在这种情况下,称共享库为动态链接库。(.dll)
五、参考附录:
[1]《GNU/Linux编程》
人民邮电出版社
[2]GNU和Unix的区别
链接: https://www.vsdiffer.com/gnu-vs-unix.html.
上一篇文章链接: 【Linux学习笔记④】——Shell程序设计【变量 输入与输出 条件表达式 判断语句 循环语句 Shell函数】.
下一篇文章链接: …
⭐️ ⭐️
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)