一、简介
1.1 什么是GCC
GCC(GNU Compiler Collection)是由GNU开发的编程语言译器 GNU编译器套件包括C、C++、 Objective-C、 Fortran、Java、Ada和Go语言前端,也包括了这些语言的库(如libstdc++,libgcj等)
1.2 GCC、gcc、g++三者关系
gcc(GUN C Compiler)是GCC中的c编译器 g++(GUN C++ Compiler)是GCC中的c++编译器 两者都可以编译c和cpp文件,但存在差异;gcc在编译cpp时语法按照c来编译,但默认不能链接到c++的库
二、源代码处理流程
源代码到可执行文件经历预处理、编译、汇编、链接几个过程; 实际调用程序
预编译和编译程序:ccl 汇编器:as 链接器:ld
#include <stdio.h>
int main ( void )
{
printf ( "nihao\n" ) ;
return 0 ;
}
2.1 预编译
预编译又称为预处理,是做些代码文本的替换工作。是整个编译过程的最先做的工作。
2.1.1 处理规则
删除所有的#define
,展开所有的宏定义。 处理所有条件编译指令,如#if,#endif、#ifdef,#elif 和 #else
处理#include
指令,将文件内容替换到对应位置,该过程递归实现 删除所有注释,//、/* */
保留所有的#program编译指令,编译器需要使用 添加行号和文件标识,便于编译时编译器产生调试用的行号信息,和编译时产生编译错误或警告是能够显示行号
2.1.2 操作示例
$gcc -E hello.c -o hello.i
$gcc -E -C hello.c -o hello.i
2.2 编译
编译程序:将某一种程序设计语言写的程序翻译成等价的另一种语言 的程序的程序,称之为编译程序(compiler) 把预编译之后生成的xxx.i或xxx.ii文件,进行一系列词法分析、语法分析、语义分析及优化 后,生成相应的汇编代码(.s)
文件
2.2.1 处理说明
词法分析:将字符串序列分割成一系列的记号 语法分析:语法树是一种以表达式为节点的树,同时将运算符的优先级确定下来 语义分析:对静态语义的分析,包含:声明和类型的匹配,类型的转换 优化: 目标代码生成:生成汇编表示的代码序列 目标代码优化:目标代码优化器对上述代码进行优化:寻找合适的寻址方式、使用位移来替代乘法运算、删除多余的指令等
2.2.2 操作示例
$gcc -S hello.i -o hello.s
2.3 汇编
将汇编代码转变成机器可执行的指令(机器码文件);生成目标文件.o(windows下)、.obj(Linux下)
根据汇编指令和机器指令的对照表一一翻译过来 汇编过程有汇编器as完成
2.3.1 操作示例
$gcc -c hello.s -o hello.o
2.4 链接
目标文件已经是二进制文件,与可执行文件的组织形式类似,只是有些函数和全局变量的地址还未找到,因此还无法执行。 链接的作用就是找到这些目标地址,将所有的目标文件组织成一个可以执行的二进制文件。
#ifndef __TEST_H_
#define __TEST_H_
int add ( int a, int b) ;
int sub ( int a, int b) ;
int div ( int a, int b) ;
#endif
#include "test.h"
int add ( int a, int b)
{
return a + b;
}
#include “test.h”
int sub ( int a, int b)
{
return a - b;
}
#include “test.h”
int div ( int a, int b)
{
return a / b;
}
#include <stdio.h>
#include "test.h"
int main ( void )
{
int m, n;
printf ( "Input two numbers: " ) ;
scanf ( "%d %d" , & m, & n) ;
printf ( "%d+%d=%d\n" , m, n, add ( m, n) ) ;
printf ( "%d-%d=%d\n" , m, n, sub ( m, n) ) ;
printf ( "%d÷%d=%d\n" , m, n, div ( m, n) ) ;
return 0 ;
}
2.4.1 链接其他目录中的库
$gcc main.c -o main.out /usr/lib/libm.a
$gcc main.c -o main.out -L/usr/lib -lm
2.4.2 静态链接库的创建和使用
1. 创建
源文件中只提供可以重复使用的代码,例如函数、设计好的类等,不能包含 main 主函数; 源文件在实现具备模块功能的同时,还要提供访问它的接口,也就是包含各个功能模块声明部分的头文件。
将所有指定源文件,都编译成相应的目标文件 然后使用 ar 压缩指令,将生成的目标文件打包成静态链接库
$gcc -c sub.c add.c div.c
$ar rcs libmymath.a add.o sub.o div.o
2. 使用
将main.c文件编译为目标文件 执行链接命令
$gcc -c mian.c
$gcc -static main.o libmymath.a
$gcc main.o -static -L /root/demo -lmymath
2.4.3 动态链接库的创建和使用
1. 创建
直接使用源文件创建动态链接库
$gcc -fpic -shared 源文件名.. . -o 动态链接库名
先使用 gcc -c 指令将指定源文件编译为目标文件
$gcc -c -fpic add.c sub.c div.c
$gcc -shared add.o sub.o dic.o -o libmymath.so
2. 使用
$gcc main.c libmymath.so -o main.out
$./main.out
./main.out: error while loading shared libraries: libmymath.so: cannot open shared object file: No such file or directory
通过ldd main.out查看当前文件在执行时需要的所有动态链接库,以及存储位置 常用解决方案
将链接库文件移动到标准库目录下(例如 /usr/lib、/usr/lib64、/lib、/lib64); 在终端输入export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx,其中 xxx 为动态链接库文件的绝对存储路径(此方式仅在当前终端有效,关闭终端后无效); 修改~/.bashrc 或~/.bash_profile 文件,即在文件最后一行添加export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx(xxx 为动态库文件的绝对存储路径)。保存之后,执行source .bashrc指令(此方式仅对当前登陆用户有效)。