嵌入式软件学习问题汇总(三)关于编译

简单聊聊

在上一篇,我们介绍到了ARM有关的一些预备知识,包含了ARM的发展史(关键里程碑,发展过程中的趣事,并谈了谈我的个人看法),以及ARM内核架构的版本号、特性。本篇文章,就继续依照我之前罗列的嵌入式学习大纲的顺序,来为各朋友们介绍一下有关编译的那些你需要了解的地方,其中包括软件开发模式的介绍、什么是编译、为什么需要编译、什么是交叉编译、为什么需要交叉编译、有关linux环境下的编译原理、编译过程的概述。总而言之,这必然是一片有关ARM编译的特别详细的解析文章,好了,废话不多说,走起:

什么是编译

  首先,带给大家两个概念:编译、编译程序,什么是编译程序呢?编译程序(Compiler)就是一种程序。它的作用是把用高级语言写的源程序作为输入,经过一系列的翻译转换,产生机器可以读懂的机器码作为输出。
  那么为什么需要编译,这是由于基于高级语言的源程序编码的出现是为了让人容易理解和阅读的,如此高端的人类语言直接传送给CPU是执行不了的,这是因为基于逻辑电路的CPU只对0、1数字敏感(数字电路中每一个元件的电平状态只有两种:高电平、低电平),因此由于计算机只能识别二进制的数据,所以基于高级语言的源代码必须要编译成二进制的字节码文件后,计算机才能够识别并运行。
  好了基于以上原因,大家应该了解了编译的必要性了,下面介绍一下什么是编译:编译(compilation , compile)就是把高级语言变成计算机可以识别的2进制语言的过程。那么编译程序把一个源程序翻译成目标程序的工作过程都做了哪些工作呢?简单分享一下,编译的过程分为五个阶段:词法分析;语法分析;语义检查和中间代码生成;代码优化;目标代码生成。主要是进行词法分析和语法分析,又称为源程序分析,分析过程中发现有语法错误,会返回提示信息。

软件的开发模式

  说完编译,我们就要谈谈编译的几种方式,并重点与大家聊聊关于嵌入式开发的编译方式。那么在这之前先要了解软件的两种开发模式:
  对于非嵌入式开发,我们用到的开发模式是A对A的开发模式,这是什么意思呢:即A类机编写源代码程序,由编译到的可执行程序,发布到A类机运行(就例如腾讯QQ,腾讯的开发人员用自己的电脑进行开发,开发好的程序经过编译生成可执行程序,发布到腾讯的官网,我们使用时直接从官网下载安装可执行程序,在我们自己的电脑上运行,软件开发者与软件使用者用到的是同一个类型(A类)的计算机,称为A对A的开发)。
  对于嵌入式开发来说,我们所需要用到的是A对B的开发模式,即A类机编写源代码,编译得到可执行程序,发布到B类机执行。(举个栗子:像我们做单片机开发的朋友,通过MDK:Windows环境下的开发工具编写源代码,经过MDK本身的编译软件编译后,通过ISP下载烧录到单片机上运行,开发者用的是A类机,执行程序在单片机B类机上执行,即A对B的开发模式)这种编译模式就是我们将在嵌入式开发中用到的交叉编译。

Linux下的编译过程概述

  由于我们做嵌入式开发是基于LInux开发环境的,因此这里简单聊一下基于Linux编译过程是什么样的:
  根据编译的定义,编译就是基于高级语言的源文件进行一系列处理,最终得到二进制代码的可执行文件。整个编译过程在Linux系统下分成了4个抽象阶段。我们举一个例子来说明,如何把一个简单的C源文件编译成名为二进制文件:这里有一段非常简单的代码hello.c

#include <stdio.h>
int main()
{
    printf("Hello CSDN\n");
    return 0;
}

第一步:预处理阶段 (从.c到.i文件)
  此阶段主要完成#符号后面的各项内容到源文件的替换,例如头文件#include和宏定义#define, #ifdef等。这是因为#include、#define这些符号在编译阶段是不能处理的,因此需要这一步预处理阶段现将这些符号处理成编译阶段能处理的代码
可以用gcc的参数-E来指示编译器只做预处理而不进行下面的3个步骤。例如:

gcc –E hello.c -o hello.i 

第二步:编译阶段 (从.i 到.s文件)
  这个阶段编译器主要做词法分析、语法分析、语义分析等,在检查无错误后后,把代码翻译成汇编语言。 编译器将文本文件hello.i 翻译成文本文件hello.s, 它包含一个汇编语言程序,即一条低级机器语言指令。
可用gcc的参数-S来指示编译器只编译到汇编语言而不进行汇编和链接。 例如,

gcc -S hello.i -o hello.s

第三步: 汇编阶段 (从.s 到.o文件)
  汇编器as 将hello.s 翻译成机器语言,打包形成可重定位(关于重定位是个比较大的话题,以后再说)的目标文件hello.o 中(二进制文本形式)。

gcc -c hello.s -o hello.o

第四步:链接阶段 (从.o到binary可执行文件)
  此阶段完成文件中调用的各种函数跟静态库和动态库的链接(链接这里也是大有可为聊的,以后单独做篇文章来聊,这里先简单理解一下),并将它们一起打包合并形成目标文件,即可执行文件。

gcc hello.o -o hello

  以上四个阶段就是其中,第1阶段和第2阶段由编译器完成,第3阶段由汇编器完成,第4阶段由链接器完成。在linux中我们可以用一条命令一次执行:

gcc hello.c -o hello

编译器、汇编器

  上面有提到编译器与汇编器,为了方便大家理解下面再举个例子解释一下:对于同一个语句的三种表示形式:高级语言、低级语言、机器语言的表示
C语言 :

a=b+1;

汇编语言 :

mov -0xc(%ebp),%eax
add $0x1,%eax
mov %eax,-0x8(%ebp)

机器语言:
8b 45 f4
83 c0 01
89 45 f8
  从高级、机器不可理解,转换为机器可理解的机器语言。由C转换为汇编语言这一过程是由编译器(Assembler)来执行的。由汇编语言转换为机器语言都是由汇编器来完成的。

Linux下的编译工具概述

  说到Linux下的编译工具,不得不提一下原版的cc编译工具,cc是unix的系统下的C编译器,商业软件(这又提到unix与linux的关系,这里不多做介绍了,感兴趣的朋友去百度了解一下)。
  Linux系统中的cc通常是符号链接,指向gcc。可以通过$ls –l /usr/bin/cc来简单察看,该变量是make程序(这里有关于后面Makefile的编写,以后会再写文章详细来聊)的内建变量,默认指向gcc。cc符号链接和变量存在的意义在于源码的移植性,可以方便的用gcc来编译老的用cc编译的Unix软件,甚至连makefile都不用再改,而且也便于Linux程序在Unix下编译。
  上古时期的gcc全称应该是GNU C Compiler,只能编译C。后来gcc扩展成了编译器套装(包含C、C++、Objective-C、Ada、Fortran、Java编译器),全称则是GNU Compiler Collection。g++: C++编译器。CC: makefile里面的宏定义,makefile里面的一个名字(后期再说)。
  一些注意事项:(暂时不重要,简单了解即可)
  1. 后缀名为.c的源文件,gcc把它当做C程序,而g++把它当做C++程序。 后缀名为.cpp的源文件,两者都把它当做C++程序。
  2. 编译阶段,g++会调用gcc。对于C++代码,两者是等价的。
  3. gcc不能自动和C++程序使用的库链接,所以要用g++来完成链接。为了统一,常常用g++直接做编译和链接,所以会让人误以为只能用g++来编译C++代码。实际上gcc也可以编译C++代码。

何为交叉编译

  好了,重点来了,说到什么是交叉编译之前,先向大家简单介绍一下为什么需要交叉编译:有时是因为目的平台上不允许或不能够安装我们所需要的编译器,而我们又需要这个编译器的某些特征;有时是因为目的平台上的资源贫乏,无法运行我们所需要编译器;有时又是因为目的平台还没有建立,连操作系统都没有,根本谈不上运行什么编译器。(这里有些抽象,举个例子简单说一下,比如单片机,我们上面有提到过两种开发方式,如果单片机用第一种方式编译开发,及A对A,在单片机上进行源程序编写和编译,并在自身执行,我一说你肯定就想到了,这是不可能的,暂且不说单片机上能不能运行编译程序,单就能不能在单片机上编程你就应该了解到了,这种开发方式是不恰当的,我们还是需要第二种开发方式:电脑编程编译烧录到单片机上运行,这才是正解)
  既然理解了为什么需要交叉编译了,下面说说什么是交叉编译, 在一种计算机环境中运行的编译程序,能编译出在另外一种环境下运行的代码,我们就称这种编译器支持交叉编译。这个编译过程就叫交叉编译。简单地说,就是在一个平台上生成另一个平台上的可执行代码。这里需要注意的是所谓平台,实际上包含两个概念:体系结构、操作系统。同一个体系结构可以运行不同的操作系统;同样,同一个操作系统也可以在不同的体系结构上运行。举例来说,我们常说的x86 Linux平台实际上是Intel x86体系结构和Linux for x86操作系统的统称;而x86 WinNT平台实际上是Intel x86体系结构和Windows NT for x86操作系统的简称。
  交叉编译这个概念的出现和流行是和嵌入式系统的广泛发展同步的。我们常用的计算机软件,都需要通过编译的方式,把使用高级计算机语言编写的代码(比如C代码)编译(compile)成计算机可以识别和执行的二进制代码。比如,我们在Windows平台上,可使用Visual C++开发环境,编写程序并编译成可执行程序。这种方式下,我们使用PC平台上的Windows工具开发针对Windows本身的可执行程序,这种编译过程称为native compilation,中文可理解为本机编译(即A对A开发)。然而,在进行嵌入式系统的开发时,运行程序的目标平台通常具有有限的存储空间和运算能力,比如常见的ARM 平台,其一般的静态存储空间大概是16到32MB,而CPU的主频大概在100MHz到500MHz之间。这种情况下,在ARM平台上进行本机编译就不太可能了,这是因为一般的编译工具链(compilation tool chain)需要很大的存储空间,并需要很强的CPU运算能力。为了解决这个问题,交叉编译工具就应运而生了。通过交叉编译工具,我们就可以在CPU能力很强、存储控件足够的主机平台上(比如PC上)编译出针对其他平台的可执行程序。
  要进行交叉编译,我们需要在主机平台上安装对应的交叉编译工具链(crosscompilation tool chain),然后用这个交叉编译工具链编译我们的源代码,最终生成可在目标平台上运行的代码。常见的交叉编译例子如下:
  1、在Windows PC上,利用ADS(ARM 开发环境),使用armcc编译器,则可编译出针对ARM CPU的可执行代码。
  2、在Linux PC上,利用arm-linux-gcc编译器,可编译出针对Linux ARM平台的可执行代码。(这是我们常用的嵌入式开发方式)
  3、在Windows PC上,利用cygwin环境,运行arm-elf-gcc编译器,可编译出针对ARM CPU的可执行代码。
  以上编译好的代码通过一定方式烧录到arm上运行,即交叉编译开发。

结束语:

  如果你看完觉的有一点点的收获,麻烦朋友可以点个赞,已让更过的朋友可以看到。有问题可以在评论区评论,我懂的地方会单独做些文章来解释,或者直接在评论区恢复,希望各路朋友多多支持,身为一个刚刚接触嵌入式软件学习不久的小白,希望能通过这个平台寻找更多志同道合的朋友前辈。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
嵌入式软件学习的原理图可以根据引用的内容进行总结。嵌入式软件工程师的学习路线主要包括以下几个阶段和步骤: 1. 学习嵌入式知识:首先,学习者需要系统地学习嵌入式知识,包括硬件和软件方面的内容,掌握嵌入式系统的工作原理和基本概念。 2. 掌握嵌入式基础:在学习嵌入式知识后,学习者可以算是入门了。这时候可以进一步深入研究嵌入式系统的各个方面,包括硬件和软件的设计和开发。 3. 设计嵌入式软件嵌入式软件工程师的主要职责是根据产品的功能需求设计好软件,让硬件工作起来。嵌入式电子产品的硬件部分大部分都是相同的,核心部分由CPU、RAM和FLASH等组成,而软件则承担了实现产品具体功能的重任。 通过以上个阶段的学习和实践,学习者可以掌握嵌入式软件的基本原理和技能,为应聘嵌入式研发工程师岗位做好准备。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [嵌入式软件工程师学习路线图](https://blog.csdn.net/m0_70888041/article/details/127242771)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值