windows下gun环境
MinGW
配置path
比如 D:/MinGW 是安装目录
D:/MinGW/msys/1.0/etc/profile
export PATH=/d/MinGW/bin:$PATH
不依赖
Cygwin
庞大,把windows的api全部做一个在linux下的转换
GCC
编译过程是分为四个阶段进行
预处理(也称预编译,Preprocessing)
编译(Compilation)
汇编 (Assembly)
连接(Linking)
1.预处理
hello.c文件
#include <stdio.h>
main(){
printf("hello word\r\n");
}
-E 可以让编译器在预处理后停止,并输出预处理结果,在本例中,预处理结果就是将stdio.h 文件中的内容插入到hello.c中了
-o 指定处理结果路径
gcc -E hello.c -o hello.i 或 gcc -E hello.c
可以输出hello.i文件中存放着hello.c经预处理之后的代码
打开hello.i文件,就明白了,后面那条指令,是直接在命令行窗口中输出预处理后的代码
2.编译为汇编代码(Compilation)
gcc -S hello.i -o hello.s
预处理之后,可直接对生成的hello.i文件编译,生成汇编代码
g-S选项,表示在程序编译期间,在生成汇编代码后,停止 -o输出汇编代码文件
3.汇编(Assembly)
对于生成的hello.s
gas汇编器负责将其编译为目标文件
gcc -c hello.s -o hello.o
可使用nm hello.o查看符号和链接
4.连接(Linking)
gcc连接器是gas提供的,负责将程序的目标文件与所需的所有附加的目标文件连接起来
最终生成可执行文件,附加的目标文件包括静态连接库和动态连接库。
对于hello.o,将其与C标准输入输出库进行连接,最终生成程序hello
gcc hello.o -o hello
多个程序的编译
通常整个程序是由多个源文件组成的
相应地也就形成了多个编译单元,使用GCC能够很好地管理这些编译单元
假设有一个由hello1.c和 hello2.c两个源文件组成的程序,为了对它们进行编译,并最终生成可执行程序test,可以使用下面这条命令:
gcc hello1.c hello2.c -o hello
如果同时处理的文件不止一个
GCC仍然会按照预处理、编译和链接的过程依次进行
如果深究起来,上面这条命令大致相当于依次执行如下三条命令:
gcc -c hello1.c -o hello1.o
gcc -c hello2.c -o hello2.o
gcc hello1.o hello2.o -o hello
gcc参数
1. gcc -E source_file.c
-E,只执行到预编译,直接输出预编译结果
2. gcc -S source_file.c
-S 只执行到源代码到汇编代码的转换,输出汇编代码
3. gcc -c source_file.c
-c 只执行到编译,输出目标文件。
4. gcc (-E/S/c/) source_file.c -o output_filename
-o, 指定输出文件名,可以配合以上三种标签使用
-o 参数可以被省略。这种情况下编译器将使用以下默认名称输出:
-E:预编译结果将被输出到标准输出端口(通常是显示器)
-S:生成名为source_file.s的汇编代码
-c:生成名为source_file.o的目标文件。
无标签情况:生成名为a.out的可执行文件。
5. gcc -g source_file.c
-g 生成供调试用的可执行文件 可以在gdb中运行 由于文件中包含了调试信息因此运行效率很低,且文件也大不少
这里可以用strip命令重新将文件中debug信息删除。
这是会发现生成的文件甚至比正常编译的输出更小了
这是因为strip把原先正常编译中的一些额外信息(如函数名之类)也删除了,用法为 strip a.out
6. gcc -s source_file.c
-s, 直接生成与运用strip同样效果的可执行文件(删除了所有符号信息)
7. gcc -O source_file.c
-O(大写的字母O),编译器对代码进行自动优化编译,输出效率更高的可执行文件
-O 后面还可以跟上数字指定优化级别,如:
gcc -O2 source_file.c
数字越大,越加优化但是通常情况下,自动的东西都不是太聪明,太大的优化级别可能会使生成的文件产生一系列的bug
一般可选择2;3会有一定风险
8. gcc -Wall source_file.c
-W 在编译中开启一些额外的警告(warning)信息。-Wall,将所有的警告信息全开
9. gcc source_file.c -L/path/to/lib -lxxx -I/path/to/include
-l 指定所使用到的函数库,本例中链接器会尝试链接名为libxxx.so的函数库
-L 指定函数库所在的文件夹,本例中链接器会尝试搜索/path/to/lib文件夹
-I, 指定头文件所在的文件夹,本例中预编译器会尝试搜索/path/to/include文件夹
#include <stdio.h> void main(int argc,char *argv[]){ int arr[10],i=0; for(i=0;i<10;i++){ arr[i]=i; if(DEV){ printf("arr[%d]=%d\n",i,arr[i]); } } }
-D name选项 预定义名称为name的宏,值为1
-D name=definition 定义一个名称为name值为definition的宏
-U name 取消名称为name的宏定义
-undef 取消任何与操作系统相关或者gcc编译器相关的宏定义,而标准所定义的宏仍然有效
gcc -D DEV -o debug debug.c
gcc -D DEV=0 -o debug debug.c
gcc -D DEV=1 -o debug debug.c
-pedantic :够帮助程序员发现一些不符合 ANSI/ISO C标准的代码(并不是全部)
-Werror: 可以让gcc在编译中遇到错误时停止继续
-Wall: 让gcc显示警告信息
-w: 禁止所有警告信息
-ansi 等价于 -std=c89 ,该选项指定源程序使用ISO C90标准,将gcc编译中与iso C90标准相冲突的特征关闭
-g:使之可用gdb调试
-O:编译器设法减小代码长度及执行时间,但不会进行发费大量编译时间的的优化
-O1:1级优化,优化编译功能需要更多时间及大量的内存
-O2:进一步优化,此时,gcc执行几乎所有支持的不涉及空间和速度平衡的优化。与-O比,它既增加编译时间,也提高所产生代码的性能
-O3:比-O2更进一步的优化
-O0:默认选项,不进行优化
-Os:对代码大小进行优化,使所生成的代码长度最小化
-l library或-llibrary: 该选项指定在编译时所搜索的库名称
GCC按照所指定的顺序搜索库,如 "foo.o -lfunc bar.o" 系统将在foo.o之后bar.o之前查找函数的定义并进行链接。
如果bar.o使用了func库中的函数,该函数将不会被加载,因此必须注意库文件的顺序。
链接器根据名字liblibrary.so(系统自动在库名字前加上lib,后面加上.so) 在标准目录查找库文件,这些目录包括系统默认目录及在-L选项所指定的库文件搜索路径
#include <stdio.h> #include <math.h> int main(){ printf("hello world\n"); double pi=3.1415926; printf("sin(pi/2)=%f\n",sin(pi/2)); return 0; } [root@centos1 gcc]# gcc math.c /tmp/cc2gHQxo.o: In function `main': math.c:(.text+0x32): undefined reference to `sin' collect2: ld 返回 1
gcc -o math math.c -lm
gcc的sin函数是定义在libm.so里面,
用-l选项定义指定的路径。不填写的话默认是/lib和/usr/lib64内
因为linux下所有的函数库都是以lib开头的。所以除去头和尾,那么m就是代表libm.so
-static:表示在编译时强制使用对应的静态链接库(.a结尾的文件)
-shared:创建共享库,它所创建的动态文件以.so结尾
-fPIC:如果目标机器环境支持,该选项产生于位置无关的适合静态库使用的代码。在编译库文件时需要使用该选项