1、gcc编译器
1、预处理,做#的事
展开头文件 #include
宏替换 #define
条件编译 #if #else #endif #elif
删除注释
2、编译阶段:检测语法错误,把文件转换为汇编
gcc -S xxx.c -0 xxx.s
3、汇编阶段:把汇编语言转换为机器语言
gcc -c xxx.c -o xxx.o
4、链接:把所有二进制文件链接整合为一个可执行文件
gcc xxx.c -o app
-o :给生成的文件取名字。其中有几个优先级包括o2等等。等待补充
-I(i的大写) :需要引用的头文件路径
-l(L的小写):
2、gdb调试
要使用gdb调试在编译时必须加上-g选项
gdb +r:让程序执行一次
gdb +l:查看十行代码内容
gdb +b:在对应行设置一个断点
gdb +p:变量名,查看变量的内容
gdb +n:让程序继续运行
quit:退出gdb调试
3、Makefile
make是一个工程管理器,用来管理多文件项目的
Makefile是make工具的唯一配置文件,文件名只能叫makefile
目标文件:依赖文件
功能语句
现有一个学生的项目,其中c_code内是c语言文件,h_code是.h文件。使用makefile对其进行编译
1、基本理解
app:main.o student.o
gcc main.o student.o -o app
main.o:./c_code/main.c
gcc -c ./c_code/main.c -I ./h_code/ -o main.o
student.o:./c_code/student.c
gcc -c ./c_code/student.c -I ./h_code -o student.o
该脚本是初级理解,代码会逐行检查依赖,若没有,就会用接下来的代码生成
2、使用shell脚本提升其复用性。使用到通配符。以后若需要添加.依赖文件,直接在obj内后方添加
B=gcc
Target=app
obj=main.o student.o
BFlages=-c -Wall#编译选项,表示显示编译期间发生的所有警告,此处有 -c了!!!!!!!!!
Hin=-I ./h_code #申明h文件的位置,-I是gcc编译的时候带着头文件一起编译
Cin=./c_code/
#格式:目标:依赖
#第一步,基于 .o文件生存目标文件,而.o文件来源于.c文件,此步骤在makefile当前文件夹执行,所以不需要添加路径
#下面的$^表示依赖文件,$@表示目标文件
#app:main.o student.o
# gcc main.o student. o -o app
$(Target):$(obj)
$B $^ -o $@
#第二部,给定所有的.o文件的依赖都是(Hin)路径下的.c文件的东西。$^表示上面的所有c文件
%.o: $(Cin)%.c
$B $(Hin) $(BFlages) $^ -o $@
#清理文件
clean:
rm -f *.o $(Target)
今日学习动态库
CC = gcc # 设置编译器为gcc
TARGET = app # 设置目标文件名为app
Cin = ./c_code/ # 设置C源文件的路径
Hin = ./h_code/ # 设置头文件的路径
SRC = $(Cin)student.c # 设置源文件为c_code目录下的student.c
METHOD= -shared -o # 设置编译选项为-shared和-o,用于生成动态库
FP = -fPIC # 设置编译选项为-fPIC,用于生成位置无关代码
OBJ = $(SRC:.c=.o) # 将源文件名的.c后缀替换为.o,得到目标文件名
HEAD =-I $(Hin) # 设置编译选项-I,用于指定头文件的路径
VERSION = 1.0.0 # 设置版本号为1.0.0
LIBDIR = /usr/lib # 设置库文件的路径
SO = libdtudent.so # 设置动态库的文件名
MAIN = ./c_code/main.c # 设置主函数的源文件
all:$(TARGET) $(SO) # 定义目标all,依赖于目标app和libdtudent.so
$(SO):$(OBJ) # 定义目标libdtudent.so,依赖于目标文件
$(CC) $(METHOD) $@ $^ # 编译命令,$@表示目标文件名,$^表示所有的依赖文件
%.o: %.c # 定义模式规则,.o文件依赖于对应的.c文件
$(CC) $(HEAD) -c $(FP) $< -o $@ # 编译命令,$<表示依赖文件,$@表示目标文件
$(TARGET): $(MAIN) $(SO) # 定义目标app,依赖于main.c和libdtudent.so
$(CC) $(HEAD) -o $@ $^ # 编译命令,$@表示目标文件名,$^表示所有的依赖文件
clean: # 定义目标clean,用于清理编译生成的文件
rm -f $(OBJ) $(SO).$(VERSION) $(TARGET) $(SO) # 删除命令
实际运用的时候,记得把注释去掉,可能会因为空格导致一些路径出现问题
有的时候会出现错误
gcc -fPIC -shared -o libstudent.so c_code/student.o
/usr/bin/ld: c_code/student.o: relocation R_X86_64_PC32 against symbol `year_cmp' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status
make: *** [makefile:18: libstudent.so] Error 1
具体原因不明,手动执行
gcc -I ./h_code/ -c -fPIC c_code/student.c -o c_code/student.o
gcc -shared -o libstudent.so c_code/student.o
gcc -I ./h_code/ -o app c_code/main.c libstudent.so
也即是makefile文件内执行的语句,发现make又能正常运行了
网上有一个解释,但由于没有再出现这个错误,就没有再尝试了relocation R_X86_64_PC32 against symbol ff_pw_9 can not be used when making a shared object-阿里云开发者社区 (aliyun.com)
经过大佬提醒,编译动态库最好不在makefile内进行,最好在脚本内执行。makefile和脚本有一定区别