动态库与静态库

静态库与动态库

我的博客
蒋炎岩老师的操作系统课程
本文例来自《深入理解计算机系统》英文书为《Computer Systems A Programmer's Perspective》即 CS APP.

静态库

源文件

main.c

#include <stdio.h>
#include "vector.h"

int x[2] = {1, 2};
int y[2] = {3, 4};
int z[2];

int main(void)
{
        addvec(x, y, z, 2);
        printf("z = [%d %d] \r\n", z[0], z[1]);

        return 0;
}

静态链接源文件 addvec.cmultvec.c

  • addvec.c

    int addcnt = 0;
    
    void addvec(int *x, int *y, int *z, int n)
    {
            int i;
            addcnt++;
    
            for(i = 0; i < n;i++)
            {
                    z[i] = x[i] + y[i];
            }
    }
    
  • multvec.c

    int multcnt = 0;
    
    void multvec(int *x, int *y, int *z, int n)
    {
            int i;
            multcnt++;
    
            for(i = 0; i < n; i++)
            {
                    z[i] = x[i] * y[i];
            }
    }
    

头文件 vector.h

#ifndef __VECTOR_H
#define __VECTOR_H

void addvec(int *x, int *y, int *z, int n);
void multvec(int *x, int *y, int *z, int n);

#endif

目录结构如下:

arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ ls
addvec.c  main.c  multvec.c  vector.h

生成静态库

在源码路径下执行如下命令,首先编译汇编源文件,生成目标文件,再使用目标文件生成静态库 libvector.a:

arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ gcc -c addvec.c multvec.c 
arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ ar rcs libvector.a addvec.o multvec.o

此时目录下有如下文件:

arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ ls
addvec.c  addvec.o  libvector.a  main.c  multvec.c  multvec.o  vector.h

链接生成可执行文件

执行如下命令首先编译 main.c 文件,再链接静态库,生成可执行文件 prog

arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ gcc -c main.c 
arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ gcc -static -o prog main.o ./libvector.a 

此时目录下有如下文件:

arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ ls
addvec.c  addvec.o  libvector.a  main.c  main.o  multvec.c  multvec.o  prog  vector.h

执行可执行文件

现在可执行生成的可执行文件,因为是静态链接,可执行文件包含所有自己需要的内容,这个可执行文件可以拷贝到本机的任意位置执行,也可以拷贝到相同环境的设备上去执行:

arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ ./prog 
z = [4 6] 

可以查看这个文件所包含的内容:

arv@arv-OptiPlex-7090:~/lib_temp/static_lib$ size prog 
   text    data     bss     dec     hex filename
 762186   20772    6112  789070   c0a4e prog

动态库

动态库例子中使用的源码与静态库中的一样。

生成动态链接库

执行如下命令生成动态链接库 libvector.so:

arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ gcc -shared -fpic -o libvector.so addvec.c multvec.c 

此时目录下有:

arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ ls
addvec.c  libvector.so  main.c  multvec.c  vector.h

生成可执行文件

执行如下命令生成依赖于动态库的可执行文件 prog1:

arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ gcc -o prog1 main.c ./libvector.so 

此时目录下有文件:

arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ ls
addvec.c  libvector.so  main.c  multvec.c  prog1  vector.h

执行可执行文件

在动态库同级目录下可以运行刚才生成的可执行文件:

arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ ./prog1 
z = [4 6] 

因为我们在编译可执行文件的时候,使用了 ./libvector.so 这样的字样,因此它的二进制文件中包含 ./libvector.so 这样的内容,执行这一可执行文件,它会在本级目录下查找这一动态库,因此可以执行。

如果使用如下的编译命令:

arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ gcc -o prog1 main.c libvector.so 

此时,即便在 libvector.so 同级目录下,这一文件也不能执行:

arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ ./prog1 
./prog1: error while loading shared libraries: libvector.so: cannot open shared object file: No such file or directory

可以将这个动态库导入到环境变量 LD_LIBRARY_PATH,中:

export LD_LIBRARY_PATH="/home/arv/lib_temp/dynamic_lib:$LD_LIBRARY_PATH"

此时,可以在任意位置执行这个新的可执行文件了:

arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ ./prog1 
z = [4 6] 

arv@arv-OptiPlex-7090:~/lib_temp/another_dir$ ./prog1 
z = [4 6] 

查看文件内容

arv@arv-OptiPlex-7090:~/lib_temp/dynamic_lib$ size prog1 
   text    data     bss     dec     hex filename
   1720     640      16    2376     948 prog1

使用我们的动态库

dll.c 源码

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

int x[2] = {1, 2};
int y[2] = {3, 4};
int z[2];

int main()
{
        void *handle;
        void (*addvec)(int *, int *, int *, int);
        char *error;
    
    	/* 注意到,因为之前我们已经将动态库导入到环境变量了 */
        handle = dlopen("libvector.so", RTLD_LAZY);
        if(!handle)
        {
                fprintf(stderr, "%s\r\n", dlerror());
                exit(1);
        }

        addvec = dlsym(handle, "addvec");
        if((error = dlerror()) != NULL)
        {
                fprintf(stderr, "%s\r\n", dlerror());
                exit(1);
        }

        addvec(x, y, z, 2);
        printf("z = [%d %d]\r\n", z[0], z[1]);

        if(dlclose(handle) <0)
        {
                fprintf(stderr, "%s\r\n", dlerror());
                exit(1);
        }

        return 0;
}

生成可执行文件

arv@arv-OptiPlex-7090:~/lib_temp/another_dir$ gcc -rdynamic -o prog2 dll.c -ldl

执行可执行文件

arv@arv-OptiPlex-7090:~/lib_temp/another_dir$ ./prog2 
z = [4 6]

查看系统调用过程

可以通过如下的小工具,分别查看静态库与动态库的可执行文件在执行时,所做的系统调用过程:

strace prog
posted @ 2022-04-27 20:38  ArvinDu  阅读(67)  评论(0编辑  收藏  举报