在windows上编译程序时,会使用到如vscode、Visual studio、keil MDK等IDE,这些IDE很方便,直接把各种编译器进行了整合,用户不用再考虑编译工具的问题。在Linux上开发时,没有这么丰富的IED可用,并且自己调用编译器更灵活,于是需要自己使用编译工具对代码进行编译。
在PC机(即X86架构)上的编译工具链为gcc、ld、objcopy、objdump等,使用它们编译出来的程序只能在X86架构上运行,若想要程序在ARM架构上运行,则需要使用交叉编译工具链xxx-gcc、xxx-ld等(如arm-gcc-linux)。
GCC是一个开源的编译器套件,包含多种编译器且支持多种语言,实际上GCC也是通过调用cc1、as、collect2等工具来实现编译的。cc1是用来将源码转换为汇编代码的工具;as是用来将汇编码翻译成机器码的工具;collect2是链接器,用来把相关目标文件和依赖库连接起来,生成可执行文件或库文件的工具。
GCC官方手册:GCC online documentation- GNU Project
GCC中文手册: GCC 13.1 简体中文
GCC编译过程
在日常交流中通常使用“编译”统称这 4 个步骤,如果不是特指这 4 个步骤中的某一个,则默认认为统称。
预处理:.c->.i 将代码包含的各种头文件包含进来,把宏定义展开,根据情况把#if #endif代码段里面的代码保留或删去。
编译: .i->.s 将高级语言转为汇编码,并且检查语法错误。
汇编: .s->.o 将汇编码转换为机器码。
链接: .o->.exe 将所有相关的.o文件链接起来,生成一个.exe可执行文件。
反汇编:.o->.s 将机器码转为汇编码,调试时会用到。
gcc使用示例(在命令后面加上 -v 可显示详细的编译步骤)
gcc hello.c // 输出一个名为 a.out 的可执行程序,然后可以执行./a.out
gcc -o hello hello.c // 输出名为 hello 的可执行程序,然后可以执行./hello
gcc -o hello hello.c -static // 静态链接
gcc -c -o hello.o hello.c // 先编译(不链接)
gcc -o hello hello.o // 再链接
//单步执行
gcc -E -o hello.i hello.c //预处理
gcc -S -o hello.s hello.i //生成汇编代码
gcc -c -o hello.o hello.s //生成机器码
gcc -o hello hello.o //链接并生成可执行文件
gcc常用编译选项
-E 预处理,开发过程中想快速确定某个宏可以使用“ -E -dM”
-c 把预处理、编译、汇编都做了,但是不链接
-o file 指定输出文件为file,如果不进行指定,则默认输出结果为a.out
-I 指定头文件目录
-L 指定链接时库文件目录
-l 指定链接哪一个库文件
-S 编译后即停止,不进行汇编。
-E 预处理后即停止,不进行编译。预处理后的代码往标准输出。
-V 显示制作 GCC 工具自身时的配置命令;同时显示编译器驱动程序、预处理器、编译器的版本号。
如何编译多个文件
1.一起编译、链接
gcc -o test main.c sub.c
2.分开编译,统一链接
gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
gcc -o test main.o sub.o
制作、使用动态库
1.制作、编译
gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
gcc -shared -o libsub.so sub.o sub2.o sub3.o(可以使用多个.o 生成动态库)
gcc -o test main.o -lsub -L /libsub.so/所在目录/
2.运行
把 libsub.so 放到 Ubuntu 的/lib 目录,然后就可以运行 test 程序。如果不想把 libsub.so 放到/lib,也可以放在某个目录比如/a,然后如下执行:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/a
./test
制作、使用静态库
gcc -c -o main.o main.c
gcc -c -o sub.o sub.c
ar crs libsub.a sub.o sub2.o sub3.o(可以使用多个.o 生成静态库)
gcc -o test main.o libsub.a (如果.a 不在当前目录下,需要指定它的绝对或相对路径)
运行:不需要把静态库 libsub.a 放到板子上。
注意: 执行 arm-buildroot-linux-gnueabihf-gcc -c -o sub.o sub.c 交叉编译需要在
最后面加上-fPIC 参数。
很有用的选项
gcc -E main.c // 查看预处理结果,比如头文件是哪个
gcc -E -dM main.c > 1.txt // 把所有的宏展开,存在 1.txt 里
gcc -Wp,-MD,abc.dep -c -o main.o main.c // 生成依赖文件 abc.dep,后面 Makefile 会用
echo 'main(){}'| gcc -E -v - // 它会列出头文件目录、库目录(LIBRARY_PATH)
警告选项(Warning Option)-Wall
gcc -Wall -c main.c
此选项打开所有需要注意的警告通知,建议加上
调试选项(Debugging Option)-g
以操作系统的本地格式(stabs, COFF, XCOFF,或 DWARF)产生调试信息,GDB 能够使用这些调试信息。在大多数使用 stabs 格式的系统上, `-g'选项加入只有 GDB 才使用的额外调试信息。可以使用下面的选项来生成额外的信息: `-gstabs+', `-gstabs', `-gxcoff+', `-gxcoff', `-gdwarf+'或`-gdwarf',具体用法请读者参考 GCC 手册。