嵌入式零基础第三次练习

用 gcc 生成 .a 静态库和 .so 动态库

例子1:写三个文件,包括,函数定义的头文件hello.h,函数内容的c文件hello.c,还有测试用的主程序c文件main.c。
程序为:

 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;
     } 
     程序作用是调用hello输出Hello everyone

一、先使用文件编辑器编辑三个文件:
在这里插入图片描述
二、无论静态库,还是动态库,都是由.o 文件创建的。因此,我们必须将源程序 hello.c 通过 gcc 先编译成.o 文件:
在这里插入图片描述
三、由.o 文件创建静态库,在系统提示符下键入以下命令将创建静态库文件 libmyhello.a:
在这里插入图片描述
四、在程序中使用静态库:
在这里插入图片描述
五、检测公用函数 hello 是否真的连接到目标文件 hello 中,删除静态库,测试程序是否正常运行:
在这里插入图片描述
删除静态库之后程序正常运行,说明内部函数已经被连接到了目标代码中。
六、以hello.o创建动态库,在系统提示符下键入以下命令得到动态库文件 libmyhello.so:
在这里插入图片描述
七、在程序中使用动态库,将文件 libmyhello.so 复制到目录/usr/lib 中,不然调用动态库时系统会找不到这个文件,调用并生成hello2可执行文件,并运行:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
注意:是将动态库文件复制到用户的lib目录下,原来的目录下也要保留动态库文件,否则系统也会找不到动态库,导致编译失败。

Linux下静态库.a与.so库文件的生成与使用

一、准备阶段;创建四个文件,分别为

A1.c:
#include <stdio.h>
 void print1(int arg)
 {
    
     printf("A1 print arg:%d\n",arg); }
 
A2.c:
#include <stdio.h>
void print2(char *arg)
{
    
     printf("A2 printf arg:%s\n", arg); }

A.h:
#ifndef A_H 
#define A_H 
void print1(int); 
void print2(char *); 
#endif

test.c:
#include <stdlib.h> 
#include "A.h" 
int main()
{
    
     print1(1); 
print2("test"); 
exit(0); }

二、静态库的生成:静态库是由.o文件生成的,所以先编译c文件成为.o文件:
在这里插入图片描述
三、接下来由两个.o文件生成名称为libafile.a的静态库
在这里插入图片描述
四、调用库文件编译然后执行
在这里插入图片描述
五、共享库.so 文件的生成:动态库也是根据.o文件来生成的,所以先编译c文件成为.o文件:
在这里插入图片描述
六、根据.o文件生成动态库:
在这里插入图片描述
在生成动态库之后还要将库拷贝到用户的lib下,否则系统无法找到库,导致无法调用。

七、使用.so 库文件,创建可执行程序:
在这里插入图片描述

关于静态库的生成与使用的自主练习

题目:除了x2x函数之外,再扩展写一个x2y函数(功能自定),main函数代码将调用x2x和x2y ;将这3个函数分别写成单独的3个 .c文件,并用gcc分别编译为3个.o 目标文件;将x2x、x2y目标文件用 ar工具生成1个 .a 静态库文件, 然后用 gcc将 main函数的目标文件与此静态库文件进行链接,生成最终的可执行程序
一、先编写三个主程序:
在这里插入图片描述
二、编译文件生成.o文件:
在这里插入图片描述
三、根据x2x.o和x2y.o生成静态库文件:
在这里插入图片描述

四、调用静态文件连接mian.c生成可执行文件,并运行:
在这里插入图片描述

关于动态库的生成与使用的自主练习

一、在上个静态库练习题的基础上进行动态库练习,同样根据.o文件生成动态库:
在这里插入图片描述
二、将动态库拷贝到用户的lib目录中:

在这里插入图片描述
三、调用静态文件连接mian.c生成可执行文件,并运行:
在这里插入图片描述

GCC常用命令

一、gcc的详细编译过程, 预处理:
在这里插入图片描述
二、编译为汇编代码:
在这里插入图片描述
三、汇编:
在这里插入图片描述
四、 连接并运行:
在这里插入图片描述
五、 多个程序文件的编译:

gcc -c test1.c -o test1.o
gcc -c test2.c -o test2.o
gcc test1.o test2.o -o test

六、库文件连接

gcc –c –I /usr/dev/mysql/include test.c –o test.o
gcc –L /usr/dev/mysql/lib –lmysqlclient test.o –o test

七、强制链接时使用静态链接库

gcc –L /usr/dev/mysql/lib –static –lmysqlclient test.o –o test

GCC的汇编与Binutils的共同使用以及 ELF 文件

一、预处理后,.i文件部分字段:
在这里插入图片描述
二、编译文件后.s文件中的部分字段:
在这里插入图片描述
三、使用Binutils中的as命令进行汇编:
在这里插入图片描述
四、连接:
1、使用动态库进行链接:
在这里插入图片描述

2、使用静态库进行链接:
在这里插入图片描述
通过对比发现生成的ELF文件由于两种不同的连接形式尺寸差距变得很大,由此可见,动态相比静态更节省空间。
五、查看ELF文件各部分信息:
在这里插入图片描述
六、反汇编 ELF:

objdump -D hello 

在这里插入图片描述

nasm命令的使用以及生成的可执行文件大小的对比

在这里插入图片描述
在这里插入图片描述
明显对比执行文件的大小,对比发现使用nasm命令编译生成的可执行文件要小得多。

curses的主要函数功能,写出几个基本函数名称及功能

curses工作在屏幕,窗口和子窗口之上。屏幕是设备全部可用显示面积(对终端是该窗口内所有可用字符位置),窗口与具体例程有关。如基本的stdscr窗口等

关于屏幕的常用部分代码:
int addch(const chtype char_to_add);//当前位置添加字符
int addchstr(chtype *const string_to_add);//当前位置添加字符串

int printw(char *format, ...);//类似与printf
int refresh(void);//刷新物理屏幕
int box(WINDOW *win_ptr, chtype vertical, chtype horizontal);
//围绕窗口绘制方框,用vertical绘制垂直边,用horizontal绘制水平边

int insch(chtype char_to_insert);   //插入一个字符(已有字符后移)

在 win10 系统中体验BBS

在 win10 系统中,“控制面板”–>“程序”—>“启用或关闭Windows功能”,启用 “telnet client” 和"适用于Linux的Windows子系统"。 然后打开一个cmd命令行窗口,命令行输入 telnet bbs.newsmth.net
在这里插入图片描述

安装curses库,以及头文件和库文件的安装位置

安装代码:
sudo apt-get install libncurses5-dev 

在这里插入图片描述

用gcc编译生成一个终端游戏并运行(贪吃蛇游戏)。

写入贪吃蛇源代码,gcc编译并运行可执行文件:
在这里插入图片描述

总结

此次试验对于入门初步了解静态库和动态库相当重要,在静态库、动态库的创建与使用中,深刻了解到了静态库和动态库的差别,与两者工作状态的差别,这让我对库文件的基本构成和工作原理有了更多的认识,特别是可执行程序的组装过程,在摸索过程中,能明显感受到,难点在于动态库在拷贝时要启用管理员权限,并且原来目录下也要存在动态库。另外在了解ELF文件格式,汇编语言格式,在编译中与gcc共同工作的工具。还有gcc编译时的分布执行实验,让我对gcc的工作原理也有了新的见解。

猜你喜欢

转载自blog.csdn.net/rude_dragon/article/details/109045771