一,用gcc生成动态库和静态库
1,用编辑器生成例子程序 hello.h,hello.c,main.c
(1)创建一个作业目录
(2)进入该目录
(3)创建hello.h文件,并且输入代码
#ifndef HELLO_H
#define HELLO_H
Void hello(const char *name);
#endif //HELLO_H
(4)创建hello.c文件并输入代码
#include <stdio.h>
void hello(const char *name)
{
printf("Hello %s!\n", name);
}
(5)创建main.c文件
#include "hello.h"
int main()
{
hello("everyone"); return 0;
}
2,将hello.c编辑成.o文件
(1)无论静态库,还是动态库,都是由.o 文件创建的。因此,我们必须将源程序 hello.c 通过 g cc 先编译成.o 文件。在系统提示符下键入以下命令得到 hello.o 文件。
(2)运行 ls 命令看看是否生存了 hello.o 文件
在 ls 命令结果中,我们看到了 hello.o 文件,本步骤操作完成。
下面我们先来看看如何创建静态库,以及使用它.
3,由.o文件创建静态库
(1)静态库文件名的命名规范是以 lib 为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将创建的静态库名为 myhello,则静态库文件名就是 libmyhello.a。在创建和使用静态库时, 需要注意这点。
创建静态库用 ar 命令。在系统提示符下键入以下命令将创建静态库文件libmyhello.a。
(2)运行ls查看是否生成对应程序
(3)ls命令中有libmyhello.a。
4,在程序中使用静态库
注意,gcc 会在静态库名前加上前缀 lib,然后追加扩展名.a 得到的静态库文件名来查找静态库文件。
(1)方法一:
运行查看结果
方法二:
查看结果
方法三:
先生成main.o,在生成可执行文件
查看结果
(2)我们删除静态库文件试试公用函数 hello 是否真的连接到目标文件 hello 中。
(3)运行 ls 命令查看是否生成文件libmyhello.a,删除后运行hello:
程序照常运行,静态库中的公用函数已经连接到目标文件中了。
我们继续看如何在 Linux 中创建动态库。我们还是从.o 文件开始。
二,静态库.a与.so库文件的生成与使用
1,回到上个目录,创建新的目录test2
2,然后用 vim、nano 或 gedit 等文本编辑器编辑生成所需要的四个文件 A1.c 、 A2.c、 A.h、test.c
(1)创建A1.c并输入代码
#include <stdio.h>
void print1(int arg){
printf("A1 print arg:%d\n",arg);
}
(2)创建A2.c并敲入代码
#include <stdio.h>
void print2(char *arg){
printf("A2 printf arg:%s\n", arg);
}
(3)创建A.h并敲入代码
#ifndef A_H
#define A_H
void print1(int);
void print2(char *);
#endif
(4)创建test.c并敲入代码
#include <stdlib.h>
#include "A.h"
int main()
{ print1(1);
print2("test"); exit(0);
}
3,静态库.a 文件的生成与使用
(1)生成目标文件(xxx.o)
(2)生成静态库.a 文件
(3)使用.a 库文件,创建可执行程序(若采用此种方式,需保证生成的.a 文件与.c 文件保存在同一目录下,
即都在当前目录下)
4,共享库.so 文件的生成与使用
(1)生成目标文件(xxx.o) (此处生成.o 文件必须添加"-fpic"(小模式,代码少),否则在生成.so文件时会出错)
(2)生成共享库.so 文件
(3)使用.so 库文件,创建可执行程序
运行 ldd test,查看链接情况,发现确实是找不到对应的.so 文件。
这是由于 linux 自身系统设定的相应的设置的原因,即其只在/lib and /usr/lib 下搜索对应的.so 文件,故需将对应 so 文件拷贝到对应路径。
(4)输入账号密码后,再次执行./test,即可成功运行。
5,编写程序生成动态库和静态库的练习并比较大小
(1)静态库的练习并记录大小
1>、编写一个x2x函数,一个x2y函数(功能自定),main函数代码将调用x2x和x2y;将这3个函数分别写成单独的3个 .c文件。
创建main.h文件,并敲入代码:
#ifndef MAIN_H
#define MAIN_H
float x2x(int a,int b);
float x2y(int a,int b);
#endif
创建sub1.c函数,并敲入代码
#include<stdio.h>
float x2x(int a,int b)
{
float c=0;
c=a+b;
return c;
}
创建sub2.c函数,并敲入代码
float x2y(int a,int b)
{
float c=0;
c=a/b;
return c;
}
创建main.c函数,并输入代码
#include<stdio.h>
#include"main.h"
void main()
{
int a=8,b=4;
printf("%d\n",x2x(a,b));
printf("%d\n",x2y(a,b));
}
2>、用gcc分别编译为3个.o 目标文件
3>、将x2x、x2y目标文件用 ar工具生成1个 .a 静态库文件
4>、用 gcc将 main函数的目标文件与此静态库文件进行链接,生成最终的可执行程序并记录文件的大小
我们会看到有警告。但可以不予理会
查看静态库生成的文件大小
(2)动态库练习并记录大小
1>、生成动态库
2>、使用.so 库文件,创建可执行程序
会有警告,但可以不理会
再次执行./main3,即可成功运行
查看生成文件的大小
通过比较发现静态库要比动态库要小很多,生成的可执行文件大小也存在较小的差别。
三,Linux GCC常用命令
1.简介:
GCC 原名为 GNU C 语言编译器(GNU C Compiler),因为它原本只能处理C语言。经过了这么多年的变换,GCC 很快地扩展,变得
可处理 C++。后来又扩展为能够支持更多编程语言,如Fortran、Pascal、Objective-C、Java、Ada、Go以及各类处理器架构上的汇编语言等,所以改名GNU编译器套件(GNU Compiler Collection),总的一句话说就是无处不在。
2,gcc命令下各选项的含义
E:仅作预处理,不进行编译、汇编和链接
-S:仅编译到汇编语言,不进行汇编和链接
-c:编译、汇编到目标代码(也就是计算机可识别的二进制)
-o:执行命令后文件的命名
-g:生成调试信息
-w:不生成任何警告
-Wall:生成所有的警告
3,gcc编译的四个步骤
预处理:gcc -E Test.c -o Test.i
编译: gcc -S Test.i -o Test.s
汇编: gcc -c Test.s -o Test.o
链接生成可执行文件: gcc Test.o -o Test
4,gcc常用的编译代码
(1)ar
用于创建静态链接库。为了便于初学者理解,在此介绍动态库与静态库 的概念:
如果要将多个.o 目标文件生成一个库文 件,则存 在两种类型的库,一种是静态库,另一种是动态库。
在 windows 中静态库是 以 .lib 为 后缀 的文 件 ,共享库 是以 .dll 为 后缀 的 文 件 。在 linux 中静 态库是以 .a 为 后 缀 的 文 件 , 共 享 库 是 以 .so 为 后 缀 的文件。
静 态 库 和 动 态 库 的 不 同 点 在 于 代 码 被 载 入 的 时 刻 不 同 。 静 态 库 的 代 码 在 编 译 过 程 中 已 经 被 载 入 可 执 行 程 序 , 因 此 体 积 较 大 。 共 享 库 的 代 码 是 在 可 执 行 程 序 运 行 时 才 载 入 内 存 的 , 在 编 译 过 程 中 仅 简 单 的 引 用 , 因 此 代 码 体 积 较 小 。 在 Linux 系 统 中 , 可 以 用 ldd 命 令 查 看 一 个 可 执 行 程 序 依 赖 的 共 享 库。
如 果 一 个 系 统 中 存 在 多 个 需 要 同 时 运 行 的 程 序 且 这 些 程 序 之 间 存 在 共 享 库,那么采用动态库的形式将更节省内存。
(2)、ld
用于链接。
(3)、as
用于汇编。
(4)、ldd
可以用于查看一个可执行程序依赖的共享库。
(5)、size
查看执行文件中各部分的大小。
(6)、addr2line:用 来将程序 地址转 换成其所 对应的程 序源文 件及所对 应的代 码 行,也可以得到所对应的函数。该工具将帮助调试器在调试的过程中定位对 应的源代码位置。
这里只介绍一部分,其余的可以自行翻阅专门的书籍查阅。
四,as汇编编译器
(由于本机自带nasm软件,就不写安装的过程了)
1,简介:
as汇编编译器针对的是AT&T汇编代码风格,Intel风格的汇编代码则可以用nasm汇编编译器编译生成执行程序
2,生成hello.asm文件,输入代码
hello.asm
section .data ; 数据段声明
msg db "Hello, world!", 0xA ; 要输出的字符串
len equ $ - msg ; 字串长度
section .text ; 代码段声明
global _start ; 指定入口函数
_start: ; 在屏幕上显示一个字符串
mov edx, len ; 参数三:字符串长度
mov ecx, msg ; 参数二:要显示的字符串
mov ebx, 1 ; 参数一:文件描述符(stdout)
mov eax, 4 ; 系统调用号(sys_write)
int 0x80 ; 调用内核功能
; 退出程序
mov ebx, 0 ; 参数一:退出代码
mov eax, 1 ; 系统调用号(sys_exit)
int 0x80 ; 调用内核功能
3,使用nasm -f elf64 hello.asm,会生成一个hello.o文件
执行./hello输出
我们会看到有一个警告,但是这个警告不会影响我们程序的运行,可以不用管它
4,使用ld -s -o hello hello.o ,生成一个可执行文件hello
5,执行./hello输出
6,查看hello文件的大小
五,Linux中的第三方库函数
1、Linux 系统中终端程序最常用的光标库(curses)
(1)光标库(curses)的主要函数功能
curses函数库能够优化光标的移动并最小化需要对屏幕进行的刷新,从而也减少了必须向字符终端发送的字符数目。
(2)一些基本函数名称及功能
从屏幕读取:
chtype inch(void); //返回光标位置字符
int instr(char *string); //读取字符到string所指向的字符串中
int innstr(char *string, int numbers);//读取numbers个字符到string所指向的字符串中
清除屏幕:
int erase(void);//在屏幕的每个位置写上空白字符
int clear(void);//使用一个终端命令来清除整个屏幕,相当于vi内的Ctrl+L
//内部调用了clearok来执行清屏操作,(在下次调用refresh时可以重现屏幕原文)
int clrtobot(void);//清除光标位置到屏幕结尾的内容
int clrtoeol(void);//清除光标位置到该行行尾的内容
窗口移动和更新屏幕
int mvwin(WINDOW *win, int new_y, int new_x); //移动窗口
int wrefresh(WINDOW *win);
int wclear(WINDOW *win);
int werase(WINDOW *win);
//类似于上面的refresh, clear, erase,但是此时针对特定窗口操作,而不是stdcur
int touchwin(WINDOW *win); //指定该窗口内容已改变、
//下次wrefresh时,需重绘窗口。利用该函数,安排要显示的窗口
int scrollok(WINDOW *win, bool flag); //指定是否允许窗口卷屏
int scroll(WINDOW *win); //把窗口内容上卷一行
窗口优化屏幕刷新
int wnoutrefresh(WINDOW *window_ptr);
//The wnoutrefresh subroutine determines which parts of the terminal may need updating.
int doupdate(void);
//The doupdate subroutine sends to the terminal the commands to perform any required changes.
2、体验即将绝迹的远古时代的 BBS (一个用键盘光标控制的终端程序)
在 win10 系统中,“控制面板”–>“程序”—>“启用或关闭Windows功能”,启用 “telnet client” 和"适用于Linux的Windows子系统"(后面会使用)。 然后打开一个cmd命令行窗口,命令行输入 telnet bbs.newsmth.net。
(1)打开控制版面,点击程序
(2)点击启用或关闭Windows功能
(3)启用 “telnet client” 和"适用于Linux的Windows子系统"
(4)打开一个cmd窗口
(5)命令行输入 telnet bbs.newsmth.net,即可体验(有的电脑可能需要重启过后才能开启执行命令)
(6)courses的安装
头文件(比如curses.h)和库文件的安装目录
curses函数库的头文件和库文件就被分别安装在/usr/include/和/usr/lib/下
3,创建一个小游戏,比如贪吃蛇
找到相应的代码,创建一个新的文件,利用curses编译代码
编译的命令是gcc mysnake1.0.c -lcurses -o mysnake1.0