Linux中gcc的简单操作

一、可执行程序的组装

参考:一个程序从源代码到可执行程序的过程

二、用gcc生成生成静态库和动态库

编辑生成程序 hello.h、hello.c 和 main.c

创建一个作业目录,输入:

mkdir test1

进入该目录输入:

cd test1

在这里插入图片描述
然后用 vim、nano 或 gedit 等文本编辑器编辑生成所需要的 3 个文件。
用vim,输入:

vim hello.h

进入vim编辑输入程序代码:

#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.c 编译成.o 文件

无论静态库,还是动态库,都是由.o 文件创建的。因此,我们必须将源程序 hello.c 通过 g cc 先编译成.o 文件。输入代码:

gcc -c hello.c

运行ls命令查看生成hello.o文件
在这里插入图片描述
看到hello.o文件生成成功。

由.o 文件创建静态库

静态库文件名的命名规范是以 lib 为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将 创建的静态库名为 myhello,则静态库文件名就是 libmyhello.a。在创建和使用静态库时, 需要注意这点。创建静态库用 ar 命令。在系统提示符下键入以下命令将创建静态库文件 libmyhello.a。
输入命令:
ar -crv libmyhello.a hello.o
接着用ls命令查看文件是否生成:
在这里插入图片描述
ls 命令结果中有 libmyhello.a。
静态库制作完了,如何使用它内部的函数呢?接下来我们来看如何使用它内部的函数。

在程序中使用静态库

在使用到这些公用函数的源程序中包 含这些公用函数的原型声明,然后在用 gcc 命令生成目标文件时指明静态库名,gcc 将会从 静态库中将公用函数连接到目标文件中。
注意,gcc 会在静态库名前加上前缀 lib,然后追 加扩展名.a 得到的静态库文件名来查找静态库文件。
在上面编写的程序 main.c 中,我们包含了静态库的头文件 hello.h,然后在主程序 main 中直接调用公用函数 hello。下面先生成目标程序 hello,然后运行 hello 程序看看结果如何。

法一
gcc -o hello main.c -L. -lmyhello
法二
gcc main.c libmyhello.a -o hello
法二
gcc -o main.c	# 先生成 main.o
gcc -o hello main.o libmyhello.a

方法一:
出现了一个问题,找不到文件或目录
在这里插入图片描述
可以先运行rm命令删除libmyhello.a文件,在执行./hello
在这里插入图片描述

方法二:
在这里插入图片描述
方法三:
先生成main.o
在这里插入图片描述
然后输入代码:

gcc -o hello main.o libmyhello.a 

动态库连接时也可以这样做。
在这里插入图片描述
我们删除静态库文件试试公用函数 hello 是否真的连接到目标文件 hello 中了。

rm libmyhello.a

在这里插入图片描述
程序照常运行,静态库中的公用函数已经连接到目标文件中了。
我们继续看看如何在 Linux 中创建动态库。我们还是从.o 文件开始。

由.o 文件创建动态库文件

动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀 lib,但其 文件扩展名为.so。例如:我们将创建的动态库名为 myhello,则动态库文件名就是 libmyh ello.so。用 gcc 来创建动态库。
在系统提示符下键入以下命令得到动态库文件 libmyhello.so。
输入命令:

gcc -shared -fPIC -o libmyhello.so hello.o

在这里插入图片描述
动态库文件创建成功。

在程序中使用动态库

在程序中使用动态库和使用静态库完全一样,也是在使用到这些公用函数的源程序中包含 这些公用函数的原型声明,然后在用 gcc 命令生成目标文件时指明动态库名进行编译。我 们先运行 gcc 命令生成目标文件,再运行它看看结果。
输入命令:

gcc -o hello main.c -L. -lmyhello

出现错误:
在这里插入图片描述
快看看错误提示,原来是找不到动态库文件 libmyhello.so。程序在运行时, 会在/usr/lib 和/lib 等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提 示类似上述错误而终止程序运行。我们将文件 libmyhello.so 复制到目录/usr/lib 中,再试试。
输入命令:mv libmyhello.so /usr/lib
出现权限不够,这时可以先进入超级用户模式在输入上面那个命令
在这里插入图片描述
运行成功!

三、动态库和静态库生成可执行文件大小的对比

1、编写一个x2x函数,一个x2y函数(功能自定),main函数代码将调用x2x和x2y;
2、将这3个函数分别写成单独的3个 .c文件。
3、并用gcc分别编译为3个.o 目标文件;将x2x、x2y目标文件用 ar工具生成1个 .a 静态库文件, 然后用 gcc将 main函数的目标文件与此静态库文件进行链接,生成最终的可执行程序,记录文件的大小

静态库

创建一个t2文件
在这里插入图片描述

创建1.h文件并输入:

#ifndef S1_H
#define S1_H 
float x2x(int a, int b);
#endif //S1_H

在这里插入图片描述
在创建1.c文件并输入代码:

#include"1.h"

float x2x(int a, int b){
    
    
	return a + b;
}

在这里插入图片描述
创建2.h文件并输入代码:

#ifndef 2_H
#define 2_H 
float x2y(int a, int b);
#endif 

在这里插入图片描述

创建2.c文件并输入代码:

#include"2.h"
float x2y(int a, int b)
{
    
    
        return a * b;
}

在这里插入图片描述

创建mai.c文件并输入代码:

#include<stdio.h>
#include"1.h"
#include"2.h"
int main(){
    
    
	int a = 4, b = 9;
	printf("%d + %d = %f\n", a, b, x2x(a, b));
	printf("%d × %d = %f\n", a, b, x2y(a, b));
	return 0;
}

在这里插入图片描述

在这里插入图片描述
用静态库文件进行链接,生成可执行文件
先 将 sub1.c、sub2.c 编译成 .o文件输入命令:
gcc -c 1.c 2.c
ls
在这里插入图片描述
然后用 .o文件创建静态库输入命令:

ar -crv lib1.a 1.o
ar -crv lib2.a 2.o

在这里插入图片描述
最后使用静态库输入命令:

gcc main.c lib1.a lib2.a -o main1
./main1

在这里插入图片描述

动态库

首先用 .o文件创建动态库输入命令:

gcc -shared -fPIC -o lib1.so 1.o
gcc -shared -fPIC -o lib2.so 2.o

在这里插入图片描述
接着 在程序中使用动态库输入命令:

gcc main.c lib1.so lib2.so -o main2
sudo mv lib1.so /usr/lib
sudo mv lib2.so /usr/lib

在这里插入图片描述

两个可执行文件大小的比较

按上述方法由静态库链接生成的可执行文件,不是完全由静态库链接生成的,因为在 main.c 中调用的 stdio.h 是由动态链接的,所以需要重新由静态库链接生成一个可执行文件,否则可能将会出现静态库生成的可执行文件小于动态库生成的。
输入命令:

gcc -static main.c lib1.a lib2.a -o main1
size main1
ldd main1
size main2
ldd main2

在这里插入图片描述
size:用于查看文件大小

ldd:查看链接了那些动态库

四、gcc的常用命令及其编译工具中的软件

gcc的常用命令参考:

Linux GCC常用命令

在ubuntu中下载安装nasm和使用

输入命令查看有没有nasm

nasm -version

没有再输入:

sudo apt install nasm

在这里插入图片描述
在这里插入图片描述
下载成功!
把示例文件hello.asm复制到linux中:
在这里插入图片描述
建立一个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         ; 调用内核功能

然后输入命令:

nasm -f elf64 hello.asm
ld -s -o hello hello.o

在这里插入图片描述
然后汇编与C代码的编译生成的可执行程序大小对比输入命令:

size hello

在这里插入图片描述
在这里插入图片描述
结果对比发现直接由汇编编译生成的可执行程序比直接由C代码编译生成的可执行要小得多。

五、Linux中的第三方库函数

在Ubuntu中用 sudo apt-get install libncurses5-dev 安装curses库
在这里插入图片描述
找到头文件和库文件安装到那些目录输入:

whereis

在这里插入图片描述
光标库(curses)的主要函数功能:curses函数库能够优化光标的移动并最小化需要对屏幕进行的刷新,从而也减少了必须向字符终端发送的字符数目。

Linux 环境下C语言编译实现贪吃蛇游戏

创建文件并编辑
在这里插入图片描述
代码参考:

C语言编译实现贪吃蛇游戏代码
执行后
在这里插入图片描述

在这里插入图片描述

体验一下即将绝迹的远古时代的BBS

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

总结

通过此次实验了解如何用 gcc 生成静态库(.a)和动态库(.so),并且用静/动态库链接生成可执行文件,同时体验了远古时代的BBS,以及贪吃蛇游戏的乐趣。

借鉴的文章链接:
参考:一个程序从源代码到可执行程序的过程
gcc的常用命令参考:Linux GCC常用命令
贪吃蛇代码参考:C语言编译实现贪吃蛇游戏代码

猜你喜欢

转载自blog.csdn.net/qq_45321687/article/details/109057958