一.编译工具

前言

1)编译器和目标程序运行在相同架构的编译过程,被称为本地编译
2)编译器和目标程序运行在不同架构的编译过程,被称为交叉编译
为什么需要交叉编译?因为编译过程往往需要很大的算力和空间,arm平台上往往不满足这个要求,因此需要在x86上编译,然后下载到arm上运行。

1.GCC简介

   Linux下编译C代码使用的是gcc,GCC(GNU Compiler Collection)是由 GNU这个组织 开发的编程语言编译器,最开始叫GNU C Compiler,只支持编译C语言,后面渐渐开始支持编译C++,Java等语言,因此改叫GNU Compiler Collection,缩写还是GCC。C语言的GCC由下面三部分组成:
1)gcc-core:gcc编译器,可以将源码编译成可执行程序
2)Binutils:除gcc-core之外的小工具的合集,里面包含了链接器ld,汇编器as等。
3)glibc:C语言的标准库,包含了printf等函数。
执行如下命令,可以查看当前gcc编译的目标程序是在x86上运行还是在arm上运行:

gcc -v

会输出gcc的版本信息,里面有target这一项,根据该项的值来判断:

1)target:x86_64-linux-gnu,表示编译生成的程序只能在x86架构上运行。
2)target:arm-linux-gnueabihf,表示编译生成的程序只能在arm架构上运行。

2.GCC编译过程

使用gcc编译代码基本语法如下:
gcc [选项] 输入的文件名

常用选项如下:
-o:小写字母“o”,指定生成的可执行文件的名字,不指定的话生成的可执行文件名为 a.out
-E:只进行预处理,既不编译,也不汇编,只是将include的文件和宏定义展开
-S:只编译,不汇编
-c:编译并汇编,但不进行链接
-g:生成的可执行文件带调试信息,方便使用 gdb 进行调试
-Ox:大写字母“O”加数字,设置程序的优化等级,如“-O0”“-O1”“-O2”“-O3”,数字
越大代码的优化等级越高,编译出来的程序一般会越小,但有可能会导致程序不正常运行

要理解上述选项,首先要知道gcc编译代码的几个阶段:预处理,编译,汇编,链接,如下:

下面通过举例说明上述过程,假设有hello.c源文件:

#include <stdio.h>int main()
{printf("hello, world! This is a C program.\n");for(int i = 0; i < 10; i++){printf("output i = %d\n", i);}return 0;
}

那么执行如下命令,可以一步到位,直接从源码生成可执行文件并执行:

gcc hello.c -o hello
./hello

其实,gcc hello.c -o hello这条命令包含了如下过程:

# 1.预处理,可理解为把头文件和宏的代码展开汇总成 C 代码,把 *.c 转换得到 *.i 文件
gcc –E hello.c –o hello.i
# 2.编译,可理解为把 C 代码转换为汇编代码,把 *.i 转换得到 *.s 文件
gcc –S hello.i –o hello.s
# 3.汇编,可理解为把汇编代码转换为机器码,把 *.s 转换得到 *.o,即目标文件
gcc –c hello.s –o hello.o
# 4.链接,把不同文件之间的调用关系链接起来,把一个或多个 *.o 转换成最终的可执行文件
gcc hello.o –o hello

1)上述四个过程是可以分别执行的,也可以按照顺序组合在一起,如:

gcc -S hello.c -o hello.s    #相当与1和2两条命令的结合,同理
gcc –c hello.c –o hello.o   #相当于1,2,3这三条命令的结合

2)上述过程生成的文件是可以打开的,比如执行了gcc –E hello.c –o hello.i,可以直接用vim打开hello.i,就能看到相关头文件代码都被包含进来,宏也被替换展开了。
3) 如果执行了gcc –S hello.i –o hello.s之后,打开hello.s之后,便能看到生成的汇编代码。
4) 但是需要注意的是,执行gcc –c hello.s –o hello.o之后,如果用vim打开hello.o会发现是乱码, 因为.o文件是机器码,是为了让机器阅读的。.o文件可以用readelf工具打开:

readelf -a hello.o

命令执行结果如下:

从上图可以看到,目标文件里面包含了 ELF 头、程序头、节等内容。对于*.o目标文件和*.so库文件,链接器根据这些内容信息来链接生成可执行程序,对于可执行文件,系统在运行时会根据这些信息来加载程序运行。

注:linux下生成的.o目标文件、.so动态库文件、可执行文件等都是elf格式的,可以通过readelf工具来查看内容。

3.链接过程

链接分为两种:静态链接和动态链接。
动态链接: GCC 编译时的默认选项。动态是指在应用程序运行时才去加载外部的代码库,比如c语言的标准库,如果是动态链接生成的程序,那么都是在运行的时候才去加载。
静态链接: 链接时使用选项“–static”,它在编译阶段就会把所有用到的库打包到自己的可执行程序中。
静态链接的优点是兼容性好,程序基本不依赖于外部环境,但是生成的程序也比较大。
动态链接生成的程序兼容性差点,但是生成的程序比较小。

gcc hello.c -o hello   #动态链接生成
gcc hello.c -o hello_static --static   #静态链接生成

通过对比,发现动态链接生成的hello比静态链接生成的hello_static小很多。

4.交叉编译器简介

编译器和目标程序运行在不同的架构上,这种编译器叫交叉编译器,x86平台上gcc交叉编译器主要有:
1)arm-linux-gnueabihf-gcc:这个编译器名称中的Linux表明该编译器生成的目标程序运行在Linux系统上,程序可以使用Linux下的c标准库和Linux内核API。
2)arm-none-eabi-gcc:名称中的none表示该编译器编译生成的目标程序运行环境不需要操作系统,可以用于编译逻辑代码,uboot,内核代码等。

注意,arm-linux-gnueabihf-gcc也是可以编译uboot和内核代码的。但是推荐用arm-none-eabi-gcc。
上述两个编译器都是由Linaro组织提供的。Linaro 是由 ARM 发起,与其它 ARM SOC 公司共同投资的非盈利组织。大部分开发者都是使用Linaro组织提供的交叉编译器。

Linaro组织的编译器命名规则如下:
arch [-os] [-(gnu)eabi(hf)] -gcc

其中,hf表示编译器的浮点模式是硬浮点hard-float(采用 fpu 参与浮点运算),如果没有hf则表明是软浮点soft-float(即使有 fpu 浮点运算单元也不用,而是使用软件模式)。
**注意,**如果目标平台的c库文件(比如glibc 的库文件 libc.so.6)都是硬浮点类型,那么使用不带hf的编译器编译出来的目标程序很可能无法在Linux平台上运行。使用如下命令可以查看库的类型:

readelf -h libc.so.6

假设在平台A上输出如下:

可以看到,平台A库类型是hard-float,如果使用如下命令编译:

sudo arm-linux-gnueabi-gcc  hello.c -o hello

那么编译生成的hello无法在上述在平台A上运行,因为平台A的c库文件是hard-float,而hello是soft-float类型编译器编译出来的。
要想在平台A上运行,有两种方法,方法一是使用hard-float类型的编译器,

sudo arm-linux-gnueabihf-gcc hello.c -o hello_hf

方法二是使用静态编译:

sudo arm-linux-gnueabi-gcc hello.c -o hello_static  --static

则编译生成的hello_hf和hello_static均可以在平台A上运行。

2.Linux下程序代码的编译相关推荐

  1. Linux下通过源码编译安装程序

    本文简单的记录了下,在Linux下如何通过源码安装程序,以及相关的知识. 一.程序的组成部分 Linux下程序大都是由以下几部分组成: 二进制文件:也就是可以运行的程序文件 库文件:就是通常我们见到的 ...

  2. Linux下程序编译通过运行时提示error while loading shared libraries(动态链接库问题)

    问题: Linux下程序编译通过了,但是运行时提示 :error while loading shared libraries: libXXX.so.X: cannot open shared obj ...

  3. Linux下程序的保护机制(checksec)

    Linux下程序的保护机制 前言 相信很多人,查看程序信息时会用到,checksec这个命令.它会给你返回如下图的结果,但是很多最开始看到的人,很多都看不懂,如果身为小白的我,跟在大佬后面比葫芦画瓢, ...

  4. Linux下程序的Profiling工具-性能测试工具GNU gprof

    Linux下程序的Profiling工具 http://blog.chinaunix.net/uid-128922-id-289972.html 我们在写程序,特别是嵌入式程序的时候,通常需要对程序的 ...

  5. Linux下boost库的编译、安装详解

    1.下载源文件 去官网下载:http://www.boost.org/ 这里下载最新版本 wget https://dl.bintray.com/boostorg/release/1.64.0/sou ...

  6. Linux下程序崩溃dump时的 core文件的使用方法

    Linux下程序崩溃dump时的 core文件的使用方法 1.在启动程序前执行 ulimit -c unlimited unlimited 表示生成文件的大小限制,也可以修改为自定义的大小,例如: u ...

  7. linux 中的代码如何编译错误提示,Ubuntu 下GCC编译代码错误提示没有system.h和conio.h,如何得到这两个文件...

    mudaizi12345 于 2015-01-23 23:42:50发表: very good mudaizi12345 于 2015-01-23 20:36:00发表: 路过试一试 菜菜123 于 ...

  8. linux下c代码调用.so,Linux下C程序调用.so(动态链)的一个例子

    /********************************************** * 使用Linux下C++的动态链接库.So文件 * void *pdlHandle; * pdlHan ...

  9. linux下c使用lzma_linux 编译lzma

    Linux下大部分系统默认自带python2.x的版本,最常见的是python2.6或python2.7版本,默认的python被系统很多程序所依赖,比如centos下的yum就是python2写的, ...

最新文章

  1. Spring Boot + thymeleaf 实现文件上传下载
  2. Incorrect string value: '\xF0\x90\x8D\x83...' for column 通用解决方案
  3. 利用matlab对xml文件进行批量处理
  4. java 数据库字段_JAVA如何获得数据库的字段及字段类型
  5. boost::container模块实现比较的程序
  6. 提问的智慧 如何得到好的帮助(转)
  7. PCB设计中焊盘的种类,你都见过几种?
  8. 浪擎全融合灾备云获大数据安全领域最佳创新奖
  9. Typora+PicGo+SMMS、github、gitee实现Typora图片上传到图床
  10. Baksmali用法
  11. PS2022丨Photoshop 2022软件下载+Ps安装教程
  12. Ubuntu18.04安装TPlink WDN5200 usb无线网卡驱动
  13. ICA算法的数学原理
  14. DELL存储SCv3020组件概念
  15. 用java开发一个简单的安卓程序,Android NDK开发简单程序分享(Hello Word!)
  16. Java程序员常用的各种快捷键和命令
  17. 辉芒微IO单片机FT60F123-RB
  18. 存token的最佳方式
  19. LZO--实时数据压缩库
  20. vue中 div高度随另一个div的高度变化

热门文章

  1. ultraiso安装matlab,ubuntu U盘安装教程:UltraISO采用U盘安装ubuntu12.10
  2. Springboot毕设项目爱团购系统设计与实现kh533(java+VUE+Mybatis+Maven+Mysql)
  3. 5G NR LDPC码(1)—— LDPC码设计原理
  4. .com .org等域名/网址的理解
  5. python pyz_Python pyzgoubi包_程序模块 - PyPI - Python中文网
  6. IT管理类培训,你想了解的全都在这里
  7. 原神PC端缺少 PCgamesSDK.dll 解决方案
  8. 什么是Mysql的next-key、插入缓冲、二次写、自适应哈希索引和预读
  9. python 小程序
  10. 当前计算机什么专业好就业找工作,计算机哪个专业最好就业