什么是gcc、什么是g++?
gcc和g++都是GNU(组织)的一个编译器。
但两者有一些区别:后缀为.c的文件gcc把它当做c程序,g++当做c++程序。后缀为c++的两者都当做c++程序。对于cpp程序,无论gcc或者是g++编译阶段都是相同的,都是用的gcc进行编译,但是在链接阶段gcc不能自动和c++程序使用的库连接,如果使用的话,形如下: gcc helloworld.cpp -lstdc++ -o helloworld
所以我们通常用g++来进行连接(g++会自动连接c++常用库),所以为了使用方便对于cpp程序干脆编译链接统统都使用g++,这样就给人一种错觉,好像cpp只能用g++编译。
Gcc编译处理过程是什么呢?
下面以helloworld程序为例去进行解释过程:
其中hello.c的内容如下:
#include
int main()
{
printf("hello world\n");
}
第一步:预处理
预处理阶段过程如下,预处理阶段是进行处理代码中的宏和include指令,并作语法检查。这一过程的命令为:# gcc -E hello.c -o hello.i 执行这一部生成了一个hello.i文件,如下:
可以看到由于进行了预处理,将include内部的文件进行了替换,预处理后的结果文件显得特别大,所以在以后的程序中,没有用到的头文件最好不要引入,这样会降低处理时间和空间。
第二步:汇编程序生成汇编码
可以看出生成的汇编程序为59行。
第三步:由汇编程序转换为中间目标文件
这一步是将汇编的代码进一步进行处理,每一个源程序都会生成相应的目标文件,是以.o为扩展名的文件。命令如下:
第四步:连接目标文件,生成可执行程序
这一阶段被称为链接阶段,这一阶段完成的是将目标文件进行连接生成相应的最终目标文件(可执行文件或静态库或动态库)
好了,这样例子中的可执行文件就生成了hello,运行一下为:
如何使用g++编译动态库\静态库?如何使用g++连接非标准库和应用程序?
什么是库呢?简单的说库就是一组已经写好了的函数和变量、是经过编译了的代码,为了提高开发的效率和运行的效率而设计的。库可以分为静态库和动态库(共享库)两类,在linux系统中静态库的扩展名为.a,动态库的扩展名是.so。
静态库是在每个程序进行链接的时候将库在目标程序中进行一次拷贝,当目标程序生成的时候,程序可以脱离库文件单独运行,换言之原来的文件即使删除程序还是会正常工作。
共享库可以被多个应用程序共享,实在程序运行的时候进行动态的加载,因此对于每个应用程序来说,即使不再使用某个共享库,也不应该将其删除,因为其他的引用程序可能需要这个库。
1. 如何生成库
下面演示如何生成静态库和动态库:
生成静态库的过程是先将每个每个原文件进行编译生成中间目标文件,然后利用打包程序,将程序进行一次打包,最后生成静态库文件。以下面的例子说明问题:
目录结构为
包括3个文件,其中hello.c是用来生成静态库的源文件,hello.h是其头文件,test.c是其测试程序,用来测试库生成是否正确,在这个例子中我们会将hello.c生成libhello.a,然后用test.cpp进行连接,最后生成hello的可执行文件。
然后通过链接静态库文件,将test.c和libhello.a生成相应的应用程序testhello
在这个例子中,我们删除静态库后,程序依然正常运行。
下面通过生成动态库连接成为应用程序,生成动态库的命令是
gcc -shared -fPIC hello.c -o libhello.so这样就生成了动态库
在把so所在的路径在环境变量里添加上,注意应该添加到LD_LIBRARY_PATH中,另外还要运行命令ldconfig,此命令在/sbin/目录下。这样就能正常运行了。下面是测试:
如果删除之后,在运行就会:
从上面可知,如果在小的项目中使用gcc还是比较方便的,如果再大的工程中,我们必须记住gcc命令,如果想让程序做移植的话,必须还得充足的文档才能管理大项目。下面提供一种解决方法,通过makefile来解决这些问题,当你移植你的程序时只需要做简单的操作,就能成功生成相应的二进制文件,从而简化了大项目的管理等问题。
GCC编译器的选项解读
1. 基本选项
-E是只进行预处理选项,不进行编译、汇编、以及连接
-S 编译后停止,不进行会变和连接
-c编译或会汇编文件,但不进行连接
-o file 指定输出文件名
2. 警告选项
-Wall 启用所有警告信息
-Werror 在发生警告时取消编译操作,即将警报看作是错误
-w 禁用所有警告信息
3. 优化选项
-O0:不进行优化处理
-O或-O1:进行基本的优化,这些优化在大所属情况下都会使程序执行的更快
-O2:除了完成-O1级别的优化外,还需要一些其他的调整工作,如处理器指令调度等,只是GNU发布软件的默认优化
-O3:除了完成-O2级别的优化外,还进行循环的展开(这往往会提高执行速度)以及其他的一些预处理器相关的优化工作。
-Os:生成最小的可执行文件,主要用在嵌入式领域。
4. 连接器选项
-Idirectory 向GCC的头文件搜索路径中添加新的目录
-Ldirectory 向GCC的库文件搜索路径中添加一个行的目录
-llibrary 提示连接程序在创建可执行文件时包含指定的库文件
-static 强制使用静态库
-shared 强制使用共享库
5. 其他选项
-xlanguage 指定输入文件的编程语言
-v 显示编译器的版本号
-g 获得有关调试程序的详细信息
-ansi 支持符合ansi彼岸准的c程序
既然已经讲了这么多了索性再讲讲gcc使用的一些环境变量
除了大名鼎鼎的CFLAGS和CXXFLAGS以外(其实是Autoconf的环境变量),再挑几个说说:
所有的PATH类环境变量(除LD_RUN_PATH外)都是用冒号分割的目录列表。
C_INCLUDE_PATH 编译C程序时使用的环境变量,用于查找头文件。
CPLUS_INCLUDE_PATH 编译C++程序时使用的环境变量,用于查找头文件。
OBJC_INCLUDE_PATH 编译Obj-C程序时使用的环境变量,用于查找头文件。
CPATH 编译C/C++/Obj-C程序时使用的环境变量,用于查找头文件。
COMPILER_PATH 如果没有用GCC_EXEC_PREFIX定位子程序,编译程序将会在此查找它的子程序。
LIBRARY_PATH 连接程序将在这些目录中寻找特殊的连接程序文件。
LD_LIBRARY_PATH 该环境变量不影响编译程序,但是程序运行的时候会有影响:程序会查找该目录列表以寻找共享库。
当不能够在编译程序的目录中找到共享库的时候,执行程序必须设置该环境变量。
LD_RUN_PATH 该环境变量不影响编译程序,但是程序运行的时候会有影响:它在运行时指出了文件的名字,运行的程序可以由此得到它的符号名字和地址。
由于地址不会重新载入,因而可能符号应用其他文件中的绝对地址。这个和ld工具使用的"-R"选项完全一样。
GCC_EXEC_PREFIX 编译程序执行所有子程序的名字的前缀,默认值是"
其中的
LANG 指定编译程序使用的字符集,可用于创建宽字符文件、串文字、注释;默认为英文。[目前只支持日文"C-JIS,C-SJIS,C-EUCJP",不支持中文]
LC_ALL 指定多字节字符的字符分类,主要用于确定字符串的字符边界以及编译程序使用何种语言发出诊断消息;默认设置与LANG相同。
中文相关的几项:"zh_CN.GB2312 , zh_CN.GB18030 , zh_CN.GBK , zh_CN.UTF-8 , zh_TW.BIG5"
TMPDIR 编译程序存放临时工作文件的临时目录,这些临时文件通常在编译结束时被删除。
PS:从http://www.cppblog.com/Roger/archive/2011/11/14/160023.html#160106转来的