使用gcc生成静态库和动态库

盘古开天辟地。咱们写了个程序,想要给终端输出一些内容,不可避免地咱们须要使用系统库,在咱们写程序的过程当中咱们常常会碰到须要使用库的过程,不管是系统库仍是第三方库,咱们统称为lib库。linux

而库的连接分为两种,分别有静态库和动态库。bash

1. 静态库

静态库能够看做一堆的目标文件的集合,可能包含了不少函数的实现。在linux最经常使用的C语言静态库libc位于/usr/lib/libc.a,它由成百上千个C语言程序,好比输入输出有printf.o,scanf.o,文件操做有fread.o,fwrite.o等等。把这些零散的文件提供给使用者会形成不便,因而一般人们用ar压缩程序将这些目标文件压缩到一块儿,而后对这些文件进行编号和索引,最后造成了libc.a这个文件。函数

运行命令查看其中包含的内容,而后过滤查看freadcode

$  ar -t /usr/lib/x86_64-linux-gnu/libc.a | grep fread
iofread.o
__freading.o
__freadable.o
iofread_u.o
fread_chk.o
fread_u_chk.o

若是咱们要在其中寻找printf.o文件可使用命令索引

$ objdump -t /usr/lib/x86_64-linux-gnu/libc.a | grep printf.o
vfprintf.o:     文件格式 elf64-x86-64
vprintf.o:     文件格式 elf64-x86-64
reg-printf.o:     文件格式 elf64-x86-64
fprintf.o:     文件格式 elf64-x86-64
printf.o:     文件格式 elf64-x86-64
snprintf.o:     文件格式 elf64-x86-64
sprintf.o:     文件格式 elf64-x86-64
asprintf.o:     文件格式 elf64-x86-64
dprintf.o:     文件格式 elf64-x86-64
vfwprintf.o:     文件格式 elf64-x86-64
fxprintf.o:     文件格式 elf64-x86-64
iovsprintf.o:     文件格式 elf64-x86-64
fwprintf.o:     文件格式 elf64-x86-64
swprintf.o:     文件格式 elf64-x86-64
vwprintf.o:     文件格式 elf64-x86-64
wprintf.o:     文件格式 elf64-x86-64
vswprintf.o:     文件格式 elf64-x86-64
vasprintf.o:     文件格式 elf64-x86-64
iovdprintf.o:     文件格式 elf64-x86-64
vsnprintf.o:     文件格式 elf64-x86-64
obprintf.o:     文件格式 elf64-x86-64

能够看到printf.o文件就在其中。it

假如以咱们写的helloworld.c程序为例io

#include <stdio.h>

int main(int argc, char *argv[])
{
    printf("Hello,World!\n");
    return 0;
}

默认状况下直接运行class

$ gcc helloworld.c -o helloworld

会进行动态连接,咱们查看生成的文件大小变量

$ ls -l helloworld
-rwxr-xr-x 1 gnc gnc 8304 10月 11 15:06 helloworld

能够看到大小为8303bytes,咱们使用选项-static来使gcc进行静态连接:gcc

$ gcc -static helloworld.c -o helloworld

查看大小

$ ls -l helloworld
-rwxr-xr-x 1 gnc gnc 844704 10月 11 15:09 helloworld

能够看到大小显著变大。

2. 动态库

静态连接好处就是连接完成之后,运行程序不须要原来的支持库,但缺点是文件大小较大,而且更新困难。

因此出现了动态连接,也就是不要静态地进行连接,而是等到动态运行时再进行连接。动态连接的符号定位是发生在运行时首先进行地址空间分配,而后再来运行程序。

具体的连接过程也比较复杂,咱们只须要知道如何来建立这种动态库便可。

3. gcc建立静态和动态库

源文件add.c

/* add.h */
void setSummand(int summand);
int  add(int summand);

/* add.c */
#include <stdio.h>

int gSummand;


void setSummand(int summand) {
  gSummand = summand;
}

int add(int summand) {
  return gSummand + summand;
}

void __attribute__ ((constructor)) initLibrary(void) {
 //
 // Function that is called when the library is loaded
 //
    printf("Library is initialized\n"); 
    gSummand = 0;
}
void __attribute__ ((destructor)) cleanUpLibrary(void) {
 //
 // Function that is called when the library is »closed«.
 //
    printf("Library is exited\n"); 
}

源文件answer.c

/* answer.h */
int answer();

/* answer.c */
#include "add.h"

int answer() {

  setSummand(20);
  return add(22);  // Will return 42 (=20+22)

}

源文件main.c

#include <stdio.h>
#include "add.h"
#include "answer.h"

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

  setSummand(5);

  printf("5 + 7 = %d\n", add(7));

  printf("And the answer is: %d\n", answer());

  return 0;
}

而后咱们建立目录.bin/static./bin/shared

完成之后的目录结构以下

$ tree
.
├── add.c
├── add.h
├── answer.c
├── answer.h
├── bin
│   ├── shared
│   └── static
└── main.c

3 directories, 5 files

咱们运行命令生成目标文件

$ gcc -c       main.c        -o bin/main.o

# 静态库
$ gcc -c       add.c    -o bin/static/add.o
$ gcc -c       answer.c -o bin/static/answer.o

# 动态库
gcc -c -fPIC add.c    -o bin/shared/add.o
gcc -c -fPIC answer.c -o bin/shared/answer.o

3.1 建立静态库

运行命令

$ ar rcs bin/static/libtq84.a bin/static/add.o bin/static/answer.o

将两个目标文件打包压缩为一个静态库文件。

静态连接

$ gcc bin/main.o -Lbin/static -ltq84 -o bin/static-main

运行

$ ./bin/static-main 
Library is initialized
5 + 7 = 12
And the answer is: 42
Library is exited

3.2 建立动态库

运行命令

$ gcc -shared bin/shared/add.o bin/shared/answer.o -o bin/shared/libtq84.so

而后进行动态连接

$ gcc  bin/main.o -Lbin/shared -ltq84 -o bin/use-shared-library

运行

$ ./bin/use-shared-library 
./bin/use-shared-library: error while loading shared libraries: libtq84.so: cannot open shared object file: No such file or directory

会提示找不到动态连接库,咱们须要修改LD_LIBRARY_PATH变量来指向咱们的动态库路径

export LD_LIBRARY_PATH=$(pwd)/bin/shared

而后再运行

./bin/use-shared-library 
Library is initialized
5 + 7 = 12
And the answer is: 42
Library is exited

就能够了,固然你也能够选择将该动态库放置到路径/usr/lib下,运行下面的命令

sudo mv bin/shared/libtq84.so /usr/lib
sudo chmod 755 /usr/lib/libtq84.so
相关文章
相关标签/搜索