linux与g++基本知识「建议收藏」

2022-09-22 12:29:40 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

基本知识

  • 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文件编译流程

  1. 预处理pre-processing
代码语言:javascript复制
# 头文件和宏定义等 进行展开 生成.i文件
g   -E test.cpp -o test.i
  1. 编译Compiling
代码语言:javascript复制
# 将test.i文件生成汇编文件 生成.s文件
g   -S test.i -o test.s
  1. 汇编Assembling
代码语言:javascript复制
# 将汇编代码转换为机器码
#缺省时 g  建立的目标代码文件有一个.o扩展名
g   -c test.s -o test.o
  1. 链接Linking
代码语言:javascript复制
#将机器码所使用的静态库动态库链接起来
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

0 人点赞