1、引言
1、Linux下的库
静态库和共享库(动态库),二者的不同点在于代码被载入的时刻不同。
静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。
共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。
2、库存在的意义
库是别人写好的现有的,成熟的,可以复用的代码,你可以使用但要记得遵守许可协议。
现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。
共享库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。
2、静态库
静态库的后缀是.a,它的产生分两步
Step 1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表
Step 2.ar命令将很多.o转换成.a,成为静态库
动态库的后缀是.so,它由gcc加特定参数编译产生。具体方法参见后文实例。
在 GNU/linux 系统中静态链接文件实际上就是多个 .o 文件的压缩包。假设我们有 cool.h cool.c 和 some.c 文件,要得到静态链接库 libcool.a。首先使用如下指令得到相应的 object 文件 cool.o 和 some.o:
gcc -c cool.c
gcc -c some.c
用这种方法生成的 object 文件称为 PDC 即位置相关代码(position-dependence code)。再使用如下指令可以得到静态链接文件 libcool.a:
ar -r libcool.a cool.o some.o
静态链接库 libcool.a 遵从 GNU/Linux 规定的静态链接库命名规范,必须是”libyour_library_name.a”
3、动态库
在 GNU/Linux 中动态链接文件,必需通过链接器 ld 生成。假设我们有 hot.c other.c 等文件要生成动态链接库 libhot.so 。首先使用如下指令得到相应的 object 文件 hot.o 和 some.o
gcc -fPIC -c hot.c
gcc -fPIC -c other.c
参数 -fPIC 指定生成的 object 文件为位置无关代码(position-independence code),只有 PIC 可以被用作生成动态链接库。然后使用如下指令得到动态库:
ld -Bshared -o libhot.so hot.o other.o
或者可以使用编译器的ld wrapper:
gcc -shared -o libhot.so hot.o other.o
也可以使用编译器直接生成动态库:
gcc -fPIC -shared -o libhot.so hot.c other.c
这里选项 -shared 指示目标文件的类型是动态链接库,动态库的命名规范是”libyour_library_name.so”
ldd 命令可以查看一个可执行程序依赖的共享库,
例如# ldd /bin/lnlibc.so.6
=> /lib/libc.so.6 (0×40021000)/lib/ld-linux.so.2
=> /lib/ld- linux.so.2 (0×40000000)
可以看到ln命令依赖于libc库和ld-linux库
1、创建动态库
目录/test/ include
lib1.h
#ifndef LIB1_H
#define LIB1_H
void lib1function(void);
void lib1_1function(void);
#endif
lib2.h
#ifndef LIB2_H
#define LIB2_H
void lib2function(void);
#endif
目录/test/src
lib1.c
#include<stdio.h>
#include "lib1.h"
void lib1function(void)
{
printf("lib1function\n");
}
void lib1_1function(void)
{
printf("lib1_1function\n");
}
lib2.c
#include<stdio.h>
#include "lib2.h"
void lib2function(void)
{
printf("lib2function\n");
}
makefile
CC=gcc
CXX=g++
AR=ar
TARGET=libmylib.a
DIR=./
INCLUDE=-I../include
SRC_C=$(wildcard *.c)
SRC_CPP=$(wildcard *.cpp)
DIR_C=$(notdir $(SRC_C))
DIR_CPP=$(notdir $(SRC_CPP))
OBJ_C=$(patsubst %.c,%.o,$(DIR_C) )
OBJ_CPP=$(patsubst %.cpp,%.o,$(DIR_CPP) )
all:$(TARGET)
mv $(TARGET) ../lib
$(TARGET):$(OBJ_C)
$(AR) -rs $(TARGET) $(OBJ_C) $(OBJ_CPP)
.cpp.o:
$(CXX) -c $^ $(INCLUDE)
.c.o:
$(CC) -c $^ $(INCLUDE)
clean:
rm -rf *.o *.a
创建目录lib
执行命令 $src#./make
在目录lib下生成libmylib.a
main.c
#include<stdio.h>
#include "lib1.h"
#include "lib2.h"
int main(void)
{
lib1function();
lib1_1function();
lib2function();
return 0;
}
makefile
CC=gcc
CXX=g++
AR=ar
TARGET=main
DIR=.
LIB=-L./lib -lmylib
INCLUDE=-I./include
SRC_C=$(wildcard *.c)
SRC_CPP=$(wildcard *.cpp)
DIR_C=$(notdir $(SRC_C))
DIR_CPP=$(notdir $(SRC_CPP))
OBJ_C=$(patsubst %.c,%.o,$(DIR_C) )
OBJ_CPP=$(patsubst %.cpp,%.o,$(DIR_CPP) )
SRC =main.c
all:$(TARGET)
$(TARGET): $(OBJ_C) $(OBJ_CPP)
$(CC) $(OBJ_C) $(LIB) -o $(TARGET)
.cpp.o:
$(CXX) -c $^ $(INCLUDE)
.c.o:
$(CC) -c $^ $(INCLUDE)
clean:
rm -rf *.o $(TARGET)
执行命令 test# ./makefile
结果在test目录下生成main
运行 #./main
# ./main
lib1function
lib1_1function
lib2function
2、创建动态库
修改两个Makefile
目录/test/src
CC=gcc
CXX=g++
AR=ar
TARGET=libmylib.so
DIR=./
INCLUDE=-I../include
SRC_C=$(wildcard *.c)
SRC_CPP=$(wildcard *.cpp)
DIR_C=$(notdir $(SRC_C))
DIR_CPP=$(notdir $(SRC_CPP))
OBJ_C=$(patsubst %.c,%.o,$(DIR_C) )
OBJ_CPP=$(patsubst %.cpp,%.o,$(DIR_CPP) )
all:$(TARGET)
mv $(TARGET) ../lib
$(TARGET):$(OBJ_C)
$(CC) -shared $(OBJ_C) $(OBJ_CPP) -o $(TARGET)
.cpp.o:
$(CXX) -c -fpic $^ $(INCLUDE)
.c.o:
$(CC) -c -fpic $^ $(INCLUDE)
clean:
rm -rf *.o *.a
test目录
Makefile
CC=gcc
CXX=g++
AR=ar
TARGET=main
DIR=.
LIB=./lib/libmylib.so
INCLUDE=-I./include
SRC_C=$(wildcard *.c)
SRC_CPP=$(wildcard *.cpp)
DIR_C=$(notdir $(SRC_C))
DIR_CPP=$(notdir $(SRC_CPP))
OBJ_C=$(patsubst %.c,%.o,$(DIR_C) )
OBJ_CPP=$(patsubst %.cpp,%.o,$(DIR_CPP) )
SRC =main.c
all:$(TARGET)
$(TARGET): $(OBJ_C) $(OBJ_CPP)
$(CC) $(OBJ_C) $(LIB) -o $(TARGET)
.cpp.o:
$(CXX) -c $^ $(INCLUDE)
.c.o:
$(CC) -c $^ $(INCLUDE)
clean:
rm -rf *.o $(TARGET)