Windows与Linux动态链接库区别概述
Windows与Linux对动态链接库的实现虽然思想相同,但是使用方式却有些不同。下表总结了这一区别。
| linux gcc |
windows vc
|
|
生成静态库
|
gcc -c calc.c -o calc.o
ar
rcs libcalc.a calc.o
|
cl /c calc.c
lib /OUT:calc.lib calc.obj
|
|
使用静态库
|
gcc test.c libcalc.a -o test
或
gcc test.c -L. -lcalc -o test
|
cl test.c calc.lib
|
gcc 有-l选项可以以它要求的名称查找库。
|
生成动态库
|
gcc -c calc.c -o calc.o
gcc -shared calc.c -o libcalc.so
|
cl /c calc.c
link /DLL calc.obj
或
lib /DLL /def:calc.def /OUT:calc.lib
|
linux下动态链接库的符号信息包含在so文件当中,Windows虽然在dll和生成的lib当中都包含一份符号表信息,但是链接的时候只可使用lib当中的符号。
|
使用动态库 |
gcc test.c ./libcalc.so
或
gcc test.c -L. -lcalc -o test
|
cl test.c calc.lib
|
|
静态链接库与动态链接库混合使用 | gcc main.c ./libcalc.a -lm |
cl test.c a.lib b.lib
|
windows无论链接动态库还是静态库都指定lib即可,在选择使用动态连接还是静态链接的时候由代码当中的__declspec(dllimport)决定,这句代码要求一个符号必须使用动态链接库
|
库的名称约束
| 静态库以libname.a方式命名。 动态库以libname.so方式命名。 若不遵循这两个规则,那么gcc -l选项便无法找到指定的库。 |
静态库以
name
.lib方式命名。
动态库以 name .dll方式命名。
动态库符号文件
name
.lib方式命名
|
linux下对动态链接库和静态链接库的名称要求以lib开头(当然也可以不必以lib开头),而Windows则无此约定。
|
Linux链接库的使用
测试程序如下:
- /*calc.c*/
- int val = 10;
- static int inner_val = 20;
- int Add(int a,int b)
- {
- return a + b;
- }
- /*test.c*/
- #include <stdio.h>
- extern int val;
- extern int Add(int a,int b);
- int main()
- {
- printf("val:%d\n",val);
- printf("4 + 4:%d\n",Add(4,4));
- return 0;
- }
静态链接库的使用
生成可重定向文件
gcc创建静态链接库的方式如下,这并不局限于Linux,如在Cygwin下也是如此。
- $gcc -c calc.c -o calc.o
在C语言当中被static修饰的变量或函数是私有的,因为在calc.c当中val与Add符号未被static修饰,所以可以在任意的其它模块当中使用val变量或调用Add函数,这意味着val变量是全局的,它的值可以被任何链接到它的一个模块更改。我们可以通过readelf查看calc.o的符号信息,从中可以看出inner_val被LOCAL修饰,而val和Add被GLOBAL修饰。
- $ readelf -s calc.o
- Symbol table '.symtab' contains 11 entries:
- Num: Value Size Type Bind Vis Ndx Name
- 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
- 1: 00000000 0 FILE LOCAL DEFAULT ABS calc.c
- 2: 00000000 0 SECTION LOCAL DEFAULT 1
- 3: 00000000 0 SECTION LOCAL DEFAULT 2
- 4: 00000000 0 SECTION LOCAL DEFAULT 3
- 5: 00000004 4 OBJECT <span style="color:#ff0000;">LOCAL </span>DEFAULT 2 inner_val
- 6: 00000000 0 SECTION LOCAL DEFAULT 5
- 7: 00000000 0 SECTION LOCAL DEFAULT 6
- 8: 00000000 0 SECTION LOCAL DEFAULT 4
- 9: 00000000 4 OBJECT <span style="color:#ff0000;">GLOBAL </span>DEFAULT 2 val
- 10: 00000000 13 FUNC <span style="color:#ff0000;">GLOBAL </span>DEFAULT 1 Add
创建归档文件
- $ar rcs libcalc.a calc.o
- $ ar -t /usr/lib/i386-linux-gnu/libc.a
- init-first.o
- libc-start.o
- sysdep.o
- version.o
- check_fds.o
- libc-tls.o
- elf-init.o
- ...
- $ nm /usr/lib/i386-linux-gnu/libc.a | head -200
- init-first.o:
- U abort
- U __ctype_init
- U _dl_fpu_control
- U _dl_non_dynamic_init
- 00000090 T _dl_start
- w _dl_starting_up
- U __environ
- U __fpu_control
- U __init_misc
- 00000004 C __libc_argc
- 00000004 C __libc_argv
- 00000000 T __libc_init_first
- U __libc_init_secure
- 00000000 D __libc_multiple_libcs
- U __setfpucw
- libc-start.o:
- U __assert_fail
- U __cxa_atexit
- U _dl_aux_init
- U _dl_discover_osversion
- U _dl_osversion
- ...
使用静态链接库
使用方式一,显式链接
- gcc test.c ./libcalc.a -o test
- gcc test.c -L. -static -lcalc -o test
隐式链接静态库的时候必须指定-static选项,若没有指定-static选项,gcc在链接的时候使用动态链接库的算法进行链接,这虽然不会出报错,但是在程序执行的时候实际其会要求加载libcalc.so,由于我们没有libcalc.so,所以程序无法执行。
另外,我们可以更改一下程序以验证上面提到的使用static修饰的变量不可被外部模块链接的说法。这里不做示例。
在链接静态库的时候还有一个陷阱需要注意。由于gcc链接的时候内部算法约束,参数的传递顺序对链接的成功起至关重要。上面的例子当中使用如下方式链接会报错。
- gcc ./libcalc.a test.c -o test
动态链接库的使用
创建动态链接库
众所周知,动态链接库的一个主要目的是允许多个正在运行的进程共享存储器中相同的库代码,因而解决宝贵的存储器资源。gcc创建一个动态链接库十分简单,并没有像VC一样单独导出一个可链接的符号文件(见Windows下动态链接库的使用),我们可以在main.c代码当中使用任何非static修饰的变量或函数。
- gcc -shared calc.c -o libcalc.so
- $ readelf -s libcalc.so
- Symbol table '<span style="color:#ff0000;">.dynsym</span>' contains 13 entries:
- Num: Value Size Type Bind Vis Ndx Name
- 0: 00000000 0 NOTYPE LOCAL DEFAULT UND
- 1: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
- 2: 00000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@GLIBC_2.1.3 (2)
- 3: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
- 4: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
- 5: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
- 6: 00002020 0 NOTYPE GLOBAL DEFAULT 21 _edata
- 7: 00002018 4 OBJECT GLOBAL DEFAULT 21 val
- 8: 00002024 0 NOTYPE GLOBAL DEFAULT 22 _end
- 9: 00002020 0 NOTYPE GLOBAL DEFAULT 22 __bss_start
- 10: 0000050b 13 FUNC GLOBAL DEFAULT 11 Add
- 11: 00000380 0 FUNC GLOBAL DEFAULT 9 _init
- 12: 00000518 0 FUNC GLOBAL DEFAULT 12 _fini
- Symbol table '<span style="color:#ff0000;">.symtab</span>' contains 56 entries:
- Num: Value Size Type Bind Vis Ndx Name
- ...
- 38: 00000000 0 FILE LOCAL DEFAULT ABS
- 39: 000003e0 4 FUNC LOCAL DEFAULT 11 __x86.get_pc_thunk.bx
- 40: 00002014 0 OBJECT LOCAL DEFAULT 21 __dso_handle
- 41: 00001f0c 0 OBJECT LOCAL DEFAULT 18 _DYNAMIC
- 42: 00002020 0 OBJECT LOCAL DEFAULT 21 __TMC_END__
- 43: 00002000 0 OBJECT LOCAL DEFAULT 20 _GLOBAL_OFFSET_TABLE_
- 44: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTab
- 45: 00002020 0 NOTYPE GLOBAL DEFAULT 21 _edata
- 46: 00000518 0 FUNC GLOBAL DEFAULT 12 _fini
- 47: 00000000 0 FUNC WEAK DEFAULT UND __cxa_finalize@@GLIBC_2.1
- 48: 00002018 4 OBJECT GLOBAL DEFAULT 21 val
- 49: 00000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
- 50: 00002024 0 NOTYPE GLOBAL DEFAULT 22 _end
- 51: 00002020 0 NOTYPE GLOBAL DEFAULT 22 __bss_start
- 52: 00000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
- 53: 00000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
- 54: 0000050b 13 FUNC GLOBAL DEFAULT 11 Add
- 55: 00000380 0 FUNC GLOBAL DEFAULT 9 _init
使用动态链接库
第一种方式,显式链接
- gcc test.c ./libcalc.so
第二种方式,隐式链接
- gcc test.c -L. -lcalc -o test
- $ gcc test.c libcalc.so -o test
- $ ./test
- ./test: error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory
- $