gcc/g++编译优化选项(一)

时间:2022-04-24 00:59:07

介绍

  1. 什么是CFLAGS和CXXFLAGS
    人们用环境变量CFLAGS和CXXFLAGS来告诉GNU编译器集合(GNU Compiler Collection),即gcc,在编译源代码时使用哪些选项。CFLAGS用于C代码,CXXFLAGS用于C++代码。
    它们可以用来减少程序的调试信息数量,增加错误警告等级以及优化代码的生成。GNU gcc手册上维护着一个可用的选项及其作用的完整列表。
  2. 如何使用?
    使用CFLAGS和CXXFLAGS有两种方法。第一,在每个程序由automake生成的Makefile中使用。
    但是,安装Portage树中的软件包时并不能这么干,而要在/etc/make.conf中设置CFLAGS和CXXFLAGS。这样所有的软件包都会用你指定的选项来编译。

    /etc/make.conf中的CFLAGS

CFLAGS="-march=athlon64 -O2 -pipe"
CXXFLAGS="${CFLAGS}"

如你所见,用CFLAGS中的所有选项来设置CXXFLAGS。在多数情况下这就是你想要的。你可以不用为CXXFLAGS指定额外的选项了。

优化基础
使用CFLAGS和CXXFLAGS的目的是生成契合你系统的代码。如果可以的话,应该能在完美运行之外还能生成精简而快速的代码。但有时候鱼与熊掌不可兼得,所以我们会选择已知没有问题的选项组合。理想来说,它们在所有的CPU构架上都有提供。我们也会在稍后提到激进的标记以便让你知道该注意些什么。我们不会讨论到在gcc手册中提到的每一个选项(有上百个之多),但是基本的,常用的标记都会涵盖到。
注意: 当你不能确定一个标记的作用时,请查阅gcc手册的相关章节。如果还有疑问,试试Google,或者检索gcc邮件列表。

-march
第一个重要的选项是-march。这个选项告诉编译器该为你的处理器架构(architecture)(或arch)生成何种代码,它告诉编译器只为特定类型的CPU生成代码。不同的CPU具有不同的能力,支持不同的指令集,以及不同的执行代码方式。-march标记指示编译器根据你CPU的能力、特征、指令集、怪癖等生成特定的代码。
即使/etc/make.conf中的CHOST变量指定了所使用的通用构架,-march还是可以用来为特定的处理器优化程序。x86和x86-64(也包括其他的)的CPU尤其应该利用-march标记。
你用哪种类型的CPU?用以下命令检测:

检测CPU信息

 $ cat /proc/cpuinfo 

-mtune和-mcpu标记也是可用的。这两个标记通常只在没有-march选项的时候才用到;特定的处理器可能要求使用-mtune甚至-mcpu。糟糕的是,gcc在不同构架上的表现并非完全一致。
对于x86和x86-64的CPU,-march将使用所指定CPU的全部可用指令集和正确的ABI来生成代码;并不会向后兼容其他旧的或者不同的CPU。如果你只需要在你当前运行Gentoo的机器上执行代码,那么就可以继续使用-march。只有在为i386和i486之类的旧CPU生成代码时,才需要考虑使用-mtune。使用-mtune生成代码比使用-march更通用;虽然它能为特定的CPU优化代码,但是并不会使用特有的指令集和ABI。别在x86或x86-64系统上使用-mcpu,因为在这两个构架上已经废弃了。
只有非x86/x86-64 CPU(如Sparc、Alpha和PowerPC)可能要求使用-mtune或-mcpu来代替-march。在这些构架上,-mtune/-mcpu的行为有时就像(x86/x86-64上的)-march,只是换了个名称。gcc在诸构架上的行为和标记的命名并不一致。所以请查阅gcc手册来确认在你的系统上该用哪个。
注意: 要获得更多-march/-mtune/-mcpu设置的建议,请阅读你的构架对应的Gentoo安装手册。还有就是gcc手册上的架构特有选项列表,其中更加详细地解释了-march、-mcpu和-mtune之间的区别。

-O
接下来是-O变量。这个选项控制所有的优化等级。使用优化选项会使编译过程耗费更多的时间,并且占用更多的内存,尤其是在提高优化等级的时候。
-O设置一共有五种:-O0、-O1、-O2、-O3和-Os。你只能在/etc/make.conf里面设置其中的一种。
除了-O0以外,每一个-O设置都会多启用几个选项,请查阅gcc手册的优化选项章节,以便了解每个-O等级启用了哪些选项及它们有何作用。
让我们来逐一考察各个优化等级:
-O0
这个等级(字母“O”后面跟个零)关闭所有优化选项,也是CFLAGS或CXXFLAGS中没有设置-O等级时的默认等级。这样就不会优化代码,这通常不是我们想要的。
-O1
这是最基本的优化等级。编译器会在不花费太多编译时间的同时试图生成更快更小的代码。这些优化是非常基础的,但一般这些任务肯定能顺利完成。
-O2
-O1的进阶。这是推荐的优化等级,除非你有特殊的需求。-O2会比-O1启用多一些标记。设置了-O2后,编译器会试图提高代码性能而不会增大体积和大量占用的编译时间。
-O3
这是最高最危险的优化等级。用这个选项会延长编译代码的时间,并且在使用gcc4.x的系统里不应全局启用。自从3.x版本以来gcc的行为已经有了极大地改变。在3.x,-O3生成的代码也只是比-O2快一点点而已,而gcc4.x中还未必更快。用-O3来编译所有的软件包将产生更大体积更耗内存的二进制文件,大大增加编译失败的机会或不可预知的程序行为(包括错误)。这样做将得不偿失,记住过犹不及。在gcc 4.x.中使用-O3是不推荐的。
-Os
这个等级用来优化代码尺寸。其中启用了-O2中不会增加磁盘空间占用的代码生成选项。这对于磁盘空间极其紧张或者CPU缓存较小的机器非常有用。但也可能产生些许问题,因此软件树中的大部分ebuild都过滤掉这个等级的优化。使用-Os是不推荐的。
正如前面所提到的,-O2是推荐的优化等级。如果编译软件出现错误,请先检查是否启用了-O3。再试试把CFLAGS和CXXFLAGS倒回到较低的等级,如-O1甚或-O0 -g2 -ggdb(用来报告错误和检查可能存在的问题),再重新编译。
-pipe
-pipe是个安全而有趣的标记。它对代码生成毫无影响,但是可以加快编译过程。此标记指示编译器在不同编译时期使用pipe而不是临时文件。
-fomit-frame-pointer
这是个用来削减代码尺寸的常用标记。在所有不影响除错(例如x86-64)的构架上,所有的-O等级(除了-O0)中都启用了它,但是也可能需要手动添加到你的标记中。尽管GNU gcc手册没有明确指出-O会启用这个标记的所有构架,你需要在x86上手动启用它。使用这个标记会使除错难以进行。
特别的,它会使排查Java程序的故障变得困难,尽管Java代码并不是唯一受此选项影响的代码。所以此标记虽然有用,但也会使除错变得困难,特别是backtrace将变得毫无用处。然而,你不准备做软件除错并且没有在CFLAGS中加入-ggdb之类与除错相关的标记的话,那就可以试试-fomit-frame-pointer。
重要: 请勿联合使用-fomit-frame-pointer和与之相似的-momit-leaf-frame-pointer。开启后者并无多大用处,因为-fomit-frame-pointer已经把事情搞定了。此外,-momit-leaf-frame-pointer还将降低代码性能。

-msse, -msse2, -msse3, -mmmx, -m3dnow
这些标记启用了x86和x86-64构架的SSE、SSE2、SSE3、MMX和3DNow!指令集。他们主要用于多媒体,游戏,及其他浮点运算密集的任务,虽然也包括了一些其他的数学增强指令。比较新的CPU都具有这些指令。
重要: 运行cat /proc/cpuinfo以确认你的CPU是否支持这些指令集。输出会包括所有支持的指令集。注意pni是SSE3的别名。

只要正确设置了-march就不需要添加额外的标记(例如,-march=nocona暗含了-msse3)。要注意的是一些新的VIA和AMD64 CPU包含了-march并不隐含的指令集(例如SSE3)。对于这些CPU就需要在检查cat /proc/cpuinfo输出之后手动加入适当的标记。
注意: 请查阅x86和x86-64特定标记列表以便确认适当的CPU类型标记启用了哪些指令集。如果某指令集已经列出了,就会由对应的-march设定开启,不再需要手动加入了。

http://blog.csdn.net/attagain/article/details/18655485