gcc编译过程、使用命令详解(多文件编译、动态库、静态库)

gcc 编译命令

gcc编译通常分为4步骤处理
gcc编译过程、使用命令详解(多文件编译、动态库、静态库)_第1张图片gcc编译过程、使用命令详解(多文件编译、动态库、静态库)_第2张图片

创建文件hello.c

vim hello.c

测试代码

#include 


/* 执行命令: ./hello dengzj 
 * argc = 2
 * argv[0] = ./hello
 * argv[1] = dengzj
 */
#define xxx 10

/*argc:argument count  argv: argument value*/
int main(int argc, char **argv)
{
        if (argc >= 2)
                printf("Hello, %s,%d!\n", argv[1],xxx);
        else
                printf("Hello, world! %d\n",xxx);
        return 0;
}

gcc基本用法:gcc [option] [filenames]
编译hello.c文件 不加参数 默认输出为a.out

gcc hello.c

gcc编译过程、使用命令详解(多文件编译、动态库、静态库)_第3张图片
通常编译hello.c 使用-o参数可命名文件,将hello.c编译后命名为hello,即gcc命令后的-o参数的位置不固定,带-o参数后面一定接编译后的文件名这也是后续编译.c文件使用最多的命令。结果如下图所示

gcc hello.c -o hello
//或者
gcc -o hello hello.c

gcc编译过程、使用命令详解(多文件编译、动态库、静态库)_第4张图片

以上是学习中大多数时候使用的gcc编译指令,上面代码是一步到位的得到链接后的文件,其本质是要经过预处理 编译 汇编 链接这四步。即下面的4行指令依次完成

gcc -E -o hello.i hello.c 
gcc -S -o hello.s hello.i 
gcc -c -o hello.o hello.s 
gcc -o hello hello.o

1、预处理 gcc -E

最开始编写的hello.c文件变为hello.i文件, 展开宏、头文件,替换条件编译,删除注释、空行、空白。

gcc -E -o hello.i hello.c

在这里插入图片描述
打开文件里面就是一些头文件路径即展开宏。打开hello.i文件,在一般模式下输入/main后会看见源代码的xxx宏已经展开后得到数值为10。
gcc编译过程、使用命令详解(多文件编译、动态库、静态库)_第5张图片

2、编译 gcc -S

.i文件编译得到汇编形式的hello.s,检测语法规范,消耗时间、系统资源最多。同样用vim 打开文件可查看到汇编形式的代码。

gcc -S -o hello.s hello.i 

gcc编译过程、使用命令详解(多文件编译、动态库、静态库)_第6张图片
同理,灵活使用,可将上面融合为一步。gcc -S -o hello.s hello.c,可直接将hello.c文件编译为汇编形式,并命名为hello.s

3、汇编 gcc -c

得到hello.o文件,将汇编指令翻译成机器指令,进入则看到的是一堆机器码。

 gcc -c -o hello.o hello.s 

gcc编译过程、使用命令详解(多文件编译、动态库、静态库)_第7张图片

4、链接 无参数

数据段合并 将生成的.obj文件与库文件.lib等文件链接,生成可执行文件(.exe文件) ,地址回填。
将hell.o和库文件、系统文件的一系列.o文件进行链接。

gcc -o hello hello.o

最终输出的文件结果
在这里插入图片描述

*选看

查看gcc完整编译过程,带-v参数,输出结果复制到Notepad++打开

gcc -o hello hello.o -v

gcc编译过程、使用命令详解(多文件编译、动态库、静态库)_第8张图片
仅供自学参考,谢谢!

进阶用法

多文件编译组成一个应用程序

在这里插入图片描述

vim main.c
#include 
#include "sub.h"

int main(int argc, char *argv[])
{
       int i;
       printf("Main fun!\n");
       sub_fun();
       return 0;
}

vim sub.c
void sub_fun(void)
{
       printf("Sub fun!\n");
}
vim sub.h
void sub_fun(void);

一条命令,处理多个源文件。以此类推,10个文件编写,在后面加10个文件名即可。实际工程中,文件一多起来就不行了(需要makefile),因此gcc的缺点是对所有文件都需要再一次处理

gcc -o test main.c sub.c

在这里插入图片描述
当多文件(比如100个文件)进行编译,其中一个文件需要修改时,因为只是某些修改文件的内容,而后其余文件却要被重新处理一次,使用上面这条命令就显得很浪费时间。因此可以使用-c命令只进行前三个步骤(预处理、编译、汇编),最后再统一链接。
即:

gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
gcc -o test main.o sub.o

这样在只修改某些文件时,只需要执行对应的-c命令即可。

-I的作用

main.c的头文件中,<>代表在系统目录或工具链的默认的指定路径目录下查找,编译时加上-v选项可查看, ""代表在当前目录下查找文件。
gcc编译过程、使用命令详解(多文件编译、动态库、静态库)_第9张图片
利用-I来指定目录,修改mian.c 该为

#include 
#include 

int main(int argc, char *argv[])
{
       int i;
       printf("Main fun!\n");
       sub_fun();
       return 0;
}

在这里插入图片描述
-I ./ 在当前路径查看头文件,编译成功。

gcc -c -o main.o main.c -I ./

静态库

每个需要使用静态库的程序都要将整个静态库编译到可执行程序中,若静态库50M,10个程序要500M。
库函数本地化,优点调用速度快,缺点是系统资源消耗大,多用于对时间要求较高的核心程序。
未链接sub.c文件,文件编译时可以将其他文件生成.o文件制作成库来使用
ar rcs lib库名.a 一系列.o文件
在这里插入图片描述
解决办法:当然可以在代码后加入sub.c文件进行链接生成test文件
或者制作静态库,先生成sub.o文件。

gcc -c -o sub.o sub.c

制作静态库

ar crs libsub.a sub.o

使用静态库

gcc -o test main.o libsub.a

gcc编译过程、使用命令详解(多文件编译、动态库、静态库)_第10张图片

动态库

机制:多个可执行程序共享一份库文件(共享代码、不共享数据)。
使用 gcc -shared 制作动态库。
gcc -shared -o lib库名.so add.o sub.o div.o
制作动态库

gcc -shared -o libsub.so sub.o

使用动态库1

gcc -o test2 main.o libsub.so

gcc编译过程、使用命令详解(多文件编译、动态库、静态库)_第11张图片
链接可执行程序时,指定所使用的动态库, -l:指定动态库名 -L:指定动态库路径。
使用动态库2

gcc -o test2 main.o -L./ -lsub

运行时,需要添加动态指定路径,:./添加当前路径

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./
./test2

总结:
1、动态库是否加载到内存,取决于程序是否运行
2、动态库每次加载的位置不固定
3、动、静态库共存时,编译器默认使用动态库

头文件依赖

查看c.c文件的依赖

gcc -M c.c

gcc编译过程、使用命令详解(多文件编译、动态库、静态库)_第12张图片

利用-MF指令生成名为c.e的依赖文件

gcc -M -MF c.e c.c

gcc编译过程、使用命令详解(多文件编译、动态库、静态库)_第13张图片
即生成依赖文件 且编译

gcc -c -o c.o c.c -MD -MF c.e

你可能感兴趣的:(开发语言,linux,c语言,ubuntu,汇编)