IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 【Linux学习笔记⑤】——GNU C语言开发环境【GNU make、静态库】 -> 正文阅读

[系统运维]【Linux学习笔记⑤】——GNU C语言开发环境【GNU make、静态库】


??



GNU ??

上一篇文章链接: 【Linux学习笔记④】——Shell程序设计【变量 输入与输出 条件表达式 判断语句 循环语句 Shell函数】.
下一篇文章链接: 🚧 🚧…


一、GNU 概述

??● GNU 的全称为 GNU’s Not Unix,这是官方的递归定义,永远找不到本义,是开源软件的幽默。

??● GNU工程已经开发了一个被称为 “GNU”(GNU是“不是UNIX”的缩写)的、对 Unix 向上兼容的完整的自由软件系统 (free software system) 。由 Richard Stallman【自由软件运动的精神领袖、GNU计划以及自由软件基金会的创立者、著名黑客】完成的最初的 GNU 工程的文档被称为 ‘GNU宣言’,该宣言已经被翻译成多种其它语言。

??● 你可以也可以不用为获取 GNU 软件而支付费用。不论是否免费,一旦你得到了软件,你在使用中就拥有三种特定的自由:
????① 首先是复制程序并且把它送给你的朋友或者同事的自由。
????② 而后是通过获取完整的源代码,按照你的意愿修改程序的自由。
????③ 最后是发布软件的改进版并且有助于创建自由软件社团的自由。

比较项GNUUnix
起源由Richard Stallman开发的,他是MIT AI Lab的黑客。由Ken Thompson和Dennis Ritchie为贝尔实验室开发的。
最初命名GNU是开发的软件的名称。由贝尔实验室开发的名称为AT&T UNIX。
独自发挥作用该软件(Shell)本身无法运行,因为它需要一个内核才能与硬件交互。UNIX由Shell和内核组成,可以单独运行。
依赖GNU仅仅是Shell软件,它依赖于任何内核,并且正确地部署了UNIX内核。它不依赖于任何其他操作系统,它具有自己的组件。
源代码GNU源代码可免费向公众公开,可以根据要求修改代码。UNIX源代码不适用于公众。


二、GNU C 编辑器

??● GUN C 是在 Linux 系统下的 C语言。

2.1 目标代码的生成过程

??● 用高级语言编写的代码必须经过编译和链接,最终生成可执行的目标代码。

??① 首先,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等)


2.3 GNU C 编译链接工具——gcc

??■ 语法gcc [选项] 目标文件 源文件
???功能:将 C 语言编译为目标代码或可执行文件。

??● 常用选项如下

选项功能
-S编译生成汇编文件(.s)
-c编译生成目标文件(.o)
-o指定输出文件名
-Wall打印警告信息

??● 例如

gcc -c test.c		# 生成目标代码 test.o
gcc -o test test.o	# 将目标文件 test.o 链接为可执行文件 test


2.4 GNU C 编译链接工具——as

??■ 语法as [选项] 汇编文件
???功能:将汇编语言源代码汇编为目标代码。

??● 常用选项如下

选项功能
-o设置输出文件名
-M输出链接信息
-T commandfile指定链接命令文件

??● 例如

ld -T linkcmds -o test test.o 	# 指定链接命令文件


2.5 GNU C 编译链接工具——ld

??■ 语法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文件中的定义,自动执行一些列编译和链接工作。这便节省了时间。

3.2 基于 make 工具的项目管理

??■ Makefile文件的语法

目标文件: 依赖文件1  依赖文件2 ... 依赖文件n
<tab键>命令1
<tab键>命令2
...
<tab键>命令n

??◆ 说明:① 只有当所依赖的文件被更新时,make才执行相应的命令更新目标文件。② “命令” 指的是产生目标文件需要执行的命令。

??■ make命令的语法make [选项] [目标]

???功能:创建指定的目标,如果没有指定目标,则创建第一个目标。make使用的默认的规则定义文件是 GNUmakefile、makefile、Makefile。

??● 常用选项如下

选项功能
-o设置输出文件名
-M输出链接信息
-T commandfile指定链接命令文件

??● 样例如下:【首先编写一个 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”。


3.3 Makefile中的变量

??● 为了使在 Makefile 中规则的书写更为简洁,也为了能适应不同的开发环境,可在定义 Makefile 定义变量,变量可用于保存文件名列表、命令和命令参数等。make 工具支持 4 种类型的变量:自定义变量、环境变量、预定义变量、自动变量。

3.3.1 自定义变量

??● 这类变量有用户自定义,一般用大写字母表示。

??■ 语法变量名=字符串

???功能:将 “字符串” 赋值给 “变量名”。注:在 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 的文件。因为已经链接好程序了,不再需要这些文件了。


3.3.2 环境变量

??● make在运行过程中,会将环境变量转化为同名同值的make变量,用户也可在Makefile中对这些变量进行重新定义。

3.3.3 预定义变量

??● GNU make预定义了一些变量(就像英语中的固定搭配的语法),它们在Makefile文件中可以直接使用。也可以对这些变量进行重新定义。一些常用的预定义变量如下表:

预定义变量名含义默认值
AR归档程序ar
AS汇编器as
CCC语言编译器cc
CXX带有标准输出的 C 语言预处理程序$(CC)-E
RM删除文件的命令rm -r

??● 样例如下:【即可把 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 的文件。因为已经链接好程序了,不再需要这些文件了。


3.3.4 自动变量

??● 自动变量由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 的文件。因为已经链接好程序了,不再需要这些文件了。


3.4 Makefile文件中的潜规则

??● 通常为了产生目标文件,需要在目标文件和依赖对象之间建立明确的规则,定义如何生成目标的流程,但有时可简化这些操作。即用以下三种规则。

3.4.1 隐含规则

??● 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 的文件。因为已经链接好程序了,不再需要这些文件了。


3.4.2 后缀规则

??● 定义:将具有某后缀的文件(例如.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.3 模式规则

??● 模式规则是对具体规则的进一步抽象,定义了一类具有相同行为特点的规则,例如用%表示通配符号。

??● 样例如下:【即可把 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 的文件。因为已经链接好程序了,不再需要这些文件了。


四、创建和使用函数库

??● 函数库:由若干目标文件按某种格式构成的集合,目标文件是由源文件经过编译生成的中间代码。在进行软件开发的过程中,往往会积累许多可复用代码。为了提高软件的开发效率,可将这些代码编译,并分类打包成函数库,供其他项目使用。

??● 函数库可分为两类:静态库和共享库。它们俩在与应用程序的链接方式上具有不同的特点。
????① 在链接静态库时,会将使用的静态库对象嵌入到可执行映像文件中。
????② 在链接共享库时,仅当可执行映像文件中保留加载目标对象所需的信息后,在调用时,才真正将目标对象加载至内存。

4.1 静态库

??● 静态库由ar工具创建。经编译的应用程序和静态库链接时,链接器将静态库中被调用的对象嵌入到可执行映像文件中,这样在没有静态库的环境下,应用程序也能独立运行。

??● 静态库文件的命名规则是libxxx.a,以lib开头,.a作为文件名后缀

4.1.1 静态库管理工具

??■ 语法ar [选项] [归档文件] 目标文件列表
???功能:用于创建、修改和查询归档文件。

??● 常用的一些选项如下

选项功能描述
-c创建一个函数库
-r向函数库中插入目标对象,若存在则替换
-u若函数库中已经存在同名目标,则用新目标更新
-t显示函数库中目标对象列表
-d从函数库中删除目标对象


4.1.2 创建静态库

??● 样例如下:【用两个 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<stdio.h>
#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

在这里插入图片描述

??● 静态库的特点
????① 运行时无需外部库的支持。
????② 较高的运行速度。
????③ 可执行文件具有较大的体积。
????④ 不容易维护。


4.2 共享库

??● 经过编译后的应用程序在和共享库链接时,与静态库不同,没有将共享库中的目标对象嵌入至映像文件,而是只在生成的可执行映像文件时嵌入。因此,离开了共享库的支持,应用程序就无法运行。

??● 共享库文件的命名规则是libxxx.so

??● 共享库的创建、使用和加载和静态库类似,这里不在赘述。

??● 注意:若在当前目录下同时存在lib_test.alib_test.so,在默认情况下首先会使用共享库,若需要使用静态库则需要加上选项-static,示例如下:

gcc -static test_file.c -L. -lib_test.a -o test

??● 共享库的特点
????① 可执行的文件体积小。
????② 容易维护
????③ 不能离开动态库独立运行
????④ 运行速度比较慢


4.3 动态链接库

??● 动态链接库是运用共享库的一种方式,在运行的任何时刻都可以动态加载共享库。与一般使用的共享库不同,通常应用程序在启动时,不立即加载共享库,而是在需要时,动态加载共享库。在这种情况下,称共享库为动态链接库。(.dll



五、参考附录:

[1]《GNU/Linux编程》📚
人民邮电出版社

[2]GNU和Unix的区别
链接: https://www.vsdiffer.com/gnu-vs-unix.html.

上一篇文章链接: 【Linux学习笔记④】——Shell程序设计【变量 输入与输出 条件表达式 判断语句 循环语句 Shell函数】.

下一篇文章链接: 🚧 🚧…


?? ??

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-12-02 17:10:50  更:2021-12-02 17:11:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 2:37:17-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码