Linux环境(gcc编译器):C编程基础操作
gcc安装
Ubuntu:
sudo apt-get install gcc
Centos:
sudo yum install gcc
确认是否安装成功
gcc -v
gcc基础编译命令
通过gcc编译命令可以生成后缀名.i的预处理文件,.s的汇编文件,.o的目标文件,.a/.so的库文件和可执行文件
Linux中的C程序源码编译成可执行程序,可能需要依赖多个库文件。可以把这些依赖的库文件当作源码文件的一部分。
常用gcc命令参数
-c 后接编译源文件名
-o 后接产生的目标文件
-g 表示在目标文件中产生调试信息,使得目标文件可以用于 gdb 调试
-D<宏定义> 编译时将宏定义参数传入进去
-Wall 打开所有类型的警告
生成可执行文件的方式
- 若干源码文件 直接编译生成可执行文件
格式:gcc [源码文件名] -o [可执行文件名]
eg.gcc c1.c c2.c -o test.exe
- 源码文件生成目标文件,目标文件和依赖的库文件(可以省略)一起链接生成可执行文件
格式:
gcc -c [源码文件名] -o [目标文件名]
gcc -o [可执行文件] [源码文件] -[库文件]
gcc -c c1.c -o c1.o gcc -c c2.c -o c2.o gcc -o test.exe c1.o c2.o
- 源码文件生成预处理文件,预处理文件生成汇编文件,汇编文件生成目标文件,目标文件链接成可执行文件
gcc -E main.c -o main.i gcc -S main.i -o main.s gcc -c main.s -o main.o gcc -o main.exe main.o
gcc进阶命令:静态库与动态库文件的生成
-
静态库文件生成
静态库生成较为简单,库文件在链接时直接注入源码文件,生成的可执行文件移植性好,运行时不依赖静态库文件,方便部署,但是不利于升级,每次升级后需要重新生成可执行文件
生成流程:- gcc编译命令生成目标文件
gcc -c add.c -o add.o
- ar命令对目标文件(可以是多个)打包生成库文件 crsv为参数,其中csv是修饰符可以省略
ar crsv libadd.a add.o
- 库文件放入默认库文件路径/lib或/usr/lib
mv libadd.a /lib
- 编译生成可执行文件,注意库文件名
gcc -o main.exe main.c -ladd
- gcc编译命令生成目标文件
其中,只有第二步需要记忆,其他均为常规操作。
-
动态库文件生成
动态库生成稍微复杂,库文件在链接时不注入源码文件,生成的可执行文件运行时需要依赖动态库文件,移植性差,不便于部署在其他机器,但是升级方便,只需要更新库文件。
生成流程: -
动态编译生成目标文件
gcc -fPIC -Wall -c add.c
-
目标文件生成动态库文件
gcc -shared -o libadd.so add.o
-
库文件放入默认库文件路径/lib或/usr/lib
mv libadd.so /lib
-
编译生成可执行文件,注意库文件名
gcc -o main.exe main.c -ladd
需要注意的是第一步和第二步也可以合成一步gcc -fPIC -Wall -shared -o libadd.so add.c
批量编译:Makefile简介
通过编写Makefile文件可以实现批量编译操作
原理:每次编译过程使用的命令大体相同,不同的只有文件名,所以可以使用变量名替换掉文件名,从而实现自动化编译。不同的文件之间存在依赖关系,所以采用自顶(可执行文件)向下(源码文件)的递归过程。
Makefile的语法规则:
-
变量命名 :Makefile实际上是采用不同字符串对命令进行替换实现的,所以变量均为字符串格式。为了与命令区别,变量使用时需要加小括号并使用$进行标识:$(变量名)
- 直接赋值定义:
变量名:= 字符串
- 递归式定义 :
变量名 = 字符串(变量名)
类似多个指针指向一个地址
- 直接赋值定义:
-
函数:
- 查找函数$(wildcard *.c),wildcard是函数名,后跟一个参数,作用是将符合该参数规则的文件名当作一列字符串输出,各个文件名之间会隔开。*.c会找到当前目录下的所有.c文件名并输出
- 字符串替换函数$(patsubst 匹配规则1,匹配规则2,源字符串列表)将源字符串列表中符合匹配规则1的字符串 进行替换 使其符合匹配规则2。Makefile中的通配符为%。
示例:
OC=$(patsubst %.c,%.o,$(wildcard *.*))
含义是将当前目录下所有有后缀名的文件中的.c文件名拿出来,并把.c替换成.o,然后将这一串字符串赋值给变量OC -
规则
主要用到 :- $@代表当前规则下的目标文件\
- $^代表当前规则的所有依赖文件
- 所有的.o文件会自动依赖同名的.c文件
- 一系列的预定义变量
通过上述规则,即可编写通用的makefile文件,针对特殊需求只需要修改对应变量即可
以下为简单的通用Makefile文件示例
生成可执行文件的Makefile文件
EXE:=test.exe
#编译后得到的可执行文件的名字
CC:=gcc
#选择的C编译器 可以根据需要改动
CFLAGS:=-Wall -g
#gcc编译参数 显示所有警告信息 可调试 可以根据需要改动
LIBSO:=
#库依赖文件 可以根据需要添加
OC := $(patsubst %.c, %.o, $(wildcard *.c))
#目标文件列表 用来生成可执行文件
$(EXE):$(OC)
$(CC) $(CFLAGS) -o $@ $^
.PHONY : clean rebuild
clean:
rm -f $(EXE) $(OC)
rebuild:
clean $(EXE)
生成静态库文件的Makefile文件
# 库文件名, lib*.a
TARGET := libtest.a
# 编译器选择
CC := gcc
#打包程序选择
AR = ar
#gcc编译参数 显示所有警告信息 可调试 可以根据需要改动
CFLAGS:=-Wall -g
#依赖的库文件
LIBS :=
# 自动查找当前目录所有 .c 文件,并将目标定义为同名 .o 文件
SOURCE := $(wildcard *.c)
OBJS := $(patsubst %.c,%.o,$(SOURCE))
$(TARGET) : $(OBJS)
#生成静态库文件
$(AR) crvs $(TARGET) $(OBJS)
#移动到/lib中
mv $(TARGET) /lib
.PHONY : clean delete rebuild
clean :
#删除中间文件
rm -rf *.o
#删除库文件
delete:
rm /lib/$(TARGET)
#重新生成库文件
rebuild:
clean $(TARGET)
生成动态库文件的Makefile文件
# 库文件名, lib*.so
TARGET := libtest.so
# 编译器选择
CC := gcc
#gcc生成动态库文件的编译参数
CFLAGS:= -g -Wall -fPIC -shared -o
#依赖的库文件
LIBS :=
# 自动查找当前目录所有 .c 文件
SOURCE := $(wildcard *.c)
$(TARGET) : $(OBJS)
$(TARGET) $(CFLAGS) $(TARFET) $(SOURCE)
#移动到/lib中
mv $(TARGET) /lib
.PHONY : clean delete rebuild
clean :
#删除中间文件
rm -rf *.o
#删除库文件
delete:
rm /lib/$(TARGET)
#重新生成库文件
rebuild:
clean $(TARGET)
gcc调试命令gdb
如果在gcc编译程序时加入了-g参数,则可以使用gdb命令对可执行文件进行调试
gdb -q 可执行文件名
#-q参数可以消除gdb启动时输出的无用的版本信息等
常用gdb命令:
l:查看代码
b : 打断点
info b:查看所有断点
tb :打临时断点
r :运行
bt:查看函数堆栈调用信息
delete:删除断点
n:下一步,遇到函数直接执行不进入
s:下一步,遇到函数进入
disable:使某个断点失效
enble:启用某个断点
c:继续运行
p:打印命令,可以用来打印变量
q:退出