STM32F gcc编译全纪录

时间:2021-02-20 17:05:34

STM32Fgcc编译全纪录

使用Keil uVision编译的时候,有编译限制(32K,盗版的例外),正版的Keil,你懂的。为此想到了网上开源的编译器,大名鼎鼎的gcc编译器,大家都听过,但是对于嵌入式ARM的编译器,也在产生了很多变种(arm-none-eabi-gcc、arm-none-linux-eabi、arm-none-uclinuxeabi等),这都是开源世界的百花齐放的结果,以下区别要点仅供参考:

1)arm-none-eabi-: 这个是没有操作系统的,自然不可能支持那些跟操作系统关系密切的函数,比如fork(2),它使用的是newlib这个专用于嵌入式系统的C库

2)arm-none-linux-eabi: 针对于Linux的,使用Glibc。

3)arm-none-uclinuxeabi: 针对于uCLinux的,使用Glibc。

4)arm-none-symbianelf: 针对于symbian系统。

 

一、下载安装包并安装。

因为针对于无操作系统的应用,自然而然的选择了arm-none-eabi-gcc版本。

安装包: gcc-arm-none-eabi-4_7-2013q1-20130313-win32.exe

源码包:gcc-arm-none-eabi-4_7-2012q4-20121208-src.tar.bz2(喜欢研究源代码的可以下载)

安装过程一路next即可。

 

二、安装MinGW

下载并安装 mingw-get-inst-20120426

安装的时候将C编译器和Minsys选上,需要联网才可以安装。

三、熟悉Makefile

强力推荐熟悉网络牛人李云的51cto博客,有一篇驾驭Makefile的文章,另外一份参考资料也尤为重要《GNUmake中文手册-v3.80.pdf》,这都是先辈们开凿好的前路,对于后辈的我们只要沿路走就可以了。

熟悉Makefile主要还是实践,按照李云博客介绍的方法,多使用echo,或者使用make的调试命令make –D > 1.txt,这样可以熟悉其中的依赖关系和建立顺序。说的直白点就是建立对应依赖关系。

在熟悉的时候,可以一边对照实际工程编写对应的Makefile。

以下是简要学习Makefile的笔记:

1. %.a: 匹配所有以.a结尾的所有文件名

   |--> 类似于通常意义的*.

2. $(addprefixsrc/,foo bar) -->

   返回值为"src/foosrc/bar"。

3. vpath %.h../headers

   Makefile中出现的.h文件:如果不能再当前目录中找到,则到目录"../headers"下寻找.

vpath与VPATH的区别在于后者指定全局的搜索路径

4. $(MAKE) -C$(STD_PERIPH_LIB)

   make的递归执行-->4.6GNUmake中文手册-v3.8

   当前目录下存在外设库文件,在编译的时候先对子目录进行编译.

   它等价于命令

   lib:

         cd $(STD_PERIPH_LIB) && $(MAKE)

5. $@:代表规则中的目标文件名:可以使用@-->at 代表目标的意思

   $%:规则的目标文件是一个静态库文件时,代表静态库的一个成员名.

   $<:规则的第一个依赖文件名.

   $^:规则的所有依赖文件列表.

   $(*D): 代表"茎"中的目录部分

   $(*F): 代表"茎"中的文件名部分

6. find ./ -name'*~' | xargs rm -f

   当你尝试用rm 删除太多的文件,你可能得到一个错误信息:

   /bin/rm Argument list too long. 用xargs 去避免这个问题

7. 将make调试信息保存到txt文档

   make -d > 1.txt

8. main.c 中#include"defs.h"

   命令 gcc -M main.c

   out: main.o:main.c defs.h

   若不需要依赖关系中不考虑标准头文件时

   使用gcc -MM main.c

9.  := 与 += 区别

   := --> 立即展开

   += --> 立即展开或延迟展开

   对于所有条件语句均采用立即展开

10. 将make输出的错误信息输出到文件1.txt

   make 2>1.txt

11. 从Shell获得当前文件夹位置

   ROOT=$(shell pwd)

12. 包含依赖文件时,不要放在所有目标的前面,如下所示

STM32F gcc编译全纪录

其中原因就是make依然会将dep文件作为目标,从而后面的目标无法得到运行。

四、熟悉gcc编译

Gcc编译学习是一个长期的过程,主要参考文档见安装目录下的Documation中的所有pdf和readme.txt。下面是简短的学习笔记。

1.      参数解释:

-g(level): 在本地操作系统产生指定格式的调试消息(stabs,COFF,XCOFF,DWARF 2)

-ggdb(level): 产生gdb格式的调试信息

-gstabs(level):产生stabs格式的调试信息,不包括GDB扩展.-->BSD.

  (level)-->默认级别为2

  0:不产生调试信息

  1:产生最少的调试信息

  3:包括额外的信息,包括在程序中出现的宏定义等.

  -gstabs+,-gcoff,-gxcoff,-gxcoff+,-gdwarf-version,-gvms

-c

   只激活预处理,编译和汇编,生成obj文件.还需要通过ld链接器对所有

   .o文件进行链接才能生成执行文件.

   -S

   只激活预处理和编译把文件汇编到汇编代码,相当于将程序生成.s文件.

   -E

   只进行预处理

   -o

   定制目标名称,缺省情况下生成a.out文件. gcc -ohello.exe test.c

   -D(macro)

   相当于#define  macro    1比如DDEBUG相当于将DEBUG的宏定义为1

   -C

   在预处理的时候不删除注释信息.

   -M

   生成文件的关联信息,就可以知道源代码依赖了那些头文件.

   -MM

   同上,忽略#include造成的依赖关系

   -MD

   和-M相当,但是输出导入到.d文件中. gcc -MDtest.c 输出依赖关系

   放在test.d文件里

   -MF file

   生成指定的默认依赖文件.

   -MMD

   和-MM相当,忽略#include造成的依赖关系

   -l(library)

   用于指定编译的时候使用的库. gcc-lgtk test.c 则程序使用gtk库进

   行编译.不过需要注意的是gcc库一般以lib(name).a来命名库文件,使用

   -l参数导入库文件的时候,直接使用-lname来引入,lib被省略.

   -L(dir)

   指定库文件所在的文件夹

   -T script

   指定空间分配文件

参考文档:GCC参数详解

2.      -ffunction-sections,-fdata-sections:

因为GCC链接操作以section作为最小的处理单元,只要一个section中有某个符号被引用,该section就会被加入。如果我们的某个.c程序中所有function都加入同一个section.则如果用到这个.c生成的.o的其中任何一个function.则必须将所有function(符号)加入其中。如此,则使用-ffunction-sections 和 -fdata-sections将每个符号创建为一个sections. sections名与function,data名保持一致。则在link阶段,-Wl,--gc-sections 申明去掉不用的section。就可以去掉没用的function(符号)了。可以减少code size。

à去除可执行文件中没用到的符号或函数

3.      调用标准库函数printf的编译错误。

a. 需要在选项中需要添加—specs= nano.specs用来优化代码尺寸,它使用了新的newlib-nano代码库,具体可以参考Documation/readme.txt和源码中的README.nano说明文档,需要注意的上这个选项上链接选项。

b. 支持浮点数打印–u _printf_float,当然相应的代码尺寸会增大。

c. 将安装文件夹中的example里面的retarget.c复制到源代码目录

d. 尽管选项设置都没问题,但依然出现以下错误:

   c:/program files/gnu tools arm embedded/4.72013q1/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7-m\libc_s.a(lib_a-sbrkr.o):In function `_sbrk_r':

sbrkr.c:(.text._sbrk_r+0xc): undefinedreference to `_sbrk'

c:/program files/gnu tools armembedded/4.72013q1/bin/../lib/gcc/arm-none-eabi/4.7.3/../../../../arm-none-eabi/lib/armv7-m\libc_s.a(lib_a-closer.o):In function `_close_r':

closer.c:(.text._close_r+0xc): undefinedreference to `_close'

查阅libc.pdf文档内容,也就是说在实现printf函数的时候,需要系统提供其它函数的实现,libc.pdfàpage164, and chapter12 syscalls.

经查问题原因如下:

STM32F gcc编译全纪录

将编译顺序调换一下即可,第一条为正确的编译顺序。

 

五、建立定制的应用程序框架

以下为参考的应用框架,针对于小型嵌入式的平台程序开发,设计如下框架的原因:在嵌入式开发中,存在一个电路板(硬件平台)应用在多个项目的情况。

FRAMEà 所有项目的总目录,一般为所有项目的源程序目录

FRAME /PROJ:    所有项目的根目录

FRAME /HAL:     硬件平台目录,添加一块新PCB版,编写对应的底层的接口文件

FRAME /LIB:      库文件:主要有对应CPU的库文件和本身应用程序的库文件。

FRAME /BUILD:   编译工作空间

FRAME /BUILD /make.rule:为所有源文件共有的makefile

FRAME /BUILD /Makefile:  配置当前项目工程和编译

FRAME /BUILD/configs:   包含当前编译工程文件名

FRAME

├─PROJ

│  ├─PROJ2

│  └─PROJ1

├─HAL

├─LIB

│  ├─STM32F10xP(st官方提供的库文件v3.5)

│  ├─CMSIS (ARM官方提供的库文件)

│  └─COMMON

└─BUILD

    │  Makefile

    │  make.rule

    └─configs

具体详见附件内容。

FRAME.tar.bz2

使用方法:可以进入Build目录,配置对应的项目工程,然后make即可;或者可以直接进入项目工程的目录,直接make同样可以。

针对STM32F10xp外设库的依赖规则做以下简要分析,供大家参考:

STM32F gcc编译全纪录

参考文档:

1.  驾驭Makefile       2.GNUMakev3.8 

3. gcc.pdf, ld.pdf libc.pdf…and so on

4. http://zaidpirwani.com/1160/stm32f3discovery-arm-gcc-environment-on-windows-part-1/

  http://zaidpirwani.com/1187/stm32f3discovery-basic-project-template-part-2