Chinaunix首页 | 论坛 | 博客
  • 博客访问: 444469
  • 博文数量: 72
  • 博客积分: 3186
  • 博客等级: 中校
  • 技术积分: 1039
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-07 16:53
文章分类

全部博文(72)

文章存档

2012年(1)

2011年(5)

2010年(10)

2009年(56)

我的朋友

分类: C/C++

2009-09-21 09:56:23

gcc会用,但只会最简单的命令。最近弄bootloader,发现自己很多基础知识都掌握的极其肤浅。接触都这么久了,仍然停留在这一个地步未能深入,不得不汗顔。
还没有看gnu gcc 的Using the GNU Compiler Collection,一来,这个文档很大,短时间能不可能看完,未来一段时间内都排不到学习计划中;二来自己的很多基础都没有打好,这样硬着去看,效果不会太好。
这里总结一下gcc的使用,不全面,只求能够满足暂时的使用要求。


运行gcc时相关程序和命令:

as             汇编器
ld            链接器
gdb            调试器
nm            列出目标文件中定义的符号
objcopy        将目标文件从一种二进制格式复制和翻译到另一种
objdump        显示一个或多个目标文件中保存的多种不同信息
size        列出目标文件中每个部分的名字和尺寸
strip        去掉目标文件中的符号信息以及调试所用的信息


------------------------------------------------------------------------------------------------------------------------


gcc常用选项:

-E                 仅作预处理,不进行编译,汇编和链接
-S                编译到汇编语言,不进行汇编和链接
-c                编译,汇编到目标代码,不进行链接
-o <文件>        输出到<文件>
-x <语言>        指定其后输入文件的语言
-v                 显示命令执行的具体步骤
-###             与-v类似,但行期被引号括住,且不执行命令
-Xassembler <参数>     将<参数>传递给汇编器
-Xpreprocessor <参数>     将<参数>传递给预处理器
-Xlinker <参数>     将<参数>传递给链接器


------------------------------------------------------------------------------------------------------------------------


拿hello world 为例:
分步执行gcc
1. 预处理(pre-processing)
gcc -E hello.c -o hello.i

选项     操作                 生成文件
 -E     预处理,但不编译     对.c文件进行预处理后的结果 .i
 -S     编译,但不汇编         .s文件(汇编文件)
 -c     汇编,但不链接         .o文件(目标文件)

2. 编译,生成.s的汇编文件
 这一阶段根据输入文件产生汇编语言指令.由于通常情况下是立即调用汇编程序as,所以输出一般不保存大文件中,可以使用-c选项完成:

 gcc -S hello.i -o hello.s

 -x告诉gcc从指定的步骤开始编译.gcc通过依靠文件扩展名来决定如何处理该文件.

3. 汇编,生成目标文件
 gcc -c hello.s -o hello.o
 (as hello.s -o hello.o)

4. 链接(ld还不太会用,所以直接用gcc替换)
 gcc hello.o -o hello


------------------------------------------------------------------------------------------------------------------------


所有的这些,我们只需要一句:
gcc hello.c -o hello
即可完成所有步骤

gcc的执行过程并不是一气呵成的,其中大体经历了以下几个步骤:
1. 调用预处理器程序cpp,对源文件进行预处理
2. 调用as将源代码编译成目标代码
3. 调用链接程序ld把生成的目标代码链接成一个可执行程序


我们来看一下:
--------------------------------------------------------------------------------------------------------------------------

#include <stdio.h>

int
main(void)
{
        printf("Hello World!\n");
        return 0;
}


gcc -### hello.c -o hello   /* 这个命令可以看到执行的具体步骤,但不进行编译*/
Using built-in specs.
Target: i586-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl= --enable-bootstrap --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre --enable-libgcj-multifile --enable-java-maintainer-mode --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libjava-multilib --with-ppl --with-cloog --with-tune=generic --with-arch=i586 --build=i586-redhat-linux

Thread model: posix
gcc version 4.4.0 20090506 (Red Hat 4.4.0-4) (GCC)
COLLECT_GCC_OPTIONS='-o' 'hello' '-mtune=generic' '-march=i586'
 "/usr/libexec/gcc/i586-redhat-linux/4.4.0/cc1" "-quiet" "hello.c""-quiet" "-dumpbase" "hello.c" "-mtune=generic" "-march=i586""-auxbase" "hello" "-o" "/tmp/cchjnnyU.s"
COLLECT_GCC_OPTIONS='-o' 'hello' '-mtune=generic' '-march=i586'    /* 上面一句编译到了汇编文件,生成‘.s’汇编文件 */


 "as" "-Qy" "-o" "/tmp/ccOF4DiF.o" "/tmp/cchjnnyU.s"    /*这一句汇编,生成目标文件*/
COMPILER_PATH=/usr/libexec/gcc/i586-redhat-linux/4.4.0/:/usr/libexec/gcc/i586-redhat-linux/4.4.0/:/usr/libexec/gcc/i586-redhat-linux/:/usr/lib/gcc/i586-redhat-linux/4.4.0/:/usr/lib/gcc/i586-redhat-linux/:/usr/libexec/gcc/i586-redhat-linux/4.4.0/:/usr/libexec/gcc/i586-redhat-linux/:/usr/lib/gcc/i586-redhat-linux/4.4.0/:/usr/lib/gcc/i586-redhat-linux/
LIBRARY_PATH=/usr/lib/gcc/i586-redhat-linux/4.4.0/:/usr/lib/gcc/i586-redhat-linux/4.4.0/:/usr/lib/gcc/i586-redhat-linux/4.4.0/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-o' 'hello' '-mtune=generic' '-march=i586'
 "/usr/libexec/gcc/i586-redhat-linux/4.4.0/collect2" "--eh-frame-hdr" "--build-id" "-m" "elf_i386" "--hash-style=gnu""-dynamic-linker" "/lib/ld-linux.so.2" "-o" "hello""/usr/lib/gcc/i586-redhat-linux/4.4.0/../../../crt1.o" "/usr/lib/gcc/i586-redhat-linux/4.4.0/../../../crti.o" "/usr/lib/gcc/i586-redhat-linux/4.4.0/crtbegin.o" "-L/usr/lib/gcc/i586-redhat-linux/4.4.0""-L/usr/lib/gcc/i586-redhat-linux/4.4.0" "-L/usr/lib/gcc/i586-redhat-linux/4.4.0/../../.." "/tmp/ccOF4DiF.o""-lgcc" "--as-needed" "-lgcc_s" "--no-as-needed" "-lc" "-lgcc""--as-needed""-lgcc_s" "--no-as-needed" "/usr/lib/gcc/i586-redhat-linux/4.4.0/crtend.o" "/usr/lib/gcc/i586-redhat-linux/4.4.0/../../../crtn.o"
/* 最后链接,生成目标文件 */

上面将关键的地方高亮了红色。中文注释是我加的,并不存在输出中。


--------------------------------------------------------------------------------------------------------------------------


编译的时候,还需要头文件和库,这个是非常重要的。
-I <目录路径>   gcc编译时有都几个默认的路径,这里向搜索路径中添加我们指定的目录。
-L <目录路径>   向库文件搜索路径中添加指定的目录
-l(小写的L) <库名> Linux下库文件名都是以lib开头的,用-l选项指定链接的库文件名时,省略lib三个字母。
默认的编译都是使用动态链接的,若要使用静态链接,gcc后面的选项中添加“-static”


--------------------------------------------------------------------------------------------------------------------------


警告提示功能:
大多都以 -W 的形式出现:

-Wcomment
           如果 "/*" 出现在注释中,则发出警告

-Wformat
           检查对printf和scanf等函数的调用,确认各个参数类型和格式的一致

-Wmain
           如果把main函数声明或定义成非法的类型,则发出警告

-Wparentheses
           某些情况下,若忽略了括号,则警告

-Wswitch
           有switch但没有case语句枚举元素,或case枚举超出了范围,则警告

-Wunused
           如果声明某变量,但却没有使用,警告

-Wuninitialized
           在初始化之前就使用自动变量,警告。

-Winline
           若某函数不能使用内嵌语句(inline),警告

-Wmissing-declarations
           没有声明就定义了全局函数,警告

-Wlong-long
           使用了long long 类型,则警告。此项为默认项。

-Werror
           发生警告时取消编译操作

另:还可使用 -Wall 开启警告,用以捕捉一些错误。这个选项也非常有用。



阅读(1080) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~