gcc的编译过程
预处理(pre-processing)
gcc -E hello.c -o hello.i
预处理过程如下:
1. 头文件展开ps把#include的文件插入到相应位置
2.宏展开ps展开所有的宏,并删除#define
3.条件编译ps条件预编译指令比如:#if,#ifdef,#else
4.删除注释ps // /**/的内容
5.添加行号和文件名标识
6.保留#pragrma命令ps指示编译器完成特定的动作
//config.h
#define DEMO_CONFIG_H "yyyy"
//main.c
#include <stdio.h>
#define ss 123
#include "config.h"
#ifdef DEMO_CONFIG_H
void pp(){
printf( "hello ARM\n");
}
#else
void pp(){
printf( "hello x86\n");
}
#endif
#pragma message("over me")
int main() {
pp();
printf("%d",ss);
return 0;
}
经过预处理得
# 412 "/usr/include/stdio.h" 2 3 4
# 2 "main.c" 2
# 1 "./config.h" 1
# 4 "main.c" 2
void pp(){
printf( "hello ARM\n");
}
#pragma message("over me")
int main() {
pp();
printf("%d",123);
return 0;
}
编译(Compiling)
gcc -S hello.i -o hello.s
编译成汇编(翻译成中间代码,具体参考编译原理)
汇编(Assembling)
gcc -c hello.s -o hello.o
编译成目标文件(将中间代码翻译成机器码)
链接 (Linking)
gcc hello.o -o hello
链接到库中,变成可执行文件
//cclib.c
#include <stdio.h>
void pp(){
printf("88888888\n");
}
//config.h
void pp();
//main.c
#include <stdio.h>
#define ss 123
#include "config.h"
#pragma message("over me")
int main() {
pp();
printf("%d",ss);
return 0;
}
gcc常用选项
选项名 | 作用 |
---|---|
o | 生成目标 |
c | 取消链接步骤,编译源码并最后生成目标文件 |
E | 只运行C预编译器(头文件,宏等展开) |
S | 生成汇编语言文件后停止编译(.s文件) |
Wall | 打开编译告警(所有) |
g | 嵌入调试信息,方便gdb调试 |
llib | 链接 lib 库 (这里是小写 L ) 相当于 C++ #pragma comment(lib, “xxx.lib”) |
Idir | 增加 include 目录 (这里是大写 i ) 头文件路径 |
LDir | 增加 lib 目录 (编译静态库和动态库) |
静态库(.a)
程序在编译链接时候把库的代码链接到可执行文件中。程序运行时候,不再需要静态库,生成的可执行文件大,每个可执行文件都会加载一份拷贝到内存
gcc -c cclib.c ##生成cclib.o文件
ar rcs libcc.a cclib.o##把cclib.o文件打包入libcc.a中(注意这边一定要lib开头)
gcc main.c -o main -L. -lcc##-lcc指定包,前面lib省略
或者
gcc main.c libcc.a -o main
静态库搜索路径
1:编译使用选项 –L 指定的目录(建议)
2:修改环境变量,export LIBRARY_PATH=“库目录”
3:lib文件放入系统指定目录,例如/usr/lib/等
共享库(.so或.sa)
程序运行时候才去链接共享库代码,多个程序共享使用,使用时候只需要加载一份到内存
gcc -c cclib.c ##生成cclib.o文件
gcc -c main.c ##生成main.o文件
gcc –shared –fPIC cclib.o –o libFun.so ##把cclib.o文件打包入libFun.so中(注意这边一定要lib开头)
gcc main.o -o mainw -L. -lFun##-lFun指定包,前面lib省略
或者
gcc main.o libFun.so -o mainw
配置方式
1:拷贝到so文件到共享库目录 /usr/lib/
2:修改环境变量 LD_LIBRARY_PATH
3:配置 /etc/ld.so.conf; 并使用 ldconfig 命令进行更新
makefile基础
当项目越来越大,c文件越来越多,用gcc命令来手动编译明显不现实。
工程管理器,顾名思义,是指管理较多的文件,Make工程管理器也就是个“自动编译管理器”,这里的“自动”是指它能够根据文件时间戳自动发现更新过的文件而减少编译的工作量。
关于makefile语法规则请浏览《Makefile教程(绝对经典,所有问题看这一篇足够了)》,里面讲述的超详细。