编译器背后的故事
一、可执行程序的组装
1.用gcc生成静态库和动态库
(1) 第 1 步:编辑生成例子程序 hello.h、hello.c 和 main.c。
先创建一个作业目录,保存本次练习的文件。
#mkdir test1
#cd test1
然后用 vim文本编辑器编辑生成所需要的 3 个文件。
程序1:
#ifndef HELLO_H
#define HELLO_H
void hello(const char *name);
#endif //HELLO_H
程序2:
#include <stdio.h>
void hello(const char *name)
{
printf("Hello %s!\n", name);
}
程序3:
#include "hello.h"
int main()
{
hello("everyone");
return 0;
}
(2) 第 2 步:将 hello.c 编译成.o 文件。
在系统提示符下键入以下命令得到 hello.o 文件。
gcc -c hello.c
我们运行 ls 命令看看是否生存了 hello.o 文件
在 ls 命令结果中,我们看到了 hello.o 文件
(3) 第 3 步:由.o 文件创建静态库。
创建静态库用 ar 命令。在系统提示符下键入以下命令将创建静态库文件 libmyhello.a。
ar -crv libmyhello.a hello.o
我们同样运行 ls 命令查看结果:
ls
hello.c hello.h hello.o libmyhello.a main.c
(4) 第 4 步:在程序中使用静态库。
下面先生成目标程序 hello,然后运行 hello 程序。
# gcc -o hello main.c -L. –lmyhello
运行结果
删除静态库文件
# rm libmyhello.a
rm: remove regular file `libmyhello.a'? y
# ./hello
Hello everyone!
#
程序照常运行
在 Linux 中创建动态库
(5) 第 5 步:由.o 文件创建动态库文件
在系统提示符下键入以下命令得到动态库文件 libmyhello.so
gcc -shared -fPIC -o libmyhello.so hello.o
使用is命令
# ls
hello.c hello.h hello.o libmyhello.so main.c
(6) 第 6 步:在程序中使用动态库
我们先运行 gcc 命令生成目标文件,再运行
# gcc -o hello main.c -L. -lmyhello
# ./hello
./hello: error while loading shared libraries: libmyhello.so: cannot open shar
ed object file: No such file or directory
运行结果
再来创建静态库文件 libmyhello.a 和动态库文件 libmyhello.so
# gcc -c hello.c
# ar -cr libmyhello.a hello.o (或-cvr )
# gcc -shared -fPIC -o libmyhello.so hello.o
# ls
hello.c hello.h hello.o libmyhello.a libmyhello.so main.c
运行 gcc 命令来使用函数库 myhello 生成目标文件 hello,并运行程序 hello
# gcc -o hello main.c -L. –lmyhello
# ./hello
./hello: error while loading shared libraries: libmyhello.so: cannot open shar
ed object file: No such file or directory
2.静态库应用
除了x2x函数之外,再扩展写一个x2y函数(功能自定),main函数代码将调用x2x和x2y ;将这3个函数分别写成单独的3个 .c文件,并用gcc分别编译为3个.o 目标文件;将x2x、x2y目标文件用 ar工具生成1个 .a 静态库文件, 然后用 gcc将 main函数的目标文件与此静态库文件进行链接,生成最终的可执行程序,记录文件的大小
(1)建立文件
#gedit sub1.c
#gedit sub2.c
#gedit main.c
(2)函数的编写
sub1.c
float x2x(float a, float b) {
return a * b;
}
sub2.c
float x2y(float a, float b) {
return a - b;
}
main.c
#include<stdio.h>
extern float x2x(float a, float b);
extern float x2y(float a, float b);
int main() {
float a = 3;
float b = 2;
printf("ax2xb=%f\n",x2x(a,b));
printf("ax2yb=%f\n",x2y(a,b));
}
(3)编译.o文件并建立连接
#gcc -c sub1.c
#gcc -c sub2.c
#gcc -c main.c
ls
运行结果
(4)生成静态库文件
#ar -crv 1.a sub1.o sub2.o
程序结果
文件大小
3.动态库应用
(1)建立文件
#rm 1.a
#rm sub1
ls
(2)建立动态库文件链接
#gcc -shared -fPIC -o 2.so sub1.o sub2.o
运行结果
4.总结
以上可见,静态库的文件大小略大于动态库的文件大小
二、Gcc不是一个人在战斗
1.Linux Gcc常用命令
(1)编译
//test.c
#include <stdio.h>
int main(void)
{
printf("Hello World!\n");
return 0;
}
(2)预处理
gcc -E test.c -o test.i
运行结果
(3)编译为汇编代码
gcc -S test.i -o test.s
(4)汇编
gcc -c test.s -o test.o
(5)连接
gcc test.o -o test
(6)多个程序文件的编译
假设有一个由 test1.c 和 test2.c 两个源文件组成的程序,为了对它们进行编译,并最终生成可执行程序 test,可以使用下面这条命令:
gcc test1.c test2.c -o test
如果同时处理的文件不止一个,深究起来,上面这条命令大致相当于依次执行如下三条命令:
gcc -c test1.c -o test1.o
gcc -c test2.c -o test2.o
gcc test1.o test2.o -o test
(7)检错
gcc -pedantic illcode.c -o illcode
除了-pedantic 之外,GCC 还有一些其它编译选项也能够产生有用的警告信息。这些选项大多以-W 开头,其中最有价值的当数-Wall 了,使用它能够使 GCC 产生尽可能多的警告信息。
gcc -Wall illcode.c -o illcode
在编译程序时带上-Werror 选项,那么 GCC 会在所有产生警告的地方停止编译,迫使程序员对自己的代码进行修改,如下:
gcc -Werror test.c -o test
运行结果
(8)库文件连接
编译可执行文件
gcc –c –I /usr/dev/mysql/include test.c –o test.o
连接
gcc –L /usr/dev/mysql/lib –lmysqlclient test.o –o test
(9)强制链接时使用静态链接库
默认情况下, GCC 在链接时优先使用动态链接库,只有当动态链接库不存在时才考虑使用静态链接库,如果需要的话可以在编译时加上-static 选项,强制使用静态链接库。
在/usr/dev/mysql/lib 目录下有链接时所需要的库文件 libmysqlclient.so 和 libmysqlclient.a,为了让GCC 在链接时只用到静态链接库,可以使用下面的命令:
gcc –L /usr/dev/mysql/lib –static –lmysqlclient test.o –o test
2.nasm安装和应用
(1)安装
sudo apt-get install nasm//安装nasm
nasm -version//查看版本
(2)应用
编译
nasm -f elf64 hello.asm
连接
ld -s -o hello hello.o
运行
./hello
运行结果
nasm比gcc生成的文件要小
三、借助第三方库函数完成代码设计
1.光标库
函数名 | 功能 |
---|---|
initscr() | 初始化curses库和tty |
endwin() | 关闭curses并重置tty |
refresh() | 使屏幕按照你的意图显示 |
addstr(s) | 在当前位置画字符串s |
addch(c) | 在当前位置画字符c |
clear() | 清屏 |
2.BBS
在 win10 系统中,“控制面板”–>“程序”—>“启用或关闭Windows功能”,启用 “telnet client” 和"适用于Linux的Windows子系统"(后面会使用)。 然后打开一个cmd命令行窗口,命令行输入 telnet bbs.newsmth.net,以游客身份体验一下即将绝迹的远古时代的 BBS
3.安装curses库
代码如下
sudo apt-get install libncurses5-dev
安装完成
4.贪吃蛇游戏
(1)建立文件
(2)游戏运行
四、总结
此次任务较多,实仿较简单,安装过程遇到了一些困难,整个过程持续时间较长。