gcc编译

 

在windows环境,我们有集成开发环境(IDE),使得我们对编译器了解的很少。当我们专向linux时需要在命令行下编译自己的程序需要对编译器的 命令行参数比较熟悉。而如果是做嵌入开发构建自己的操作系统时失去了系统平台,需要我们对编译的过程以及可执行文件的内部结构有所了解。本文讲述了如何编 译可执行文件、静态库、动态库,如何优化编译器,如何编译无操作系统环境下的程序(自己的OS)等。

1.分析普通的helloworld程序
先书写一下一个简单的helloworld程序如下:

  1. /* hello.c */
  2. int main(int argc, char * argv[])
  3. {
  4. return 0
  5. }

编译程序:

gcc -o hello hello.c

等价的编译方法:

gcc -c hello.c
gcc -o hello.my -nostartfiles hello.o /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtn.o

我在redflag workstation 5.0版本下用3.4.3版本GCC编译器编译出来的大小都是3589字节,并且用diff命令比较为相同的文件。由此证明gcc在编译并链接 hello.c文件时先将hello.c编译成hello.o,然后将它与crt1.o、crti.o、crtn.o链接在一起。

如果要写一个没有main函数的程序,就需要自己实现crt1.o。程序入口为符号“_start”处。代码如下:

  1. /* nomain.c */
  2. void _start(void)
  3. {
  4. _exit(0);
  5. }
gcc -o nomain -nostartfiles hello.c

2.编译和使用库
除了直接编译代码外还会使用到函数库。库有静态库和动态库之分。静态库是以.a结尾的文件,例如:libXXX.a;动态库是以.so结尾的文件,例如: libXXX.so。XXX之后或者.so和.a之后会跟版本号,例如:libc-2.3.4.so,或者libuuid.so.1.2。
加入函数库的代码如下:

  1. /* test.h */
  2. int test1 (void);
  3. /* test.c */
  4. #include <stdio.h>
  5. #include "libtest.h"
  6. int test1 (void)
  7. {
  8. printf("test1 function is called.\n");
  9. return 0;
  10. }

当要编译成静态库的时候使用如下命令生成libtest.a:

gcc -c test.c
ar -r libtest.a test.o

当要编译成动态链接库的时候使用如下命令生成libtest.so

gcc -c -fpic test.c
gcc -shared test.o -o libtest.so

gcc -fpic -shared test.c -o libtest.so

当需要调用该库时使用如下代码。

  1. /* calllib.c */
  2. #include "test.h"
  3. int main (int argc, char * argv[])
  4. {
  5. test1();
  6. }

按如下方式编译:

gcc -o calllib.static calllib.c libtest.a

gcc -o calllib.dynamic calllib.c libtest.so

gcc -o calllib calllib.c -ltest

前提是libtest.a或libtest.so在当前编译的目录。
使用ldd显示calllib.static依赖的库只有libc和ld-linux,但calllib.dynamic就多了一个libtest.so。

3.库文件和头文件
在程序中,使用#include 类似的头文件stdio.h在编译器的头文件路径中,#include “abc.h”中的stdio.h文件则应该在当前目录。通过对编译器指定参数-I来指定头文件所在目录,可以用 #include <>来引用。例如:gcc -I./include hello.c,将从当前目录下的include目录下去寻找头文件。
同理,程序中调用的库函数在编译时也需要指定路径,同时指定库。使用-L参数指定库文件的目录,-l指定包含的库文件。例如,要使用libXXX.so库,参数为-lXXX。
一般一个库编译完成后有库文件和头文件。如果要使用这个库,可以将库文件目录和头文件目录分别用-I和-L参数指定,也可以将他们拷贝到编译器的include和lib目录下。

4.缩小程序体积
代码如下:

  1. /* nomain.c */
  2. void _start(void)
  3. {
  4. asm("movl , eax\n"
  5. "movl {fckeditor}, ebx\n"
  6. "int {fckeditor}x80"
  7. );
  8. }

使用如下方法能使可执行文件体积最小(手工方法除外)。

gcc -o nomain -s -O3 nomain.c
objcopy -R .comment -R .data

由此得到可执行文件的体积为352字节。

GCC能编译出2种格式的可执行体:a.out格式、elf格式。其中.o目标文件、.a静态库文件

Appendix.1 常用命令
ldd:显示可执行文件或者库文件依赖的库文件。
objdump:显示elf可执行文件的内部信息。
-h:显示
-t:显示符号信息
-T:显示动态符号信息。(例如引用动态链接库中的函数名称)
-r:显示重定位入口信息。
-R:显示动态重定位入口信息。(例如:动态链接库中的变量或者函数地址)
-s:显示所有section内容。
-S:反汇编代码段。
objcopy:copy elf文件内容
-R:删除某个section
-j:仅仅复制指定的section

<think>好的,我需要帮助用户了解如何使用GCC进行编译。首先,我需要确保回答符合用户的要求,包括结构清晰、步骤详细,并且引用提供的参考资料。同时,必须遵循系统级指令,比如正确使用LaTeX格式和生成相关问题。 首先,我应该整理GCC的基本使用步骤。用户提供的引用[1]提到GCC是一个广泛使用的编译器,支持多种语言。引用[2]详细介绍了编译过程,包括预处理、编译汇编和链接四个阶段。因此,我需要将这些步骤分解开来,用简单的中文解释每个阶段,并给出相应的gcc命令示例。例如,预处理使用-E选项,编译汇编使用-S,汇编成目标文件使用-c,最后链接生成可执行文件。 接下来,用户可能需要知道如何一步完成整个编译过程,即直接从源代码生成可执行文件。这时需要提到gcc的-o选项,例如gcc hello.c -o hello。同时,根据引用[3],在链接某些库时可能需要使用-l选项,比如-lglut -lGL -lGLU,这里需要解释这些选项的作用。 然后,常见的编译选项也是用户关心的内容。引用[1]提到了常见的编译选项,如-Wall显示警告,-g生成调试信息,-O优化级别。需要将这些选项分类说明,并给出示例命令,帮助用户理解如何应用这些选项。 此外,处理多文件编译也是实际开发中的常见需求,需要指导用户如何同时编译多个.c文件,或者先生成目标文件再链接。这部分需要给出具体的命令示例,如gcc main.c utils.c -o program,或者分步编译。 最后,生成相关问题。根据用户提供的示例,问题应围绕GCC的更多使用场景、调试方法、优化影响以及静态库和动态库的区别展开。这些问题需要自然相关,并且能够引导用户进一步学习。 整个过程中,需要确保所有技术术语解释清晰,命令示例正确,并且正确引用提供的参考资料。例如,在讲解预处理阶段时,引用[2]中的命令示例gcc -E test.c -o test.i需要被提及,并添加引用标识[^2]。同时,注意所有行内数学表达式如变量或文件名使用$...$格式,而独立公式如可能出现的命令示例使用代码块格式,但根据用户要求,独立公式应使用$$...$$,但在此问题中可能较少涉及数学公式,更多是代码示例,因此需注意代码块的正确使用。 最后检查回答是否符合所有系统级指令,特别是LaTeX的使用是否正确,生成的相关问题是否合适,引用是否正确标注。确保没有使用任何Markdown格式,所有代码示例用三个反引号包裹,并标明语言类型,如python或bash。同时,回答使用中文,结构清晰,分步骤解释,帮助用户逐步理解和应用GCC编译器。</think>### 如何用 GCC 进行编译:使用方法和教程 GCC(GNU Compiler Collection)是广泛使用的编译器套件,支持 C、C++ 等多种编程语言。以下是 GCC 的基本使用方法指南: --- #### 1. **单文件编译** 最简单的编译方式是将源代码直接编译为可执行文件: ```bash gcc hello.c -o hello ``` - `hello.c`:源文件 - `-o hello`:指定输出文件名为 `hello`(默认生成 `a.out`)[^1]。 --- #### 2. **分阶段编译** GCC编译过程分为四个阶段,可逐步执行: - **预处理**:展开宏和头文件 ```bash gcc -E hello.c -o hello.i # 生成预处理文件 hello.i ``` - **编译汇编代码** ```bash gcc -S hello.i -o hello.s # 生成汇编文件 hello.s ``` - **汇编为目标文件** ```bash gcc -c hello.s -o hello.o # 生成二进制目标文件 hello.o ``` - **链接为可执行文件** ```bash gcc hello.o -o hello # 链接目标文件生成可执行文件 ``` --- #### 3. **常见编译选项** - **显示所有警告**:`-Wall` ```bash gcc -Wall hello.c -o hello ``` - **生成调试信息**:`-g`(用于 GDB 调试) ```bash gcc -g hello.c -o hello ``` - **优化级别**:`-O1`、`-O2`、`-O3` ```bash gcc -O2 hello.c -o hello # 启用中级优化 ``` - **链接外部库**:`-l`(例如 OpenGL 库) ```bash gcc program.c -lglut -lGL -lGLU -o program[^3] ``` --- #### 4. **多文件编译** - **直接编译多个文件**: ```bash gcc main.c utils.c -o program ``` - **分步编译**: ```bash gcc -c main.c # 生成 main.o gcc -c utils.c # 生成 utils.o gcc main.o utils.o -o program ``` --- #### 5. **静态库与动态库** - **生成静态库**: ```bash ar rcs libutils.a utils.o # 打包目标文件为静态库 gcc main.c -L. -lutils -o program ``` - **生成动态库**: ```bash gcc -shared -fPIC utils.c -o libutils.so gcc main.c -L. -lutils -o program ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值