GCC处理静态库与动态库与各种命令用途、小游戏体验
一、用gcc处理静态库与动态库
1、用gcc生成.a静态库和.so的动态库
(1)编辑所需要的程序hello.h,hello.c,main.c
在写代码之前先创建一个目录保存此次作业
nivechen@nivechen-virtual-machine:~$ mkdir homework3.1
nivechen@nivechen-virtual-machine:~$ cd homework3.1
程序代码如下:
hello.h文件
#ifndef HELLO_H
#define HELLO_H
void hello(const char *name);
#endif //HELLO_H
hello.c文件
#include <stdio.h>
void hello(const char *name)
{
printf("Hello %s!\n", name);
}
main.c文件
#include "hello.h"
int main()
{
hello("everyone");
return 0;
}
(2)将hello.c文件编译成hello.o文件
nivechen@nivechen-virtual-machine:~/homework3.1$ gcc -c hello.c
nivechen@nivechen-virtual-machine:~/homework3.1$ ls //通过ls命令查看hello.o文件确实存在
hello.c hello.h hello.o main.c
(3)由.o文件创建静态库
nivechen@nivechen-virtual-machine:~/homework3.1$ ar -crv libmyhello.a hello.o
a - hello.o
nivechen@nivechen-virtual-machine:~/homework3.1$ ls
hello.c hello.h hello.o libmyhello.a main.c
(4)使用静态库文件,创建可执行程序,并运行
nivechen@nivechen-virtual-machine:~/homework3.1$ gcc main.c libmyhello.a -o outputhello1
nivechen@nivechen-virtual-machine:~/homework3.1$ ls
hello.c hello.h hello.o libmyhello.a main.c outputhello1
nivechen@nivechen-virtual-machine:~/homework3.1$ ./outputhello1
Hello everyone!
我们删除静态库文件看看公用函数hello是否真的已经连接到目标文件中
nivechen@nivechen-virtual-machine:~/homework3.1$ rm libmyhello.a
nivechen@nivechen-virtual-machine:~/homework3.1$ ls
hello.c hello.h hello.o main.c outputhello1
nivechen@nivechen-virtual-machine:~/homework3.1$ ./outputhello1
Hello everyone!
注:上面可以清晰看出静态库文件已经被删除,但是程序还是正常的运行,因为静态库文件在编译时就会连接到目标文件中,程序运行不需要再使用静态库文件。下面我们看动态库文件与之的区别。
(5)由.o文件创建动态库文件
nivechen@nivechen-virtual-machine:~/homework3.1$ gcc -shared -fPIC -o libmyhello.so hello.o
nivechen@nivechen-virtual-machine:~/homework3.1$ ls
hello.c hello.h hello.o libmyhello.so main.c outputhello1
(6)使用动态库文件,创建可执行程序,并运行
nivechen@nivechen-virtual-machine:~/homework3.1$ gcc main.c libmyhello.so -o outputhello2
nivechen@nivechen-virtual-machine:~/homework3.1$ ls
hello.c hello.h hello.o libmyhello.so main.c outputhello1 outputhello2
nivechen@nivechen-virtual-machine:~/homework3.1$ ./outputhello2
./outputhello2: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory //这里发现不能正常运行可执行文件outputhello2,这是因为虽然连接时用的是当前目录的动态库,但是运行时,是到/usr/lib 中找库文件的,我们将文件 libmyhello.so 复制到目录/usr/lib 中就可以正常运行了。
nivechen@nivechen-virtual-machine:~/homework3.1$ mv libmyhello.so /usr/lib
nivechen@nivechen-virtual-machine:~/homework3.1$ ./outputhello2
Hello everyone!
2、.a与.so库文件的生成与使用
(1)编写需要用到的文件A1.C,A2.C,A.h,test.c
首先还是先建一个目录存放该练习的文件
nivechen@nivechen-virtual-machine:~$ mkdir homework3.2
nivechen@nivechen-virtual-machine:~$ cd homework3.2
nivechen@nivechen-virtual-machine:~/homework3.2$ gedit A1.c
nivechen@nivechen-virtual-machine:~/homework3.2$ gedit A2.c
nivechen@nivechen-virtual-machine:~/homework3.2$ gedit A.h
nivechen@nivechen-virtual-machine:~/homework3.2$ gedit test.c
nivechen@nivechen-virtual-machine:~/homework3.2$ ls
A1.c A2.c A.h test.c
通过ls命令可以看见我们创建的目录下面已经存在这四个文件,也可以在桌面打开文件,这里也可以看见四个文件已经存在
(2)生成.o文件
nivechen@nivechen-virtual-machine:~/homework3.2$ gcc -c A1.c A2.c
A2.o
(3)生成静态库.a文件
nivechen@nivechen-virtual-machine:~/homework3.2$ ar -crv libmyfile.a A1.o A2.o
(4)使用静态库文件,创建可执行程序,并运行
nivechen@nivechen-virtual-machine:~/homework3.2$ gcc -o output1 test.c libmyfile.a
nivechen@nivechen-virtual-machine:~/homework3.2$ ./output1
A1 print arg:1
A2 printf arg:test
(5)生成动态库.so文件
nivechen@nivechen-virtual-machine:~/homework3.2$ gcc -shared -fPIC -o libmyfile.so A1.o A2.o
注:.a和.so文件都是由.o文件生成的,所以这里不再生成.o文件,这里有多个.o文件,只需要依次写在后面即可。
(6)使用动态库文件,创建可执行程序,并运行
nivechen@nivechen-virtual-machine:~/homework3.2$ gcc -o output2 test.c libmyfile.so
nivechen@nivechen-virtual-machine:~/homework3.2$ sudo cp libmyfile.so /usr/lib
[sudo] nivechen 的密码:
nivechen@nivechen-virtual-machine:~/homework3.2$ ./output2
A1 print arg:1
A2 printf arg:test
注:我这里使用的cp命令,将libmyfile.so文件复制到/usr/lib下,上面用的mv,作用都差不多,cp是复制一份,mv是直接搬移过去。
3、对第一篇博客中由原来的一个x2x函数,扩展为两个函数,在进行相关静态库,动态库的操作
(1)编写相关函数sub1.c,sub2.c ,main.c,sub.h
nivechen@nivechen-virtual-machine:~/homework3.2$ gedit sub1.c
nivechen@nivechen-virtual-machine:~/homework3.2$ gedit sub2.c
nivechen@nivechen-virtual-machine:~/homework3.2$ gedit main.c
nivechen@nivechen-virtual-machine:~/homework3.2$ gedit sub.h
上图可以清楚看见编写的四个文件已经存在。
(2)生成相关的.o文件
nivechen@nivechen-virtual-machine:~/homework3.2$gcc -c main.c sub1.c sub2.c
(3)用ar工具,将x2x和x2y的目标文件生成一个.a文件
nivechen@nivechen-virtual-machine:~/homework3.2$ ar crv libmyfile1.a sub1.o sub2.o
a - sub1.o
a - sub2.o
(4)用gcc将main.o文件与生成的.a文件链接生成最终的可执行文件,并运行
nivechen@nivechen-virtual-machine:~/homework3.2$ gcc -o output3 main.o libmyfile1.a
nivechen@nivechen-virtual-machine:~/homework3.2$ ls
A1.c A1.o A2.c A2.o A.h libmyfile1.a libmyfile.a libmyfile.so main.c main.o output output1 output2 output3 sub1.c sub1.o sub2.c sub2.o sub.h test.c
nivechen@nivechen-virtual-machine:~/homework3.2$ ./output3
请输入两个整数
2
3
11.000000
(5)记录该可执行文件output3的大小
nivechen@nivechen-virtual-machine:~/homework3.2$ size output3
text data bss dec hex filename
2094 624 8 2726 aa6 output3
(6)将x2x和x2y的目标文件生成一个.so文件
nivechen@nivechen-virtual-machine:~/homework3.2$ gcc -shared -fPIC -o libmyfile1.so sub1.o sub2.o
nivechen@nivechen-virtual-machine:~/homework3.2$ ls
A1.c A2.c A.h libmyfile1.so libmyfile.so main.o output1 output3 sub1.o sub2.o test.c
(7)用gcc将main.o文件与生成的.so文件链接生成最终的可执行文件,并运行
nivechen@nivechen-virtual-machine:~/homework3.2$ gcc -o output4 main.o libmyfile1.so
nivechen@nivechen-virtual-machine:~/homework3.2$ sudo cp libmyfile1.so /usr/lib
[sudo] nivechen 的密码:
nivechen@nivechen-virtual-machine:~/homework3.2$ ./output4
请输入两个整数
2
3
11.000000
(8)记录该可执行文件output4的大小
nivechen@nivechen-virtual-machine:~/homework3.2$ size output4
text data bss dec hex filename
2298 656 8 2962 b92 output4
(9)对比output3和output4这两个文件
text data bss dec hex filename
2094 624 8 2726 aa6 output3
text data bss dec hex filename
2298 656 8 2962 b92 output4
二、gcc编译的内部操作
1.gcc常见命令和内部处理
(1)创建一个新的目录
nivechen@nivechen-virtual-machine:~$ mkdir homework3.3
nivechen@nivechen-virtual-machine:~$ cd homework3.3
程序示例
nivechen@nivechen-virtual-machine:~/homework3.3$ gcc test1.c -o output1//这里一步到位的指令,现在我们来看看分步操作
nivechen@nivechen-virtual-machine:~/homework3.3$ ./output1
Hello World!
(2)预处理
nivechen@nivechen-virtual-machine:~/homework3.3$ gcc -E test.c -o test.i
nivechen@nivechen-virtual-machine:~/homework3.3$ ls
output1 test.c test.i
注: test.i 文件中存放着 test.c 经预处理之后的代码。打开 test.i 文件。
也可以用 gcc -E test.c指令,这样会直接在命令行窗口中输出预处理后的代码. gcc 的-E 选项,可以让编译器在预处理后停止,并输出预处理结果。在本例中,预处理结果就是将stdio.h 文件中的内容插入到 test.c 中了。
(3)编译为汇编代码(Compilation)
nivechen@nivechen-virtual-machine:~/homework3.3$ gcc -S test.i -o test.s
(4) 汇编(Assembly)
nivechen@nivechen-virtual-machine:~/homework3.3$ gcc -c test.s -o test.o
(5)连接(Linking)
nivechen@nivechen-virtual-machine:~/homework3.3$ gcc test.o -o output2
(6)运行经过连接后产生的output2执行文件
nivechen@nivechen-virtual-machine:~/homework3.3$ ./output2
Hello World!
(7)用gcc相关命令连接动态库,并用size查看大小并记录
nivechen@nivechen-virtual-machine:~/homework3.3$ gcc test.c -o output3
nivechen@nivechen-virtual-machine:~/homework3.3$ ./output3
Hello World!
(8)用gcc相关命令连接静态库,并用size查看大小并记录
nivechen@nivechen-virtual-machine:~/homework3.3$ gcc -static test.c -o output4
nivechen@nivechen-virtual-machine:~/homework3.3$ ./output4
Hello World!
(9)用 ldd命令查看一个可执行程序依赖的共享库
nivechen@nivechen-virtual-machine:~/homework3.3$ ldd output3//动态库
linux-vdso.so.1 (0x00007fff0898a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f49da3d5000)
/lib64/ld-linux-x86-64.so.2 (0x00007f49da9c8000)
nivechen@nivechen-virtual-machine:~/homework3.3$ ldd output4//静态库文件
不是动态可执行文件
(10)对比两个可执行程序
nivechen@nivechen-virtual-machine:~/homework3.3$ size output3
text data bss dec hex filename
1515 600 8 2123 84b output3
nivechen@nivechen-virtual-machine:~/homework3.3$ size output4
text data bss dec hex filename
743329 20876 5984 770189 bc08d output4
可以看出链接静态库的执行文件中text,data,bss,dec代码尺寸都变大了
(11)ELF相关指令
(1)使用 readelf -S 查看其各个 section 的信息如下
(2)使用 objdump -D 对其进行反汇编如下:
(3)使用 objdump -S 将其反汇编并且将其 C 语言源代码混合显示出来:
$ gcc -o hello -g hello.c //要加上-g 选项
$ objdump -S hello
2.intel风格的汇编
(1)下载nasm编译器,编写hello.asm文件
nivechen@nivechen-virtual-machine:~/homework3.3$ sudo apt-get install nasm
nivechen@nivechen-virtual-machine:~$ gedit hello.asm
(2)生成目标文件,并且链接生成执行文件
nivechen@nivechen-virtual-machine:~$ nasm -f elf64 hello.asm
nivechen@nivechen-virtual-machine:~$ ld -s -o output hello.o
nivechen@nivechen-virtual-machine:~$ ./output
Hello, world!
(3)对比用nasm编译生成的可执行程序与gcc编译生成的可执行程序
nivechen@nivechen-virtual-machine:~$ size output//nasm编译
text data bss dec hex filename
34 14 0 48 30 output
nivechen@nivechen-virtual-machine:~$ size output1//gcc编译
text data bss dec hex filename
1515 600 8 2123 84b output1
三、实际代码与第三方库
1、curse库的主要函数和功能
int insertln(void); //插入空白行
int deleteln(void); //删除字符和空白行
int beep(void); //终端响铃
int erase(void); //在屏幕的每个位置写上空白字符
int clear(void); //使用一个终端命令来清除整个屏幕,内部调用了clearok来执行清屏操作,(在下次调用refresh时可以重现屏幕原文)
int clrtobot(void); //清除光标位置到屏幕结尾的内容
int attroff(chtype attribute); //启用或关闭某属性
int standend(void); //这两个表示更加通用的强调模式,通常映射为反白显示
int cbreak(); //设置cbreak模式,字符一键入,直接传给程序
2、Win10系统中,启用 “telnet client” 和"适用于Linux的Windows子系统"(
3、以游客身份体验一下即将绝迹的远古时代的 BBS
4、Ubuntu安装curses库,并查找安装的位置,体验小游戏
(1)安装curses库
nivechen@nivechen-virtual-machine:~$ sudo apt-get install libncurses5-dev
(2)查找头文件和库文件的安装位置
头文件位置:
库文件:
(3)体验小游戏
贪吃蛇游戏:
俄罗斯方块:
总结:
1、静态库与动态库区别
静态库文件在编译时就会连接到目标文件中,程序运行不需要再使用静态库文件。动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。程序在运行时,会在/usr/lib 和/lib 等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提
示错误而终止程序运行。所以动态库文件创建后,我们将文件 libmyhello.so 复制到目录/usr/lib 中。用mv file /usr/lib 或者cp file /usr/lib均可。
2、静态库与动态库的创建及其使用
(1)静态库和动态库创建
静态库和动态库都是用.o文件创建,所以我们先用gcc -c file.c创建file.o文件;然后用 ar -crv libmyhello.a file.o创建静态库 ;用 gcc -shared -fPIC -o libmyhello.so file.o创建动态库。如果静态库或者动态库由多个.o文件构成,直接写在后面即可
eg:ar -crv libmyhello.a file1.o file2.o
在静态库libmyhello.a的命名中,lib为前缀myhello为自己设计的文件名.a为静态库后缀;动态库类似lib为前缀myhello为自己设计的文件名.so为动态库后缀
(2)静态库和动态库使用
静态库的使用方法:
(1)gcc main.c libmyhello.a -o output
(2)先生成 main.o:
gcc -c main.c
再生成可执行文件:
gcc -o output main.o libmyhello.a
我这里推荐用这两种方法
动态库使用方法:
(1)gcc main.c libmyhello.so -o output
(2)先生成 main.o:
gcc -c main.c
再生成可执行文件:
gcc -o output main.o libmyhello.so
(3)“sub.h”
#ifndef SUB_H
#define SUB_H
float x2x(int a,int b);
float x2y(int a,int b);
#endif
注意这里对x2x,x2y函数定义的类型是float,在后面要与之相匹配,不然在后面编译连接会出错,这里千万注意。