既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)
2. 静态链接库
静态链接库实现链接操作的方式很简单,即程序文件中哪里用到了库文件中的功能模块,GCC
编译器就会将该模板代码直接复制到程序文件的适当位置,最终生成可执行文件。
使用静态库文件实现程序的链接操作,既有优势也有劣势:
- 优势是,生成的可执行文件不再需要任何静态库文件的支持就可以独立运行(可移植性强);
- 劣势是,如果程序文件中多次调用库中的同一功能模块,则该模块代码势必就会被复制多次,生成的可执行文件中会包含多段完全相同的代码,造成代码的冗余。
和使用动态链接库生成的可执行文件相比,静态链接库生成的可执行文件的体积更大。
- 在
Linux
发行版系统中,静态链接库文件的后缀名通常用.a
表示; - 在
Windows
系统中,静态链接库文件的后缀名为.lib
;
2.1 创建静态链接库
静态链接库其实就相当于压缩包,其内部可以包含多个源文件。但需要注意的是,并非任何一个源文件都可以被加工成静态链接库,其至少需要满足以下 2 个条件:
- 源文件中只提供可以重复使用的代码,例如函数、设计好的类等,不能包含
main
主函数; - 源文件在实现具备模块功能的同时,还要提供访问它的接口,也就是包含各个功能模块声明部分的头文件;
示例代码结构:
wohu@ubuntu:~/cpp/src$ tree
.
├── function.h
├── greeting.cpp
├── main.cpp
└── name.cpp
0 directories, 4 files
wohu@ubuntu:~/cpp/src$
function.h
代码
void sayGreetings();
void sayName();
greeting.cpp
代码, 其中包含 #include "function.h"
,不创建静态库时可以不用包含该头文件。
#include <iostream>
#include "function.h"
void sayGreetings()
{
std::cout << "hello,world" << std::endl;
}
name.cpp
代码,其中包含 #include "function.h"
,不创建静态库时可以不用包含该头文件。
#include <iostream>
#include "function.h"
void sayName()
{
std::cout << "My name is wohu" << std::endl;
}
main.cpp
代码
#include <iostream>
#include "function.h"
int main()
{
sayGreetings();
sayName();
return 0;
}
对于name.cpp
和 greeting.cpp
都符合以上两个条件, 因此都可以被加工成静态链接库。并且根据实际需要,我们可以将它们集体压缩到一个静态链接库中,也可以各自压缩成一个静态链接库。
将源文件打包为静态链接库的过程很简单,只需经历以下 2 个步骤:
- 将所有指定的源文件,都编译成相应的目标文件
wohu@ubuntu:~/cpp/src$ g++ -c greeting.cpp name.cpp
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp greeting.o main.cpp name.cpp name.o
wohu@ubuntu:~/cpp/src$
- 然后使用
ar
压缩指令,将生成的目标文件打包成静态链接库,其基本格式如下:
ar rcs 静态链接库名称 目标文件1 目标文件2 ...
有关 ar
打包压缩指令,以及 rcs
各选项的含义和功能,请参考 Linux ar命令
重点说明的是,静态链接库的不能随意起名,需遵循如下的命名规则:
libxxx.a
Linux
系统下,静态链接库的后缀名为.a
;Windows
系统下,静态链接库的后缀名为.lib
;
其中,xxx
代指我们为该库起的名字,比如 Linux
系统自带的一些静态链接库名称为 libc.a
、libgcc.a
、libm.a
,它们的名称分别为 c
、gcc
和 m
。
下面,将 greeting.o
、name.o
打包到一个静态链接库中:
wohu@ubuntu:~/cpp/src$ ar rcs libmyfunction.a name.o greeting.o
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp greeting.o libmyfunction.a main.cpp name.cpp name.o
wohu@ubuntu:~/cpp/src$
其中,libmyfunction.a
就是 name.o
、greeting.o
一起打包生成的静态链接库,myfunction
是我们自定义的库名。
2.2 使用静态链接库
静态链接库的使用很简单,就是在程序的链接阶段,将静态链接库和其他目标文件一起执行链接操作,从而生成可执行文件。
以前面代码为例,首先我们将 main.cpp
文件编译为目标文件:
wohu@ubuntu:~/cpp/src$ g++ -c main.cpp
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp greeting.o libmyfunction.a main.cpp main.o name.cpp name.o
wohu@ubuntu:~/cpp/src$
在此基础上,我们可以直接执行如下命令,即可完成链接操作:
wohu@ubuntu:~/cpp/src$ g++ -static main.o libmyfunction.a
wohu@ubuntu:~/cpp/src$ ls
a.out function.h greeting.cpp greeting.o libmyfunction.a main.cpp main.o name.cpp name.o
wohu@ubuntu:~/cpp/src$
其中,-static
选项强制 GCC
编译器使用静态链接库。
注意,如果 GCC
编译器提示无法找到 libmyfunction.a
,还可以使用如下方式完成链接操作:
wohu@ubuntu:~/cpp/src$ g++ -static main.o -L /home/wohu/cpp/src -lmyfunction
wohu@ubuntu:~/cpp/src$ ls
a.out function.h greeting.cpp greeting.o libmyfunction.a main.cpp main.o name.cpp name.o
其中,
-L
(大写的L
)选项用于向GCC
编译器指明静态链接库的存储位置(可以借助 pwd 指令查看具体的存储位置);-l
(小写的L
)选项用于指明所需静态链接库的名称,注意这里的名称指的是xxx
部分,且建议将-l
和xxx
直接连用(即-lxxx
),中间不需有空格。
由此,就生成了 a.out
可执行文件:
wohu@ubuntu:~/cpp/src$ ./a.out
hello,world
My name is wohu
wohu@ubuntu:~/cpp/src$
3. 动态链接库
动态链接库,又称为共享链接库。和静态链接库不同,采用动态链接库实现链接操作时,程序文件中哪里需要库文件的功能模块,GCC
编译器不会直接将该功能模块的代码拷贝到文件中,而是将功能模块的位置信息记录到文件中,直接生成可执行文件。
显然,这样生成的可执行文件是无法独立运行的。采用动态链接库生成的可执行文件运行时,GCC
编译器会将对应的动态链接库一同加载在内存中,由于可执行文件中事先记录了所需功能模块的位置信息,所以在现有动态链接库的支持下,也可以成功运行。
采用动态链接库实现程序的连接操作,其优势和劣势恰好和静态链接库相反:
- 优势是,由于可执行文件中记录的是功能模块的地址,真正的实现代码会在程序运行时被载入内存,这意味着,即便功能模块被调用多次,使用的都是同一份实现代码(这也是将动态链接库称为共享链接库的原因)。
- 劣势是,此方式生成的可执行文件无法独立运行,必须借助相应的库文件(可移植性差)。
和使用静态链接库生成的可执行文件相比,动态链接库生成的可执行文件的体积更小,因为其内部不会被复制一堆冗余的代码。
- 在
Linux
发行版系统中,动态链接库的后缀名通常用.so
表示; - 在
Windows
系统中,动态链接库的后缀名为.dll
;
GCC
编译器生成可执行文件时,默认情况下会优先使用动态链接库实现链接操作,除非当前系统环境中没有程序文件所需要的动态链接库,GCC
编译器才会选择相应的静态链接库。如果两种都没有(或者 GCC
编译器未找到),则链接失败。
3.1 创建动态链接库
总的来说,动态链接库的创建方式有 2 种。
- 直接使用源文件创建动态链接库,采用
gcc
命令实现的基本格式如下:
gcc -fpic -shared 源文件名... -o 动态链接库名
其中,
-shared
选项用于生成动态链接库;-fpic
(还可写成-fPIC
)选项的功能是,令GCC
编译器生成动态链接库(多个目标文件的压缩包)时,表示各目标文件中函数、类等功能模块的地址使用相对地址,而非绝对地址。这样,无论将来链接库被加载到内存的什么位置,都可以正常使用。
例如,将前面项目中的 greeting.cpp
、name.cpp
这 2 个源文件生成一个动态链接库,执行命令为:
wohu@ubuntu:~/cpp/src$ g++ -fPIC -shared name.cpp greeting.cpp -o libmyfunction.so
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp libmyfunction.a libmyfunction.so main.cpp name.cpp
![img](https://img-blog.csdnimg.cn/img_convert/57227ad45a58e9e104724fdb666c86e9.png)
![img](https://img-blog.csdnimg.cn/img_convert/e3f618834a17377ddbb3cc8de1d1c562.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**
-1715881489765)]
[外链图片转存中...(img-rMkZbYKA-1715881489765)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**