GCC编译器的使用
源文件需要经过编译才能生成可执行文件。在Windows下进行开发时,只需要点几个按钮即可编译,集成开发环境(比如Visual studio)已经将各种编译工具的使用封装好了。Linux下也有很多优秀的集成开发工具,但是更多的时候是直接使用编译工具;即使使用集成开发工具,也需要掌握一些编译选项。
PC机上的编译工具链为 gcc、ld、objcopy、objdump 等,它们编译出来的程序在x86平台上运行。要编译出能在ARM平台上运行的程序,必须使用交叉编译工具 xxx-gcc、xxx-ld 等(不同版本的编译器前缀不一样,比如 arm-linux-gcc),下面分别介绍。
GCC编译过程
一个C/C++文件要经过预处理(preprocessing)、编译(compilation)、汇编(assembly)和链接(linking)等4步才能变成可执行文件。
例如,现在我们创建一个hello.c文件:
$ sudo vi hello.c
然后随意编写一个打印helloworld的程序,确保能编译通过并用来进行测试:
#include<stdio.h>
int main(int argc, char *argv[])
{
printf("helloworld");
return 0;
}
通过不同的 gcc 选项可以控制这些过程:
在日常交流中通常使用“编译”统称这4个步骤
gcc使用示例:
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 -o hello hello.c -v”时,可以查看到这些步骤:
cc1 main.c -o /tmp/ccXCx1YG.s
as -o /tmp/ccZfdaDo.o /tmp/ccXCx1YG.s
cc1 sub.c -o /tmp/ccXCx1YG.s
as -o /tmp/ccZfdaDo.o /tmp/ccXCx1YG.s
collect2 -o test /tmp/ccZfdaDo.o /tmp/ccn8Cjq6.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
完成编译后,使用 ./hello
命令就能执行程序。
GCC常用选项
常用编译选项
在学习时,我们暂时只需要了解下表中的选项:
常用选项 | 描述 |
---|---|
-E | 预处理,开发过程中想快速确定某个宏可以使用“-E -dM” |
-c | 把预处理、编译、汇编都做了,但是不链接 |
-o | 指定输出文件 |
-I | 指定头文件目录 |
-L | 指定链接时库文件目录 |
-l | 指定链接哪一个库文件 |
怎么编译多个文件
①一起编译、链接:
gcc -o test main.c sub.c
每次修改都需要重新编译全部文件,当编译多个文件时,比较浪费编译的时间。
②分开编译,统一链接
gcc -c -o main.o main.c
gcc -c -o sub.c sub.c
gcc -o test main.o sub.o
当编译多个文件时,分开编译统一链接就显得比较高效。
制作、使用静态库
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-linux-gnueabihf-gcc -c -o sub.o sub.c
交叉编译需要在最后加上 -fPIC
参数。
制作、使用动态库
制作、编译:
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/所在目录/
运行:
①先把libsub.so放到PC或板子上的/lib目录,然后就可以运行test程序。
② 如果不想把libsub.so放到/lib,也可以放在某个目录比如/a,然后如下执行:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/a
./test
很有用的选项
gcc -E main.c //查看预处理结果,比如头文件是哪个
gcc -E -dM main.c >1.txt //把所有的宏展开,存在1.txt里
gcc -Wp,-MD,adc.dep -c -o main.o main.c //生成依赖文件abc.dep,后面Makefile会用
echo 'main(){}'| gcc -E -v - //它会列出头文件目录、库目录(LIBRARY_PATH)