库
库文件是计算机上的一类文件,可以简单的把库文件看成一种代码仓库,它提供给使用者一些直接拿来用的变量、函数或类。库不能单独运行。
- 静态库:在程序链接阶段被复制到程序中
- 动态库:在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用
库的好处:
- 代码保密
- 方便部署和分发
静态库
命名规则:
- Linux:libxxx.a
- lib: 前缀(固定)
- xxx:库的名字,自己起
- .a:后缀(固定)
- windows:libxxx.lib
静态库的制作:
- gcc获得.o文件
- 将.o文件打包,使用ar工具(archive)
- ar rcs libxxx.a .o xxx.o xxx.o
- r - 将文件插入备存文件中
- c - 建立备存文件
- s - 索引
动态库
命名规则:
- Linux:libxxx.so
- windows: libxxx.dll
动态库的制作:
- gcc -c -fpic/fPIC 获得.o 文件
- gcc -shared *.o -o libxxx.so
程序启动后,动态库会被动态加载到内存中,通过ldd(list dynamic dependencies)命令检查动态库依赖关系。
解决动态库加载失败的问题
- 修改DT_RPATH ,临时的
- 修改环境变量LD_LIBRARY_PATH
- 修改/etc/ld.so.cache文件列表
- 修改/lib/, /usr/lib
静态库和动态库的对比
静态库、动态库区别来自链接阶段如何处理,分别称为静态链接方式和动态链接方式
静态库的优缺点
- 优点:
- 静态库打包到应用程序中加载速度快
- 发布程序无需提供静态库,移植方便
- 缺点:
- 消耗系统资源,浪费内存
- 更新、部署、发布麻烦
动态库的优缺点
- 优点:
- 可以实现进程间资源共享(共享库)
- 更新、部署、发布简单
- 可以控制何时加载动态库
- 缺点:
- 加载速度比静态库慢
- 发布程序时需要提供依赖的动态库
Makefile
Makefile规则
一个 Makefile 文件中可以有一个或者多个规则
目标…:依赖…
命令(shell命令)
…
- 目标:最终要生成的文件(伪目标除外)
- 依赖:生成目标所需要的文件或是目标
- 命令:通过执行命令对依赖操作生成目标(命令前必须 Tab 缩进)
Makefile 中的其它规则一般都是为第一条规则服务的。
工作原理
- 命令在执行之前,需要先检查规则中的依赖是否存在
- 如果存在,执行命令
- 如果不存在,向下检查其它的规则,检查有没有一个规则是用来生成这个依赖的,如果找到了,则执行该规则中的命令
- 检测更新,在执行规则中的命令时,会比较目标和依赖文件的时间
- 如果依赖的时间比目标的时间晚,需要重新生成目标
- 如果依赖的时间比目标的时间早,目标不需要更新,对应规则中的命令不需要被执行
GDB
- 通常,在为调试而编译时,我们会()关掉编译器的优化选项(
-O
), 并打开调试选项(-g
)。另外,-Wall
在尽量不影响程序行为的情况下选项打开所有warning,也可以发现许多问题,避免一些不必要的 BUG。 - gcc -g -Wall program.c -o program
-g
选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证 gdb 能找到源文件。
标准C库函数和Linux系统函数
标准C库IO和Linux系统IO的关系
虚拟地址空间
文件描述符 File Descriptor
内核(kernel)利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。
Linux 系统IO函数
- int open(const char *pathname, int flags);
- 打开文件
- flags 如 O_CREAT,意思是没有即创建
- int open(const char *pathname, int flags, mode_t mode);
- 打开文件,并设置模式
- mode 可以是 O_RDONLY, O_WRONLY, O_RDWR
- int close(int fd);
- 关闭文件描述符
- ssize_t read(int fd, void *buf, size_t count);
- ssize_t write(int fd, const void *buf, size_t count);
- off_t lseek(int fd, off_t offset, int whence);
- 重定位文件偏移量
- SEEK_SET:设置offset
- SEEK_CUR:设置offset为当前加上传的参数offset
- SEEK_END:设置offset为文件末端加上传的参数offset(记得之后要写入一些字符才能更新)
- int stat(const char *pathname, struct stat *statbuf);
- 得到文件状态信息
- int lstat(const char *pathname, struct stat *statbuf);
- 得到软连接文件状态信息
文件属性操作函数
- int access(const char *pathname, int mode);
- 判断文件mode
- int chmod(const char *filename, int mode);
- int chown(const char *path, uid_t owner, gid_t group);
- int truncate(const char *path, off_t length);
- 截断或延长文件长度
目录操作函数
- int rename(const char *oldpath, const char *newpath);
- int chdir(const char *path);
- char *getcwd(char *buf, size_t size);
- int mkdir(const char *pathname, mode_t mode);
- int rmdir(const char *pathname);
目录遍历函数
- DIR *opendir(const char *name);
- 返回目录流
- struct dirent *readdir(DIR *dirp);
- 返回direct结构体,目录流文件的信息
- int closedir(DIR *dirp);
dup, dup2 函数
- int dup(int oldfd);
- 复制文件描述符
- int dup2(int oldfd, int newfd);
- 重定向文件描述符
fcntl函数
- int fcntl(int fd, int cmd, … /* arg */ );
- 复制文件描述符
- 设置/获取文件的状态标志