1 GCC
- GCC原名为GNU C Complier(C语言编译器),只针对C语言的编译。而今,GCC还支持其他语言的编译,如C++、Objective-C、JAVA、Ada和Go语言,因而更名为GNU Complier Collection(GNU编译器套件)。
- 安装指令:
sudo apt install gcc g++
(版本>4.8.5).gcc可以理解为用于编译c的套件,g++则是用于编译C++.
- 版本查询:
gcc/g++ -v/--version
2 GCC工作流程
工作流程
参数选项
3 GCC和G++差别
对于
.c
文件,GCC会将其认为是c
文件进行编译,而G++则是当作cpp
文件进行编译;而对于.cpp
文件,二者均是认为是cpp
文件。gcc
可以编译.c
文件,也可以编译.cpp
文件,但是编译后者时无法自动和C++程序所使用的库进行链接,而是需要调用g++
来实现;而g++
则是在编译阶段会自动调用gcc
。
4 静态库&动态库
静态库在程序的链接阶段被复制到程序中,而动态库则并未进行复制,而是在运行过程时由程序动态加载到内存中以供调用。
4.1 库的规范
静态库
- 命名规则
- Linux:
libxxx.a
, 其中lib
为固定前缀,xxx
则是用户自定义静态库名,.a
则为固定后缀。 - Windows:
libxxx.lib
- Linux:
- 制作
- gcc获得
.o
文件,即链接前的格式:gcc -c a.c b.c
- 将
.o
文件通过ar命令进行打包:ar rcs libcalc.a a.o b.o
, 其中r意为将文件插入备存文件中,c为建立备存文件,s则是索引
- gcc获得
- 使用
gcc main.c -o app -I ./path1 -L ./path2 -l calc
, 其中path1
用于指定main.c
中包含的头文件的相对地址,其实就是指所使用的静态库的头文件,而path2
则是指定静态库的相对地址,calc
则是静态库的名称(注意不是libcalc
).
- 命名规则
动态库
- 命名规则
- Linux:
libxxx.so
,其中lib
为固定前缀,xxx
则是用户自定义动态库名,.so
则为固定后缀。为可执行文件。 - Windows:
libxxx.dll
- Linux:
- 制作
- gcc得到
.o
文件,得到和位置无关的代码:gcc -c -fpic/-fPIC a.c b.c
- gcc得到动态库:
gcc -shared a.o b.o -o libcalc.so
.
- gcc得到
- 使用
gcc main.c -o app -I ./path1 -L ./path2 -l calc
, 其中path1
用于指定main.c
中包含的头文件的相对地址,其实就是指所使用的动态库的头文件,而path2
则是指定动态库的相对地址,calc
则是动态库的名称(注意不是libcalc
).
- 命名规则
4.2 动态库加载失败原因及解决方法
原因:链接时GCC只是把动态库的信息写入可执行程序中,并没有把动态库的代码打包到程序中,因而程序执行过程中需要系统的动态载入器来获取该库的绝对路径以加载对应的代码。对于elf格式的可执行程序,是由ld-linux.so来完成这个操作,搜索顺序为:elf文件的DT_RPATH段->环境变量LD_LIBRARY_PATH->/etc/ld.so.cache文件列表->/lib/,/usr/lib目录.
解决:在上述任意的位置中加入动态库的绝对路径。
在
LD_LIBRARY_PATH
中加入动态库地址export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:Absolute_ path_of_dynamic_lib
:冒号后加上动态库的绝对地址使用
echo $LD_LIBRARY_PATH
即可查看是否成功将动态库的绝对地址加入到环境变量中. 但直接在终端中配置时只是暂时的,关闭终端后重新执行程序会再次报错。
用户级别:编辑
.bashrc
, 在最后一行加入空行再加入上边的命令。(Shift+G: 跳到最后一行,o
:插入空行)source ~/.bashrc
(等效于. ~/.bashrc
):使更改生效.波浪号表示/Home/文件夹系统级别:
sudo vim /etc/profile
然后跟方法2一致.
修改
/etc/ld.so.cache
sudo vim /etc/ld.so.conf
,然后将路径加入到该文件中并用sudo ldconfig
更新一下
- 修改
/lib/
或/usr/lib
(不建议:存有系统本身自带的库,防止用户自定义库名与系统库一致导致将系统库擦除)
4.3 静态库和动态库的优缺点
静态库:
- 加载速度快
- 无需额外提供静态库,移植方便
- 消耗系统资源,浪费内存
- 更新、部署、发布麻烦(修改后需要重新编译)
动态库:
- 可以实现进程间的资源共享:只需加载一次,进程间可以共享
- 更新、部署、发布简单
- 可以控制何时加载动态库
- 加载速度慢
- 发布时需要额外提供所依赖的动态库
使用动态库还是静态库,取决于库的大小,库如果较大则推荐使用动态库。
附录 Linux基本命令
mkdir
: 在当前目录下新建一个文件夹cd
:打开某一个文件夹,cd ..
为回到父文件夹touch
:打开某一文件vi
/vim
: 编辑某一文件gcc xxx.c -o app
: 编译某个c文件,输出名为app的目标,如果没有指定目标,则生成的是.out
文件(同样是可执行文件)tree
: 打开当前文件夹的目录树ls
:查看当前文件夹具有哪些文件,ll
查看当前文件夹中的文件的详细信息cp 源文件相对路径 目标文件相对路径
:复制源文件到目标文件位置rm
:删除文件,rmdir
:删除文件夹ldd
: 查看可执行文件所依赖的动态库env
:查看环境变量pwd
:查看当前文件夹得绝对路径