使用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
相關文章
相關標籤/搜索