c文件 :
[root@db-172-16-3-150 zzz]# cat a.c
#include
#include "a.h"
void display() {
fprintf(stdout, "this is display function in a.c\n");
}
头文件 :
[root@db-172-16-3-150 zzz]# cat a.h
void display();
生成静态库 :
首先要生成object file.
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g -c ./a.c -o a.o
gcc 简述 :
DESCRIPTION
When you invoke GCC, it normally does preprocessing, compilation, assembly and linking. The "overall options"
allow you to stop this process at an intermediate stage. For example, the -c option says not to run the
linker. Then the output consists of object files output by the assembler.
这里使用了-c , 所以输出的是对象文件, 没有去调用linker(ld).
接下来要把object file a.o打包到静态库liba.a, 注意命名规则 :
[root@db-172-16-3-150 zzz]# ar -rcs liba.a ./a.o
查看这个静态库文件包含了哪些对象文件:
[root@db-172-16-3-150 zzz]# ar -t liba.a
a.o
查看liba.a静态库文件里面的symbols :
[root@db-172-16-3-150 zzz]# nm liba.a
a.o:
0000000000000000 T display // 这个是display函数
U fwrite
U stdout
2. 动态库 :
与静态库不一样的地方, 创建object file时需要加-fPIC 参数.
PIC是position-independent code的缩写, 为什么要这么做呢? 原因是和操作系统加载动态库的方式有关, 如果程序调用动态库时内核不是将动态库加载到内存, 而程序要通过offset去获取动态库中的代码段时, 可能会有问题, PIC是要解决这个问题的。
如下 :
-fpic
Generate position-independent code (PIC) suitable for use in a shared library, if supported for the target
machine. Such code accesses all constant addresses through a global offset table (GOT). The dynamic
loader resolves the GOT entries when the program starts (the dynamic loader is not part of GCC; it is part
of the operating system). If the GOT size for the linked executable exceeds a machine-specific maximum
size, you get an error message from the linker indicating that -fpic does not work; in that case, recompile
with -fPIC instead. (These maximums are 8k on the SPARC and 32k on the m68k and RS/6000. The 386 has no
such limit.)
Position-independent code requires special support, and therefore works only on certain machines. For the
386, GCC supports PIC for System V but not for the Sun 386i. Code generated for the IBM RS/6000 is always
position-independent.
-fPIC
If supported for the target machine, emit position-independent code, suitable for dynamic linking and
avoiding any limit on the size of the global offset table. This option makes a difference on the m68k,
PowerPC and SPARC.
Position-independent code requires special support, and therefore works only on certain machines.
接下来创建object file :
c文件 :
[root@db-172-16-3-150 zzz]# cat a.c
#include
#include "a.h"
void display() {
fprintf(stdout, "this is display function in a.c\n");
}
头文件 :
[root@db-172-16-3-150 zzz]# cat a.h
void display();
生成object file :
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g -fPIC -c ./a.c -o a.o
这个object file 也可以直接使用 :
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./b.c a.o -o b
[root@db-172-16-3-150 zzz]# ./b
this is display function in a.c
接下来就生成
包含a.o的动态库文件liba.so吧 :
如果生成a.o时未加-fPIC, 创建liba.so将报错 :
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g -shared a.o -o liba.so
/usr/bin/ld: a.o: relocation R_X86_64_32 against `a local symbol' can not be used when making a shared object; recompile with -fPIC
a.o: could not read symbols: Bad value
collect2: ld returned 1 exit status
所以必须加上-fPIC :
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g -fPIC -c ./a.c -o a.o
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g -shared a.o -o liba.so
【命名规则】
静态库 :
lib?.a
动态库 :
lib?.so
【使用】
不管是动态还是静态库, 编译时都是使用 "-L目录名" "-l库名"
如果库文件放在系统的库文件目录中(如/usr/lib), 则不需要使用
"-L目录名"指出这个库文件在哪里.
或者配置LD_LIBRARY_PATH(linux)或PATH(windows)
静态库和动态库在生成bin文件的使用是一样的 :
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g b.c -L. -la -o b
注意c文件一定要放在库文件前面, 否则可能会报错. b.c -L. -la 如果改成 -L. -la b.c 就可能报错.
-L 表示库文件在什么目录找.
-l 表示需要用到那个库
如果动态库和静态库都有的情况下会使用哪个呢?
如 :
-rw-r--r-- 1 root root 6168 Aug 15 10:26 liba.a
-rwxr-xr-x 1 root root 8465 Aug 15 10:56 liba.so
默认使用的是动态库 :
[root@db-172-16-3-150 zzz]# ll
total 40
-rw-r--r-- 1 root root 110 Aug 15 09:58 a.c
-rw-r--r-- 1 root root 16 Aug 15 09:58 a.h
-rw-r--r-- 1 root root 6064 Aug 15 11:09 a.o
-rw-r--r-- 1 root root 56 Aug 15 09:58 b.c
-rw-r--r-- 1 root root 6208 Aug 15 11:09 liba.a
-rwxr-xr-x 1 root root 8449 Aug 15 11:10 liba.so
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g b.c -L. -la -o b
[root@db-172-16-3-150 zzz]# ./b
./b: error while loading shared libraries: liba.so: cannot open shared object file: No such file or directory
[root@db-172-16-3-150 zzz]# export LD_LIBRARY_PATH=.
[root@db-172-16-3-150 zzz]# ll
显然使用动态库编译的bin文件b要比使用静态库的小(
8185 bytes
).
total 48
-rw-r--r-- 1 root root 110 Aug 15 09:58 a.c
-rw-r--r-- 1 root root 16 Aug 15 09:58 a.h
-rw-r--r-- 1 root root 6064 Aug 15 11:09 a.o
-rwxr-xr-x 1 root root 8185 Aug 15 11:14 b
-rw-r--r-- 1 root root 56 Aug 15 09:58 b.c
-rw-r--r-- 1 root root 6208 Aug 15 11:09 liba.a
-rwxr-xr-x 1 root root 8449 Aug 15 11:10 liba.so
[root@db-172-16-3-150 zzz]# ./b
this is display function in a.c
使用-static强制静态编译.
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g -static b.c -L. -la -o b
[root@db-172-16-3-150 zzz]# ll
total 640
-rw-r--r-- 1 root root 110 Aug 15 09:58 a.c
-rw-r--r-- 1 root root 16 Aug 15 09:58 a.h
-rw-r--r-- 1 root root 6064 Aug 15 11:09 a.o
-rwxr-xr-x 1 root root 609720 Aug 15 11:14 b
-rw-r--r-- 1 root root 56 Aug 15 09:58 b.c
-rw-r--r-- 1 root root 6208 Aug 15 11:09 liba.a
-rwxr-xr-x 1 root root 8449 Aug 15 11:10 liba.so
[root@db-172-16-3-150 zzz]# ./b
this is display function in a.c
// 修改LD_LIBRARY_PATH后依旧可用使用, 说明却是已经不是动态状态了. 但是文件硕大(609720 bytes). 不建议使用.
[root@db-172-16-3-150 zzz]# export LD_LIBRARY_PATH=/usr/lib
[root@db-172-16-3-150 zzz]# ./b
this is display function in a.c
说明 :
-static
On systems that support dynamic linking, this prevents linking with the shared libraries. On other sys-
tems, this option has no effect.
使用静态库编译出来b的大小(9973 bytes) :
[root@db-172-16-3-150 zzz]# mv liba.so libb.so
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g b.c -L. -la -o b
[root@db-172-16-3-150 zzz]# ll -a
total 64
drwxr-xr-x 2 root root 4096 Aug 15 11:18 .
drwxr-x--- 16 root root 4096 Aug 9 11:22 ..
-rw-r--r-- 1 root root 110 Aug 15 09:58 a.c
-rw-r--r-- 1 root root 16 Aug 15 09:58 a.h
-rw-r--r-- 1 root root 6064 Aug 15 11:09 a.o
-rwxr-xr-x 1 root root 9973 Aug 15 11:18 b
-rw-r--r-- 1 root root 56 Aug 15 09:58 b.c
-rw-r--r-- 1 root root 6208 Aug 15 11:09 liba.a
-rwxr-xr-x 1 root root 8449 Aug 15 11:10 libb.so
【注意】
1. 有书说动态库的名字修改后不能使用, 如liba.so 改成libb.so 使用-lb编译也无法使用. 实际测试可用使用.
[root@db-172-16-3-150 zzz]# mv liba.so libb.so
[root@db-172-16-3-150 zzz]# gcc -O3 -Wall -Wextra -Werror -g b.c -L. -lb -o b
[root@db-172-16-3-150 zzz]# ./b
./b: error while loading shared libraries: libb.so: cannot open shared object file: No such file or directory
[root@db-172-16-3-150 zzz]# export LD_LIBRARY_PATH=.
[root@db-172-16-3-150 zzz]# ./b
this is display function in a.c
【参考】
http://en.wikipedia.org/wiki/Linker_(computing)
http://en.wikipedia.org/wiki/Shared_library
man ar, nm, gcc
ar :
r Insert the files member... into archive (with replacement). This operation differs from q in that any pre-
viously existing members are deleted if their names match those being added.
If one of the files named in member... does not exist, ar displays an error message, and leaves undisturbed
any existing members of the archive matching that name.
By default, new members are added at the end of the file; but you may use one of the modifiers a, b, or i
to request placement relative to some existing member.
The modifier v used with this operation elicits a line of output for each file inserted, along with one of
the letters a or r to indicate whether the file was appended (no old member deleted) or replaced.
c Create the archive. The specified archive is always created if it did not exist, when you request an
update. But a warning is issued unless you specify in advance that you expect to create it, by using this
modifier.
s Write an object-file index into the archive, or update an existing one, even if no other change is made to
the archive. You may use this modifier flag either with any operation, or alone. Running ar s on an
archive is equivalent to running ranlib on it.
t Display a table listing the contents of archive, or those of the files listed in member... that are present
in the archive. Normally only the member name is shown; if you also want to see the modes (permissions),
timestamp, owner, group, and size, you can request that by also specifying the v modifier.
If you do not specify a member, all files in the archive are listed.
If there is more than one file with the same name (say, fie) in an archive (say b.a), ar t b.a fie lists
only the first instance; to see them all, you must ask for a complete listing---in our example, ar t b.a.
查看一个静态库文件里面包含了哪些对象文件 :
[root@db-172-16-3-150 lib]# cd /usr/lib
[root@db-172-16-3-150 lib]# ar -t libz.a
adler32.o
compress.o
crc32.o
gzio.o
uncompr.o
deflate.o
trees.o
zutil.o
inflate.o
infback.o
inftrees.o
inffast.o
查看库文件中的symbol信息 :
[root@db-172-16-3-150 lib]# nm ./libz.a
adler32.o:
0000000000000000 T adler32
0000000000000390 T adler32_combine
compress.o:
0000000000000000 r .LC0
U _GLOBAL_OFFSET_TABLE_
0000000000000000 T __i686.get_pc_thunk.bx
00000000000000f0 T compress
0000000000000020 T compress2
0000000000000000 T compressBound
U deflate
U deflateEnd
U deflateInit_
.......
这里标记的意思可参考man nm
[root@db-172-16-3-150 zzz]# nm liba.so
0000000000200660 a _DYNAMIC
0000000000200800 a _GLOBAL_OFFSET_TABLE_
w _Jv_RegisterClasses
0000000000200638 d __CTOR_END__
0000000000200630 d __CTOR_LIST__
0000000000200648 d __DTOR_END__
0000000000200640 d __DTOR_LIST__
0000000000000628 r __FRAME_END__
0000000000200650 d __JCR_END__
0000000000200650 d __JCR_LIST__
0000000000200828 A __bss_start
w __cxa_finalize@@GLIBC_2.2.5
0000000000000570 t __do_global_ctors_aux
00000000000004a0 t __do_global_dtors_aux
0000000000200658 d __dso_handle
w __gmon_start__
0000000000200828 A _edata
0000000000200838 A _end
00000000000005a8 T _fini
0000000000000438 T _init
0000000000000480 t call_gmon_start
0000000000200830 b completed.6145
0000000000000550 T display
0000000000200828 b dtor_idx.6147
0000000000000520 t frame_dummy
U fwrite@@GLIBC_2.2.5
U stdout@@GLIBC_2.2.5
-O3 代码优化,级别3
-Wall 警告
-Wextra 额外警告
-Werror 将警告当做error处理
-g 包含debug信息到bin文件
-L 指出LIBRARY检索目录
-I 指出头文件检索目录
-l 指出库名字