c文件编译过程
- 预编译(展开头文件、去掉注释、宏处理)(
.c
->.i
) - 编译(
.i
->.s
) - 汇编 (
.s
->.o
) - 链接 (
.0
->app
)
基本指令
gcc
- -E:预处理将
.c
文件变为.i
文件(其实也是c
文件) - -S:编译,将
.i
文件变为.s
汇编文件 - -c:汇编,将
.c
文件变为.o
二进制文件 - -o:指定名称
- -g:
gdb
调试的时候需要加 - -D:在编译的时候指定一个宏
- -Wall:输出警告信息
- -On:优化等级,
n
为等级数目1
,2
,3
只有这三级
为什么要用库
- 保密:别人想使用你的代码功能,但你不想让别人看见代码细节
- 方便:只需要知道库文件函数接口,就可以方便使用其功能,不用知道具体细节
- 说明书:头文件相当于说明书,库函数使用信息基本都可以找到
静态库与动态库的区别
在windows
和linux
中都有库概念,都有静态库、动态库之分。
- windows
- 静态库文件为
.lib
文件, - 动态库文件为
.dll
文件
- 静态库文件为
- linux
- 静态库文件为
.a
文件 - 动态库文件为
.so
文件,后面可能跟数字,表明库版本
- 静态库文件为
- 两者区别
- 静态库在编译阶段,会加载到程序内部
- 动态库在程序运行时才会被加载
- 优缺点
- 静态库优点:程序依赖性不大,自身就是功能完备的主体
- 静态库缺点:加入多个程序用到同一个库文件,编译出每个程序都有一份该静态库融入其中,体量巨大。不利于更新,(游戏改动人物轻微细节,就需要对整个程序进行重新编译发布)
- 动态库优点:程序调用时加载结束时释放,应用灵活占用空间不大,对程序轻微改动时,只需要改变某些库文件即可
- 动态库缺点:某些库文件丢失可能导致导致程序无法正运行
静态库的制作
命名规则
- 前缀
lib
- 库名
- 后缀
.a
- 完整形式
libxxx.a
制作步骤
- 原材料:
.c
.cpp
- 将
c
文件生成.o
gcc -c xxx.c
- 将
.o
打包
ar rcs 静态库的名字 原材料
ar rcs libxxx.a *.o
- 库的使用
gcc main.c -I 头文件路径 -L 库路径 -l库名(紧挨着,只写库名前缀尾缀都不要) -o 指定文件名
静态库制作调用举例
//工程目录下有一个main.c文件src、include两个文件夹
root@DESKTOP-FR31BP0:/tmp# ls -l
总用量 16
drwxrwxrwx 0 root root 4096 4月 25 10:22 include
-rw-rw-rw- 1 root root 77 4月 25 10:22 main.c
drwxrwxrwx 0 root root 4096 4月 25 10:40 src
//src目录下有两个.c文件
root@DESKTOP-FR31BP0:/tmp# ls src/
func1.c func2.c
//include目录下有一个.h头文件
root@DESKTOP-FR31BP0:/tmp# ls include/
head.h
//查看相关的内容
root@DESKTOP-FR31BP0:/tmp# cat src/func1.c
#include <stdio.h>
#include "head.h"
void func1(void)
{
printf("this is func1\n");
}
root@DESKTOP-FR31BP0:/tmp# cat src/func2.c
#include <stdio.h>
#include "head.h"
void func2(void)
{
printf("this is func2\n");
}
root@DESKTOP-FR31BP0:/tmp# cat include/head.h
#ifndef _HEAD_H_
#define _HEAD_H_
void func1(void);
void func2(void);
#endif
root@DESKTOP-FR31BP0:/tmp# cd src
root@DESKTOP-FR31BP0:/tmp/src# ls
func1.c func2.c
//制作静态库第一步将.c文件转化.o文件
root@DESKTOP-FR31BP0:/tmp/src# gcc *.c -I ../include/ -c
root@DESKTOP-FR31BP0:/tmp/src# ls
func1.c func1.o func2.c func2.o
//制作静态库第二部=步将.o文件转化为静态库文件
root@DESKTOP-FR31BP0:/tmp/src# ar rcs libtest.a *.o
root@DESKTOP-FR31BP0:/tmp/src# ls
func1.c func1.o func2.c func2.o libtest.a
root@DESKTOP-FR31BP0:/tmp/src# cd ..
//调用验证
root@DESKTOP-FR31BP0:/tmp# gcc main.c -o run -I ./include/ -L src/ -l test
//成功编译
root@DESKTOP-FR31BP0:/tmp# ls
include main.c run src
//功能有效
root@DESKTOP-FR31BP0:/tmp# ./run
this is func1
this is func2
动态库的制作
命名规则
libxxx.so
libxxx.so.n.n.n
(n
代表数字表示版本)
制作步骤
- 源文件生成
.o
gcc -c *.c -fpic
或(fPIC)
- 打包成动态库
gcc -shared -o libxxx.so *.o
(第一步生成的.o
文件)
库的使用
- 加入现在有以下原料:(
a.h
libtest.so
(动态库和库的头文件)) 、main.c
(测试程序) - 使用方法与静态库使用方法一致
gcc main.c -I 头文件路径 -L 库路径 -l库名(紧挨着,只写库名前缀尾缀都不要) -o 指定文件名
- 调用报错:执行动态库的时候,打不开动态库文件
对于elf
格式的可执行程序,是由ld-linux.so*
,它先后搜索elf
文件的DT_RPATH
段->环境变量LD_LIBRARY_PATH
->/etc/ld.so.cache
文件列表->/lib/
,/usr/lib
目录找到库文件后将其载入内存 - 解决办法
-直接将库文件复制到/lib/
,/usr/lib
目录下
- 使用环境变量
- 临时设置
在终端里面写一个命令:export LD_LIBRARY_PATH=动态库的路径
- 永久设置
- 用户级别
在~/.bashrc
用户配置文件里添加上面命令,配置完成重启终端或者source~/.bashrc
- 系统级别
在/etc/profile
系统配置文件里添加上面命令,配置完成source /etc/profile
更新配置文件
- 用户级别
- 临时设置
- 更新
/etc/ld.so.cache
文件列表
- 找到一个配置文件
/etc/ld.so.conf
- 动态库绝对路径写到里面
- 执行一个命令
ldconfig -v
- 找到一个配置文件
- 使用环境变量
用法举例
//工程目录结构
root@DESKTOP-FR31BP0:/tmp# ls -l
总用量 20
drwxrwxrwx 0 root root 4096 4月 25 10:22 include
-rw-rw-rw- 1 root root 77 4月 25 10:22 main.c
drwxrwxrwx 0 root root 4096 4月 25 16:34 src
root@DESKTOP-FR31BP0:/tmp# ls include/
head.h
root@DESKTOP-FR31BP0:/tmp# ls src/
func1.c func2.c
//进入src文件夹进行库的生成
root@DESKTOP-FR31BP0:/tmp# cd src
root@DESKTOP-FR31BP0:/tmp/src# ls
func1.c func2.c
//将.c文件转化为.o文件
root@DESKTOP-FR31BP0:/tmp/src# gcc -c *.c -I ../include/ -fpic
root@DESKTOP-FR31BP0:/tmp/src# ls
func1.c func1.o func2.c func2.o
//生成动态库文件
root@DESKTOP-FR31BP0:/tmp/src# gcc -shared -o libtest.so *.o
root@DESKTOP-FR31BP0:/tmp/src# ls
func1.c func1.o func2.c func2.o libtest.so
root@DESKTOP-FR31BP0:/tmp/src# cd ..
root@DESKTOP-FR31BP0:/tmp# ls
include main.c src
//编译工程
root@DESKTOP-FR31BP0:/tmp# gcc main.c -o run -I ./include/ -L src/ -l test
//生成了目标程序run
root@DESKTOP-FR31BP0:/tmp# ls
include main.c run src
//运行程序出错
root@DESKTOP-FR31BP0:/tmp# ./run
./run: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directory
//运行其中一种方法,程序成功运行
root@DESKTOP-FR31BP0:/tmp# cp src/libtest.so /lib
root@DESKTOP-FR31BP0:/tmp# ./run
this is func1
this is func2
//其余解决方案自行测试