GCC的学习(二)头文件及其库制作

一、-I 头文件路径

1.1 工程结构简单不需要-I选项

工程若源代码及头文件数量较少根本不需要-I选项,将他们放在同一级目录下,源文件就可正常找到头文件:

//ttt.cpp
#include <stdio.h>
#include "data.h"
int main()
{
	printf("Hello world\n");
	printf("Data in header is %lf\n",pi);
}
// data.h
double pi=3.1415;

在终端键入:

gcc ttt.cpp

即可正常编译连接形成可执行文件。

1.2 工程结构较复杂

随着工程的进展,为了更清晰的结构,人们常常把头文件和源文件,编译结果分开放在不同的文件夹。仅为演示,将ttt.cppdata,h分别放入两个文件夹src和include中,如果仍然使用(1.1)方法将会发生错误:

junwuli@ubuntu:~/Desktop/gcctest/build$ gcc ../src/ttt.c 
../src/ttt.c:2:10: fatal error: data.h: No such file or directory
 #include "data.h"
          ^~~~~~~~
compilation terminated.

此时就需要用到-I选项:

junwuli@ubuntu:~/Desktop/gcctest/build$ gcc ../src/ttt.c -I ../include/
junwuli@ubuntu:~/Desktop/gcctest/build$ ./a.out
Hello world
Data in header is 3.141500

假设我们的主程序不想写相对路径的,只想写一个简洁的“head.h”而不是“./include/”就需要用到这个参数。

gcc hello.c -Iinclude -o app

或者是

gcc hello.c -I include -o app

二、库的制作和使用

无论是静态库还是动态库,都需要将源文件编译成目标文件,再将目标文件整合在一起形成库。这里的这里的库,类似于生活中的仓库,不过存放的内容是目标文件,仓库里有什么,靠的就是头文件。

大概是这样的过程:

graph LR
源文件-->目标文件
目标文件-->库的打包
2.1 库的命名规则

和变量命名一样,Linux库的命名也要揭示库的属性、名称。

libxxx.so.x.y.z
libxxx.a.x.y.z
部分含义
lib文件属性
xxx库名称
.so/.a库类型
.x.y.z版本号[2]
2.2 静态库的制作和使用
2.2.1 制作静态库

以a.c b.c为例,生成目标文件

gcc a.c b.c -c 

默认生成同名目标文件a.o b.o

根据上一步产生的a.o b.o材料,打包目标文件

ar rcs libtest.a a.o b.o

注:rcs 代表插入目标文件创建归档文件及引索。

2.2.2 使用静态库

libtest.a + 头文件,头文件加库使用静态库

gcc main.c -I ./include/ -L ./lib/ -ltest -o app

注:nm(name)可以查看lib中的内容

2.3 动态库制作和使用
2.3.1 制作动态库

以a.c b.c为例,-fPIC选项,生成目标文件[3]

gcc a.c b.c -c -fPIC(-fpic)

根据上一步产生的a.o b.o材料,–shared选项,打包目标文件

gcc -shared a.o b.o -o libxxx.so

2.3.2 使用动态库

头文件加库设置使用动态库

gcc main.c -I ./include/ -L ./lib/ -lxxx -o app

和静态库一样的,指定库所在路径,库的名称。如果他和源文件在同一级目录,OK,完全没有问题,但是,如果它在下一级的lib当中,就会提示找不到了!

ldd 用静态库编译的可执行文件

上面这个可以查看依赖库,以及其是否被找到。

2.4 动态库搜索路径

动态库和可执行程序、和.o文件他们的格式都为ELF,系统使用ld-linux.so.X[1]来完成。按顺序分别是:

  • ELF文件的DT_PRATH段
  • 环境变量LD_LIBRARY_PATH
  • 文件列表 /etc/ld.so.cache
  • /lib usr/lib
    在任意步骤找到,都将会载入内存正常使用,反之报找不到库的错误。

注释:

[1] Glibc安装的库中有一个为ld-linux.so.X,其中X为一个数字,在不同的平台上名字也会不同,如ubuntu18.04就为ld-linux-x86-64.so.2

[2]x表示主版本号,不同主版本一般不兼容;y次版本号,库的增量升级,原接口不变但是新增了一些接口,同时兼容旧版本;z发布版本号,一些库功能错误、性能改善,接口不增加也不更改。

[3] 为了兼容各个系统,在生成位置无关的代码的时候,应该使用-fPIC参数。

参考文章:

【1】《-fpic 与-fPIC的区别》 作者:zhang_dawei666 (https://blog.csdn.net/xiangguiwang/article/details/81939237)

扩展:

动态和静态库的区别:https://www.cnblogs.com/mhscn/p/4264357.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值