gcc编译过程及简单实战

gcc编译过程及简单项目实战

1、gcc编译过程

其实我们用c或者cpp的时候用到很多的库,那是别人写好的给我们直接使用的,极大的方便了我们,但是我们做项目的时候往往要自己将函数分离出来,然后再main函数中引用,就需要用到编译的过程了。
如图:
在这里插入图片描述
上图中我们的main文件跟input、calcu文件是一个文件夹,input、calcu文件是分别实现的两个功能一个是输入,一个是计算,main实现的是数字加法计算,但是为了功能分明我们就将他们分开,这样在大型项目中是低耦合表现。
项目源码:https://github.com/yjc-123/gcc-compile-process

首先我们要搞懂gcc编译的过程:
在这里插入图片描述

有四个过程:
预编译->编译->汇编->链接
这里我主要讲的是链接的过程
静态库
之所以成为【静态库】(.a),是因为在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。

  • 静态库对函数库的链接是放在编译时期完成的。
  • 程序在运行时与函数库再无瓜葛,移植方便。
  • 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。
    Linux静态库命名规则:
    必须是"lib[your_library_name].a":lib为前缀,中间是静态库名,扩展名为.a

动态库
因为静态库空间浪费比较严重,动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,接下来我们看看动态库
在这里插入图片描述

在这里插入图片描述

这就是链接的两种方式,最后我们看到实战是怎么回事。

2、实战

就拿我这个示例而言:
在这里插入图片描述

首先我们编写main函数。
main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "input.h" //导入库
#include "calcu.h"

extern int input(); //引入input.h中的函数
extern int calcu(int a,int b); //引入calcu中的函数

int main(int argc, char ** argv){
    
    

        int input_num_1 = input();
        int input_num_2 = input();

        printf("input over\n");
        int sum;
        sum = calcu(input_num_1, input_num_2);
        printf("calcu successful ,the sum is :%d\n",sum);
        return 0;
}

input.c

#include <stdio.h>
#include <stdlib.h>
int input(){
        int a;
        printf("input num:");
        scanf("%d",&a);
        return a;
} 

calcu.c

#include <stdio.h>
#include <stdlib.h>

int calcu(int a, int b){
    
    
        int sum;
        sum = a+b;
        return sum;
}

上面是主要实现功能的c文件,但是main在引用的时候并不会引用到c文件,而是用到他们写成的头文件。
calcu.h

#ifndef _CALCU_H
#define _CALCU_H

int calcu(int a, int b);

#endif

input.h

#ifndef _INPUT_H
#define _INPUT_H

int input();

#endif

这两个头文件是负责声明函数的作用,因为在main.c引入了这两个头文件,只不过实现是在input.c、calcu.c中。
接下来就是每个问价的Makefile文件了。
Makefile_input

CC = gcc

libinput.so:
        $(CC) -fPIC -shared input.c -o libinput.so
        sudo cp libinput.so /usr/lib
        sudo cp libinput.so /usr/bin
clean:
        rm -rf libinput.so

Makefile_calcu

CC = gcc
  
libcalcu.so:
        $(CC) -fPIC -shared calcu.c -o libcalcu.so
        sudo cp libcalcu.so /usr/lib
        sudo cp libcalcu.so /usr/bin

clean:
        rm -rf libcalcu.so                      

上面两个makefile的作用是生成动态库,并将动态库复制到系统库中去。
接下来看生成最终Makefile的文件:

CC = gcc
  
main:
        $(CC) main.c \
                -I ./input -L ./input -linput \
                -I ./calcu -L ./calcu -lcalcu \
                -o main
clean:
        rm -rf main

这里需要用到gcc -I、-L、-l三个参数,后面分别接头文件的位置、动态库的文件夹、动态库。
强调一下为什么要sudo cp libcalcu.so /usr/lib用这个语句,因为默认的我们在运行的时候,程序会在usr/lib中去寻找此动态库文件,如果不存在就会报错,至于为什么还需要指定因为我们运行的时候需要用到。

猜你喜欢

转载自blog.csdn.net/qq_45125250/article/details/112182503