从hello world说起
- 首先我们有一段 hello world 程序
1
2
3
4
5
6
7
8
9
using namespace std;
int main()
{
retunr 0;
} - 我们通过以下步骤编译程序:
- g++ hello.cpp
这会生成一个a.out
的文件,这个名字是由于历史原因导致的,所以不管源文件的名字是啥,生成的可执行文件的文件名都是一样的。
- 首先,认识一下文件的后缀
.c
c语言的源文件.cpp .C .cc .cxx
c++ 语言的源文件.i
经过预处理的c 文件.ii
经过处理后的c++ 文件.s
汇编代码源文件.S
经过预处理的汇编代码文件.h
头文件.o
编译后的目标文件.so
动态链接库文件 在Win下是.dll
.a
静态链接库文件 在Win下是.lib
- gcc 常用的命令
- 一般格式:
gcc [-option] srcfile [-option] desfile
- g++ -E hello.cpp -o hello.ii 只进行预处理,得到预处理后的文件
- g++ -S hello.cpp -o hello.s 生成到汇编代码后停止,得到汇编文件。
- g++ -c hello.cpp -o hello.o 编译到最后的二进制代码,但不进行链接,得到目标文件。
- g++ -g hello.cpp -o ghello 生成包含调试信息的可执行文件,可以通过
strip ghello
删除文件中的debug信息。 - g++ -O hello.cpp 对代码进行自动优化编译,O后面可以接数字,比如可以使用
-O3
进行三级优化编译 - g++ -W hello.cpp 编译中开启一些额外的警告信息,
-Wall
表示把所有的警告信息全部打开 - g++ hello.cpp -I/path/to/include -L/path/to/lib -lnameoflib 分别表示添加包含文件的搜索路径,链接文件的搜索路径以及指定要使用的链接库的名字
- 链接库的生成,首先要介绍一些基本的规则
- 动态库一律是以 lib 开头,制定链接库名字的时候可以省去lib三个字母。
- 由于动态库节省空间,所以默认链接动态库,可就是说如果有两个同名的动态库和静态库,那么linux会优先选择动态库链接,如果要特别告诉编译器与重名的那个静态库链接,则主要加上
-static
或-WI,-Bstatic
选项,如果既要链接动态库又要链接静态库,则需使用-WI,-Bstatic -lnameofstaticlib -WI,-Bdynamic -lnameofdynamiclib
- 为了让程序使用自己创建的动态库有三种方法
- 将自己的库拷到 /usr/lib或/lib 等已经存在于环境变量中的动态库搜索路径中
- 修改环境变量
export LD_LIBRARY_PATH
=$LD_LIBRARY_PATH:/new/lib/path - 修改 /etc/ld.so.conf ,把库的路径加到末尾,然后执行 ldconfig 刷新。
- nm libname.so 查看库中有哪些函数,如果库中没有自己想要找的库,则可以使用 ldd libname.so 来看看它依赖的其他库,在其他库中说不定可以找到哦
- 到达
- 生成库文件
- ar cqs libname.a name.o
- ar cr libnamme.a name.o
- g++ -shared -W1,-soname,libname.so.1 -o libname.so.1.0 hello.o
- g++ -shared -fPCI -o libname.so name.o
- 其中soname 是库区分的标志,这就像库的身份证,通常的做法就是将库的soname与库的顶级版本号的保持一致,然后将低级版本到软连接到一个与soname同名的链接文件。
使用GDB调试程序
- 使用 gdb test 来启动调试。
- 一些常用的命令
- r(run) pram1 parm2 运行
- l(list) start,end 显示指定行数的代码
- p(print) var(fun) 打印变量的值,或是打印函数调用的值
- whatis 查看变量的类型
- b(break) [行号,函数名] 在指定位置设置断点
- tbreak 设置临时断点,触发后自动删除
- info b 查看所有的断点
- d(delete) 删除断点
- set pram=val 设置变量的值
- c(continue) 继续执行直到遇到新的断点
- n(next) 不进入的单步调试
- s(step) 进入的单步调试
- finish 执行完当前函数
- q(quit) 退出调试
- h(help) command 查看指定命令的用法