Linux下静态库/动态库制作及gcc命令详解

(一)概述

       一个C语言程序从编写完成到执行需要经历预处理(生成.i)->编译(生成.s)->汇编(生成.o)->链接(生成可执行文件)几个步骤,如下图所示。
在这里插入图片描述

(二)gcc命令参数详解

这里推荐一篇讲解的比较全面的博客——GCC常用参数详解
我们最常用的gcc编译选项主要有以下几个:

  • (1) 无选项链接
    gcc test.o -o test
    将编译输出文件test.o链接成最终可执行文件test。

  • (2) -c
      只激活预处理->编译->汇编,也就是他只把程序做成obj文件。
      例子用法:
      gcc -c hello.c
      他将生成.o的obj文件
      gcc -c test.s
      将汇编输出文件test.s编译输出test.o文件。

  • (3) -S
      只激活预处理和编译,就是指把文件编译成为汇编代码。
      例子用法:
      gcc -S hello.c
      他将生成.s的汇编代码,你可以用文本编辑器察看
      gcc -S test.i
      将预处理输出文件test.i汇编成test.s文件

  • (4) -E
      只激活预处理,这个不生成文件,你需要把它重定向到一个输出文件里面.
      例子用法:
      gcc -E hello.c >; pianoapan.txt
      gcc -E hello.c | more
      一个hello word 也要与处理成1000+行的代码
      gcc -E test.c -o test.i

  • (5) -o
      制定目标名称,缺省的时候,gcc 编译出来的文件是a.out,很难听,如果你和我有同感,改掉它,哈哈
      例子用法:
      gcc -o hello.exe hello.c (哦,windows用习惯了)
      gcc -o hello.asm -S hello.c

  • (6) -l参数和-L参数
    -l参数就是用来指定程序要链接的库,-l参数紧接着就是库名,那么库名跟真正的库文件名有什么关系呢?就拿数学库来说,他的库名是m,他的库文件名是libm.so,很容易看出,把库文件名的头lib和尾.so去掉就是库名了。
    好了现在我们知道怎么得到库名了,比如我们自已要用到一个第三方提供的库名字叫libtest.so,那么我们只要把libtest.so拷贝到/usr/lib里,编译时加上-ltest参数,我们就能用上libtest.so库了(当然要用libtest.so库里的函数,我们还需要与libtest.so配套的头文件)。
    放在/lib和/usr/lib和/usr/local/lib里的库直接用-l参数就能链接了,但如果库文件没放在这三个目录里,而是放在其他目录里,这时我们只用-l参数的话,链接还是会出错,出错信息大概是:“/usr/bin/ld: cannot find -lxxx”,也就是链接程序ld在那3个目录里找不到libxxx.so,这时另外一个参数-L就派上用场了,比如常用的X11的库,它放在/usr/X11R6/lib目录下,我们编译时就要用-L/usr/X11R6/lib -lX11参数,-L参数跟着的是库文件所在的目录名。再比如我们把libtest.so放在/aaa/bbb/ccc目录下,那链接参数就是-L/aaa/bbb/ccc -ltest。

(三)静态链接和动态链接

以下是几篇讲的比较好的博客:

       静态链接就是在执行之前讲已经编译好的静态库加载链接合并到程序中,而动态链接则是在程序运行的时候动态加载链接库(当碰到内存中已经加载进来该库的时候,只进行虚拟地址空间的映射,这样可以提升内存利用率)。其实#include<stdio.h>只是定义了printf这些函数的函数原型,具体的代码要在链接的过程中才会被加载进来。

  • 下面使用静态库编译程序生成可执行代码
    在这里插入图片描述
    在这里插入图片描述
  • 下面使用动态库编译程序生成可执行代码
    在这里插入图片描述
  • 其中Pow_test.c的源代码如下:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
    unsigned int x, y;
    unsigned long long res;
    if((argc < 3) || (sscanf(argv[1], "%u", &x) != 1) || (sscanf(argv[2], "%u", &y) != 1))
    {
        printf("Usage: pow base exponent\n");
        exit(1);
    }
    res = unsgn_pow(x, y);
    printf("%u ^ %u = %u\n", x, y, res);
    return 0;
}

  • 其中unsgn_pow.c的源代码如下:
unsigned long long unsgn_pow(unsigned int x, unsigned int y)
{
    unsigned long long res = 1;
    if(!y)
    {
        res = 1;
    }
    else if(y == 1)
    {
        res = x;
    }
    else
    {
        res = x * unsgn_pow(x, y - 1);
    }
    return res;
}

猜你喜欢

转载自blog.csdn.net/qq_42968686/article/details/106059724