一、GCC编译器
-
概念
GCC 原名为 GNU C 语言编译器(GNU C Compiler),只能处理 C 语言。但其很快扩展,变得可处理 C++,后来又扩展为能够支持更多编程语言,如 Fortran、Pascal、Objective -C、Java、Ada、Go 以及各类处理器架构上的汇编语言等,所以改名 GNU 编译器套件(GNU Compiler Collection)
-
特点
GCC(特别是其中的 C 语言编译器)也常被认为是跨平台编译器的事实标准。 GCC 提供了 30 多条警告信息和 3 个警告级别,使用它们有助于增强程序的稳定性和可移植性。 GCC 还对标准的 C/C++ 语言进行了大量的扩展,提高了程序的执行效率,有助于编译器进行代码优化,能够减轻编程的工作量
-
安装GCC
#查看GCC是否安装 # 查看 gcc 版本 $ gcc -v $ gcc --version # 查看 g++ 版本 $ g++ -v $ g++ --version #gcc --version 如果已安装,显示如下信息 gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44) Copyright (C) 2015 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-
编译过程
1.预处理(Pre-Processing)(gcc -E main.c -o gcc.i) //将源码生成.i文件 主要做以下几件事,展开头文件、宏替换、删除注释行 生成已.i结尾的预处理文件,还是C源文件 2.编译(Compiling)(gcc -S main.i -o main.s)检查语法错误 // 将 .i文件编译生成汇编源码 gcc 检测代码规范性,语法错误 gcc 产生汇编代码, 已.s结尾的汇编源码文件 3.汇编(Assembling)(gcc -c main.s -o main.o)处理汇编为二进制文件 // 将汇编源码汇编成目标二进制文件 把编译阶段的.s文件转换成目标文件 gcc生成已.o结尾的目标二进制文件 4.链接(Linking)(gcc main.o -o test)链接库变为可执行文件 // 通过连接将目标文件变为可执行文件 gcc调用连接器,把需要连接的库进行连接,得到一个可执行文件 #以上4步骤可以合成一个步骤,详细过程如下, 1.预处理 通过添加-E 参数 将test.c生成预处理后的C文件test.i 通过-c参数指定文件名 gcc -E test.c -c test.i 2.编译 通过添加-S 参数 将 test.i预处理文件转换为汇编文件test.s gcc -S test.i 或 gcc -S test.i -o test.s 3.汇编 通过汇编获得二进制文件 gcc -c test.s gcc -c test.s -o test.o 4.连接 通过连接得到可执行文件 gcc test.o -o test
-
GCC常用选项
-c,只编译,不连接成为可执行文件,编译器只是由输入的.c等源代码文件生成.o为后缀的目标文件,通常用于编译不包含主程序的子程序文件。 -o output_filename,确定输出文件的名称为output_filename,同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出预设的可执行文件a.out。 -g,产生符号调试工具(GNU的gdb)所必要的符号资讯,要想对源代码进行调试,我们就必须加入这个选项。 -O,对程序进行优化编译、连接,采用这个选项,整个源代码会在编译、连接过程中进行优化处理,这样产生的可执行文件的执行效率可以提高,但是,编译、连接的速度就相应地要慢一些。 -O2,比-O更好的优化编译、连接,当然整个编译、连接过程会更慢。 -I dirname,将dirname所指出的目录加入到程序头文件目录列表中,是在预编译过程中使用的参数。 -L dirname,将dirname所指出的目录加入到程序函数档案库文件的目录列表中,是在链接过程中使用的参数。
-
条件编译
一般情况下,C语言源程序中的每一行代码都要参加编译。但有时候出于对程序代码优化的考虑,希望只对其中一部分内容进行编译,此时就需要在程序中加上条件,让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃,这就是条件编译(conditional compile)
1. 根据宏定义 #ifdef <macro> …… #else …… #endif 实例 #define _DEBUG_ #ifdef _DEBUG_ printf(“The macro _DEBUG_ is defined\n”); #else printf(“The macro _DEBUG_ is not defined\n”); #endif 2.根据宏的值 #if <macro> …… #else …… #endif 实例 #define _DEBUG_ 1 #if _DEBUG_ printf(“The macro _DEBUG_ is defined\n”); #else printf(“The macro _DEBUG_ is not defined\n”); #endif 3.编译时条件编译 #ifdef UMP_TO_FILE //do something here... #endif gcc myprogram.c -D UMP_TO_FILE -D加上宏UMP_TO_FILE,相当于你在代码中#define UMP_TO_FILE -D UMP_TO_FILE = 1,相当于你在代码中#define UMP_TO_FILE 1
-
生成静态库
gcc -o libstr.a string.o // lib+str是静态库名,通过目标文件生成静态库
-
使用静态库
第一种:gcc -o test hello.c libstr.a 第二种:gcc -o test hello.c -L ./ -lstr //-L指在指定目录中查找静态库,str库文件名
-
动态链接库
概念:动态链接库是程序运行时加载的库,当动态链接库安装成功后,所有的程序都可以使用动态链接库;动态链接库是目标文件的集合。动态链接库的名称有 别名(soname,有个前缀lib,例如libstr.so)、真名(realname)、连接名(linker name)
-
生成动态链接库
gcc -shared -Wl,soname,libstr.so -o libstr.so.1 string.c //-soname,libstr.so 表示生成的动态链接库的别名是libstr.so; //-o libstr.so.1 表示实际生成的动态链接库的名字 //-fpic 参数告诉gcc编译器生成的代码与位置无关,即相对位置 //-shared 告诉编译器生成一个动态库 //动态库制作 1.将源文件test.c 进行汇编生成test.o目标文件 gcc -fpic -c test.c -o test.o 2.将目标文件打包成动态库 gcc -shared test.o -o libtest.so
-
安装动态链接库
一般情况下将生成的动态链接库复制到默认的动态链接库的搜索路径下,例如/lib,/usr/lib,/usr/local/lib
-
动态链接库管理命令
为了让新增加的动态链接库能够被系统共享,需要运行ldconfig,作用是在默认搜索路径,动态链接库的配置文件中列出的目录中搜索动态链接库,当用户的动态链接库不在系统动态链接库配置文件/etc/ld.so.conf中时,通过ldconfig 用户目录,将用户指定目录中的动态链接库放入系统中共享
-
使用动态链接库
gcc -o test hello.c -L ./ -lstr // -L 指定搜索动态链接库的路径,-lstr 指定链接库的名字 //运行test发现报错,./test: error while loading shared libraries: libstr.so: cannot open shared object file: No such file or directory //这是因为程序运行时没有找到动态链接库,程序编译时的俩姐动态链接库和运行时连接动态链接库的概念是不一样的 // 运行时,程序连接的动态链接库必须时在系统搞得目录下才行。 //1. LD_LIBRARY_PATH是Linux环境变量名,该环境变量主要用于指定查找共享库(动态链接库)时除了默认路径之外的其他路径 为什么修改LD_LIBRARY_PATH呢 因为运行时动态库的搜索路径的先后顺序是: 1.编译目标代码时指定的动态库搜索路径; 2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径; 3.配置文件/etc/ld.so.conf中指定的动态库搜索路径; 4.默认的动态库搜索路径/lib和/usr/lib; //如果系统路径下同时存在静态链接库和动态链接库,默认有限连接动态链接库。如果强制连接静态链接库,增加-static gcc -o test hello.c -static -lstr
-
GCC常用参数
gcc 编译选项 解释说明
-E 预处理,主要是进行宏展开等步骤,生成 test.i -S 编译指定的源文件,但是不进行汇编,生成 test.s -c 编译、汇编源文件,但是不进行链接,生成 test.o -o 指定链接的文件名及路径 -g 在编译的时候,生成调试信息,该程序可以被调试器调试 -D 在程序编译的时候,指定一个宏 -std 指定 C 方言,如 -std=c99。gcc 默认的方言是 GNU C -l 在程序编译的时候,指定使用的库(库的名字一定要掐头去尾,如 libtest.so 变为 test) -L 在程序编译的时候,指定使用的库的路径 -fpic 生成与位置无关的代码 -shared 生成共享目标文件,通常用在建立动态库时