(菜鸡自救,仅做个人记录,谢谢大佬)
主要参考:编译链接基础知识 · FFmpeg原理 (xianwaizhiyin.net)
1、从简单的命令开始:
编译程序:
gcc -c -o hello.o hello.c
Linux命令格式 :命令 [选项] 参数
-c:只编译,不链接
hello.o:输出文件
hello.c:输入文件
在编译时,对于一些函数的地址先用占位符占位,如00 00
链接程序:
gcc -o hello hello.o
链接动态库VS链接静态库 :
动态库:libc.so
静态库:libc.a
gcc默认使用动态库链接,找不到.so文件,才会采用静态链接找.a文件。
如何手动设置静态链接?
gcc -o hello hello.o -static -lc
-static:设置所有库都以静态的方式链接 ;
-l:这是一个需要链接的库,不需要加lib;
c:库名,指libc.so库,若-ltest 指链接libtest.so;
Linux 系统各个版本的 C运行时库版本 可能不一样,该怎么解决?
(1)静态链接;
(2)将动态链接库libc.so文件复制到运行程序当前目录,跟程序一起发布;再在 /etc/ld.so.conf.d/
,添加相关配置,再执行 sudo ldconfig
即可。因为 ld.so.conf.d 里面的路径是优先于 /lib
跟 /usr/lib
目录的。
2、gcc编译多个C文件
无论是多庞大的C/C++ 项目,编译阶段,都是单个文件编译的,单个文件里面引用了外部的变量,函数。编译阶段只会把这些引用 替换成一些占位符号,例如 00 00 。
只有在链接阶段,gcc 才可以接受多个 文件作为输入。然后 扫描这些输入文件,找到各个 函数符号地址,然后进行替换。链接器通常会扫两次输入文件,第一次找到所有符号,第二次才开始替换占位符号。
提示:命令可以加上 -v
或者 -###
显示更多的编译信息。
大型C/C++项目编译时会遇到哪几种问题?
(1)找不到头文件:
加上-v函数,观察#include说明,查看目标头文件是否在相关路径下;如果头文件的目录不在编译器搜索路径当中,利用-I参数加上搜索路径:
gcc -v -c -o sun.o sun.c -I/home/ubuntu/
#include引入头文件的两种写法:
#include "moon.h"
#include <moon.h>
<header.h>只在系统目录下查找
"header.h"在系统目录和当前目录找
(2)undefined reference:
a.‘undefined reference to `std::ios_base::Init::Init()’
一般编译链接c++程序最好使用g++,若有如上的报错信息,需要在gcc后加上 -lstdc++
eg: gcc test.c -lstdc++
gcc和g++都是GNU的一个编译器。
g++:后缀.c的程序和.cpp的程序都会当成是c++的源程序来处理。
gcc:会把.c的程序处理成c程序。
对于**.cpp**的程序,编译可以用gcc/g++,链接可以用g++或者gcc -lstdc++。
b. undefined reference to `xxx'
找不到实现函数的库:命令中遗漏库引用,或者写错库名称
3、编译静态库
静态库VS动态库
参考:(85条消息) 静态库与动态库的区别与优缺点_静态库和动态库的优缺点_雨荔@秋垣的博客-CSDN博客
实践参考:
C++静态库与动态库 - 吴秦 - 博客园 (cnblogs.com)
静态库也称归档文件,就是对已经编译好的字节码进行封装,在编译时直接整合到目标程序中,编译成功的可执行文件可独立运行;
动态库在编译时,目标程序中只会存在一个“指向”的位置,可执行文件无法单独运行;
封装静态库:
Linux 的静态库封装,实际上就是打包,把多个 .o 文件打包在一个 .ar 文件里面:
ar -rcs libstar.a moon.o sun.o earth.o
ar:打包封装命令
封装静态库不需要链接
引用静态库:
(1)直接写 静态库文件的全称,会在当前目录找 libstar.a:
gcc -o poseidon poseidon.o libstar.a
(2) -static
指定后面的库是静态库,然后使用 -l
参数 指定库名称:
gcc -v -o poseidon poseidon.o -static -lstar
4、封装静态库
在第三方静态库基础上加一些功能——省流:解压静态库,将.o文件重新打包
ar -x libstar.a
ar -rcs libpower.a moon.o sun.o earth.o dog.o pig.o
5、编译动态库
eg:
g++ -fPIC -c name.cpp
g++ -fPIC -c age.cpp
g++ -fPIC -c hobby.cpp
g++ -fPIC -c logan.cpp
g++ -fPIC -shared -o libintro.so name.o age.o logan.o hobby.o
-fPIC
是编译选项,PIC是 Position Independent Code 的缩写,表示要生成位置无关的代码。
链接动态库:
g++ -o hello hello.o libintro.so
配置加载动态库路径:
(1) 编辑/etc/ld.so.conf文件,加入库文件所在目录的路径
(2) 运行sudo ldconfig ,该命令会重建/etc/ld.so.cache文件
(3)将动态库文件移动到/usr/lib下
6、显式使用动态库(这个感觉不重要)
参考:
Linux环境显式使用动态库—编译链接基础知识 · FFmpeg原理 (xianwaizhiyin.net)
7、封装静态库为动态库
省流:解压再编译
8、混合使用动态库 静态库
在一些使用第三方动态库和第四方静态库的场景下——省流:复杂,看不懂
项目中通用做法:cpp 编译 .o, 一个目录或一个库生成*.a, 在把所有a链接成可执行的二进制的文件