大家好,又见面了,我是你们的朋友全栈君。
基本知识
- gcc、g 、gdb区别
- linux和win换行符
- yum、apt、rpm区别
- 二进制包和源码包
- linux动态库和静态库
- cpp文件编译流程
- g 重要参数
- 生成库文件
- 生成静态库
- 生成动态库
- GDB调试
gcc、g 、gdb区别
GCC:GNU Compiler Collection(GUN 编译器集合),它可以编译C、C 、JAV、Fortran、Pascal、Object-C、Ada等语言。
- gcc是GCC中的GUN C Compiler(C 编译器)
- g 是GCC中的GUN C Compiler(C 编译器)
- gdb是是GCC中的GUN 调试工具
linux和win换行符
- windows : CRLR rn
- linux : LF n
yum、apt、rpm区别
rpm 命令是RPM软件包的管理工具,包括安装,升级,卸载,查询等操作。
尽管几乎所有的Linux发行版本都使用rpm进行软件包的管理安装、更新和卸载软件,但是并不受linux用户喜爱, 主要原因就是因为rpm软件包之间的依赖性问题往往会很繁琐,一般用户根本无法解决。 而yum仓库的产生,就是为了解决这个问题,它最大的特点就是为了帮助linux用户降低软件安装难度。
apt是ubuntu系列的包管理工具
一般来说著名的linux系统基本上分两大类:
- RedHat系列:Redhat、Centos、Fedora等
- Debian系列:Debian、Ubuntu等
vscode底层也是调用gcc和g 来编译代码的
二进制包和源码包
Linux 软件包管理大致可分为二进制包、源码包,使用的工具也各不相同。Linux 常见软件包分为两种,分别是源代码包(Source Code)、二进制包(Binary Code),源代码包是没有经过编译的包,需要经过 GCC、C 编译器环境编译或解压才能运行,二进制包无需编译,可以直接安装使用。
通常而言,可以通过后缀简单区别源码包和二进制包,例如.tar.gz、.zip、.rar 结尾的包通常称之为源码包,以.rpm 结尾的软件包称之为二进制包。
linux动态库和静态库
静态库(.a、.lib)和动态库(.so、.dll)
cpp文件编译流程
- 预处理pre-processing
# 头文件和宏定义等 进行展开 生成.i文件
g -E test.cpp -o test.i
- 编译Compiling
# 将test.i文件生成汇编文件 生成.s文件
g -S test.i -o test.s
- 汇编Assembling
# 将汇编代码转换为机器码
#缺省时 g 建立的目标代码文件有一个.o扩展名
g -c test.s -o test.o
- 链接Linking
#将机器码所使用的静态库动态库链接起来
g test.o -o test
也可以使用
代码语言:javascript复制g test.cpp -o test
一条命令代替以上四条命令 生成test.cpp文件
代码语言:javascript复制vim test.cpp
#include<iostream>
using namespace std;
int main(){
cout<<"hello world";
return 0;
}
# 生成test可执行文件
g test.cpp -o test
#使用./test执行可执行文件
./test
g 重要参数
-g
代码语言:javascript复制# -g 告诉GCC产生能被GNU调试器GDB使用的调式信息
# 所以生成的文件比一般的文件大一些
g -g test.cpp -o test
-O
代码语言:javascript复制# -O告诉g 对源代码进行优化 大多数情况下可以替换
# -O0不做优化
# -O1默认优化
# -O2进行额外调整入指令重排
# -O3 包括循环展开和其他一些与处理工程相关的优化工作
g -O2 test.cpp
-I 和 -L 指定库文件 | 指定库文件路径
代码语言:javascript复制# -l参数用来指定程序要链接的库
# 在/lib和/usr/lib和/usr/local/lib 里的库直接用-l参数就能连接
#连接glog库
g -lglog test.cpp
#如果文件没有放在上面三个目录里,需要使用-L 参数指定库文件搜索路径
#-L 参数跟着的是库文件所在的目录名
# 连接mytest库 libmytest.so 在/home/bing/mytestlibfolder目录下
g -L/home/bing.mytestlibfolder -lmytest test.cpp
-I
代码语言:javascript复制# /usr/include目录一般是不用指定的,gcc知道去哪里找 但是如果文件不在/usr/include里
#我们就要使用-I 参数指定. 比如文件在/myinclude目录里,那编译命令就要加上 -I/myinclude 参数了
#如果不加你会得到一个"xxx.h No such file or directory"的错误
#-I参数可以用相对路径 比如头文件在当前目录 可以用 -I. 来指定 上面我们提到的-cflags参数就是我们用来生成-I参数的
g -I/myinclude test.cpp
-Wall 打印警告信息
代码语言:javascript复制# 打印警告信息
g -Wall test.cpp
-w 关闭警告信息
代码语言:javascript复制#关闭警告信息
g -w test.cpp
-std=c 11 设置编译标准
代码语言:javascript复制g -std=c test.cpp
-o 指定输出文件名字
代码语言:javascript复制g test.cpp -o test
-D 定义宏
代码语言:javascript复制# 使用gcc/g 编译的时候定义宏
#常用场景
# -DDEBUG 定义DEBUG宏 可能文件中又DEBUG宏部分的相关信息 用个DDEBUG来选择开去或关闭DEBUG
#如
1.#include<stdio.h>
2.int main(){
3. #ifdef DEBUG
4. printf("DEBUG LOGn");
5. #endif
6. printf("inn");
7. return 0;
}
#编译的时候 使用g -DDEBUG main.cpp
#第4行的代码会被执行
代码语言:javascript复制[root@master test]# tree .
.
├── include
│ └── swap.h
├── main.cpp
└── src
└── swap.cpp
代码语言:javascript复制#main.cpp函数
#include<iostream>
#include "swap.h"
using namespace std;
int main(){
int a = 1;
int b = 2;
cout<<"before swap"<<endl;
cout<<"a is "<<a<<endl;
cout<<"b is "<<b<<endl;
cout<<"after swap"<<endl;
cout<<"a is "<<a<<endl;
cout<<"b is "<<b<<endl;
return 0;
}
#swap.cpp
#include "swap.h"
void swap(int &a,int &b){
int temp;
temp = a;
a = b;
b = temp;
}
#swap.h
oid swap(int &a,int &b);
代码语言:javascript复制#生成
g main.cpp src/swap.cpp -Iinclude -Wall -std=c 11 -o b.out
生成库文件
生成静态库
代码语言:javascript复制#进入src目录下
cd src
#汇编 生成swap.o文件
g swap.cpp -c -I,,/include
#生成静态库libswap.a
ar rs libswap.a swap.o
#回到上级目录
cd ..
#链接 生成可执行文件 staticmain
#-lswap 则系统就会去查找libswap.a静态库
g main.cpp -lswap -Lsrc -Iinclude -o static_main
生成动态库
代码语言:javascript复制#进入src目录
cd src
#生成动态库libswap.so
g swap.cpp -I../include -fPIC -shared -o libswap.so
#上面这条命令相当于下面两条命令
#gcc swap.cpp -I../include -c fPIC
#gcc -shared -o libswap.so swap,o
#-shared参数指定生成动态库
#回到上级目录
cd ..
#链接
g main.cpp -Iinclude -Lsrc -lswap -o sharemain
代码语言:javascript复制./sharemain
#执行./sharemain: error while loading shared libraries: libswap.so: cannot open shared object file: No such file or directory
静态库和动态库区别 静态库生成的可执行文件已经包装了静态库 运行的时候不需要额外链接静态库 动态库生成的可执行文件没有包括静态库 运行的时候需要额外链接动态库
代码语言:javascript复制#执行动态库可执行文件
LD_LIBRARY_PATH=src ./sharemain
GDB调试
执行gdb [exefilename] 进入gdb调试程序
代码语言:javascript复制help(h) #查看帮助 在gdb中输入 Help 命令
run(r) #重新开始运行文件
start #单步执行
list(l) #查看源代码(list-n 从第n行开始查看代码 list 函数名 查看具体函数)
set #设置变量值
next(n) #单步调试(越过函数)
step(s) #单步调试(进入函数)
backtrace(bt) #查看函数调用的栈帧和层级关系
frame(f) #切换函数栈帧
info(i) #查看函数内部局部变量的值
finish #结束当前函数 回到原函数
continue(c) #跳到下一个断点
print(p) #打印值及地址
quit(q) #退出gdb
break num(b num) #在第num行打断点
info breakpoints#查看当前所有断点
delete breakpoints num(d)#删除第num个断点
display #追踪查看具体变量值
undisplay #取消追踪具体变量值
watch #被设置观察点的变量发生变化时 打印显示
i watch #显示观察点
enable breakpoints#启用断点
disable breakpoints #禁用断点
x #查看内存x/20xw 显示20个单元 16进制 4字节单元
run argv[1] argv[2] #调试时命令传参
set follow-fork-mode child #makefile项目管理 选择跟踪父子进程(fork())
注意
- 编译程序的时候需要加上-g参数 之后才能使用gdb进行调试 gcc -g main.c -o main
- 回车键代表上一命令
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/168518.html原文链接:https://javaforall.cn