库文件实际上就是封装了一大堆的已经编译完成的代码文件,通过链接这个库而获取到响应函数实现。
gcc
-
编译选项
1)-c :指编译,不链接,生成目标文件 .o。
2) -S :只编译,不汇编,生成汇编代码 .S。
3) -E :只进行预编译/预处理,不做其他处理。
4) -o file:把输出文件输出到file里。
5) -g :在可执行程序中包含标准调试信息。
6) -v :打印出编译器内部编译各过程的命令行信息和编译器的版本。
7) -I dir :在头文件的搜索路径列表中添加dir目录
8) -L dir :在库文件的搜索路径列表中添加dir目录
9) -static :连接静态库(静态库也可以用动态库链接方式链接)
10) -llibrary :连接名为library的库文件(显示指定需要链接的动态库文件) -
编译流程
预处理:展开头文件,宏定义,条件编译处理等。通过gcc -E xx.c -o xx.i或者cpp xx.c生成。
编译:这里是一个狭义的编译意义,指的是将预处理后的文件翻译成汇编代码的过程。通过gcc -S xx.i生成。默认生成xx.s文件。
汇编:汇编即将上一步生成的汇编代码翻译成对应的二进制机器码的过程。通过gcc -c xx.s来生成xx.o文件。
链接:链接是将生成目标文件和其引用的各种符号等生成一个完整的可执行程序的过程。链接的时候会进行虚拟内存的重定向操作。
动态库与静态库的生成与使用
动态库:以 .so 为后缀,lib为前缀,由gcc编译器完成。
静态库:以 .a 为后缀,lib为前缀,由ar工具完成
- 生成
gcc -fPIC -c xx.c -o xx.o //生成目标文件
-fPIC :生成目标代码时产生位置无关代码。
不加 -fPIC 就会报错,加上之后就可以生成这个动态库。
//单个目标文件
gcc --share xx.o -o libxx.so //动态库
ar -cr libxx.a xx.o //静态库
//多个目标文件
gcc --share xx.o xx.o xx.o -o libxx.so //动态库
ar -cr libxx.a xx.o xx.o xx.o //静态库
-share:生成动态库而并非可执行程序。
-cr:-c 创建静态库、-r 模块替换。
- 使用
gcc main.c -o main -L . -lfile
1.生成可执行程序时–链接库文件的搜素路径。
1)生成一个可执行程序时,若需要链接一个第三方库,需要将这个库放置到指定路径下。
2)或者使用 export LIBRARY_PATH=. 环境变量的设置来设置哭的链接搜素路径。
3)gcc的 -L 选项,指定链接是库的搜索路径。
2.运行可执行程序时–动态库的加载搜索路径
1)程序运行时,若程序是动态链接生成,运行是需要到指定的目录下加载动态库 /lib64/usr/lib64…
2)也可以使用export LD_LIBRARY_PATH=. 环境变量的设置,来声明程序运行时库的加载路径。
使用当前路径下的自己生成的动态库,在lib1.c 和lib2.c中都只是打印“haha",我们将可执行文件文件main运行一下,得到了我们的预期结果。
二者的异同
不同:
1.动态库是运行时系统调用库函数实现链接,代码较小巧, 而静态库是在链接时复制到代码中,代码量较庞大,冗余度高。
2.正因为静态库这种方式也决定了它,在链接后不再依赖静态库存在,及即使静态库被删除程序依然可以正常运行,可移植性强。 而动态库因为是利用本机的库函数,所以可能移植到其他电脑会出现运行bug等问题,可移植性差。
3.二者的区别在于链接过程的差异,和代码被载入的时刻不同 。
4.动态库必须放在指定的目录下完成链接,而静态库给出链接文件路径即可 。
相同:
1.库文件中都不可以出现主main函数 。
2.这些库都是提供函数接口,满足功能的,不暴露源代码。
3.目的增加代码复用,可共享性,减小冗余。
库文件与可执行文件
1.只要是库文件,文件中就不可以有mian函数。 而可执行文件,必须有且只有一个mian函数。
2.无论是可执行文件还是库文件都需要编译至少到.o形式的机器代码文件。