armcc的交叉编译和持续交付

因为基本上没什么人直接使用 armcc 作为自动化编译、持续集成和交付的工具,更多是使用 UV4 软件读取 .uvprojx 文件来获取编译信息,进而驱动 armcc 进行编译过程。

通过自行编辑 Makefile 文件,使用 make 和 armcc 工具可以对代码文件进行编译,可以进行静态库的生成,也可以生成可烧录文件,但是就不要想着复杂的 make test 等测试功能了。

DIFF BETWEEN THEM

下方详细描述一下使用 arm-none-eabi-gccmakecmakearmccmake 的不同。

  1. 使用 arm-none-eabi-gccmake 编译的 SDK 过程属于 Unix Makefile 编译过程(详见 CMake 工具及官网对 CMakefiles Generators 说明)。暂时不清楚使用 armcccmake 是如何生成 Makefile 的,因为尚不了解toolchain的绑定过程,导致一致检测到的是 windows平台本地的 mingw 工具。
  2. 启动文件不同。详见 ABOUT STARTUP FILE
  3. 工具链指定方式不同。详见 TOOLCHAIN

KEIL MDK ENV

MDK SOFTPACK

MDK5 Software Packs

TOOLCHAIN DOWNLOADS

首先需要安装版本较新的 Keil MDK-ARM 开发软件。最好是在Windows上安装,方便破解。

可以从 About uVision 中查看版本信息。也可以直接在 PowerShell 中直接调用查看。

MDK 的版本为 v5.22 确实是比较老旧的,建议下载 v5.27 及以上版本。

下载链接:MDKv5.28MDKv5.37keygen

官网下载:ARM Compiler 5 Downloads

image-20220608100300944
image-20220608100748964

TOOLCHAIN

下面的一些参数可以从 ARM Compiler v5.06 for uVision armcc User Guide 获取帮助。

FROMELF

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Options:
--help display this help screen
--vsn display version information
--output file the output file. (defaults to stdout for -text format)
--nodebug do not put debug areas in the output image
--nolinkview do not put sections in the output image

Binary Output Formats:
--bin Plain Binary
--m32 Motorola 32 bit Hex
--i32 Intel 32 bit Hex
--vhx Byte Oriented Hex format

--base addr Optionally set base address for m32,i32

Output Formats Requiring Debug Information
--fieldoffsets Assembly Language Description of Structures/Classes
--expandarrays Arrays inside and outside structures are expanded

Other Output Formats:
--elf ELF
--text Text Information

Flags for Text Information
-v verbose
-a print data addresses (For images built with debug)
-c disassemble code
-d print contents of data section
-e print exception tables
-g print debug tables
-r print relocation information
-s print symbol table
-t print string table
-y print dynamic segment contents
-z print code and data size information
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Usage: armlink option-list input-file-list
where
option-list is a list of case-insensitive options.
input-file-list is a list of input object and library files.

General options (abbreviations shown capitalised):
--help Print this summary.
--output file Specify the name of the output file.
--via file Read further arguments from file.

Options for specifying memory map information:
--partial Generate a partially linked object.
--scatter file Create the memory map as described in file.
--ro-base n Set exec addr of region containing RO sections.
--rw-base n Set exec addr of region containing RW/ZI sections.

Options for controlling image contents:
--bestdebug Add debug information giving best debug view to image.
--datacompressor off
Do not compress RW data sections.
--no_debug Do not add debug information to image.
--entry Specify entry sections and entry point.
--libpath Specify path to find system libraries from.
--userlibpath Specify path to find user libraries from.
--no_locals Do not add local symbols to image symbol table.
--no_remove Do not remove unused sections from image.

Options for controlling image related information:
--callgraph Create a static callgraph of functions.
--feedback file Generate feedback that can be used by the compiler in file.
--info topic List misc. information about image.
Available topics: (separate multiple topics with comma)
common List common sections eliminated from the image.
debug List eliminated input debug sections.
sizes List code and data sizes for objects in image.
totals List total sizes of all objects in image.
veneers List veneers that have been generated.
unused List sections eliminated from the image.
--map Display memory map of image.
--symbols List symbols in image.
--xref List all cross-references between input sections.

--summary_stderr

ARMCC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Usage:         armcc [options] file1 file2 ... filen
Main options:

--arm Generate ARM code
--thumb Generate Thumb code
--c90 Switch to C mode (default for .c files)
--cpp Switch to C++ mode (default for .cpp files)
-O0 Minimum optimization
-O1 Restricted optimization for debugging
-O2 High optimization
-O3 Maximum optimization
-Ospace Optimize for codesize
-Otime Optimize for maximum performance
--cpu <cpu> Select CPU to generate code for
--cpu list Output a list of all the selectable CPUs
-o <file> Name the final output file of the compilation
-c Compile only, do not link
--asm Output assembly code as well as object code
-S Output assembly code instead of object code
--interleave Interleave source with disassembly (use with --asm or -S)
-E Preprocess the C source code only
-D<symbol> Define <symbol> on entry to the compiler
-g Generate tables for high-level debugging
-I<directory> Include <directory> on the #include search pat

MAKEFILE

make 可以在任一路径下执行,只需要加入 -C <path> 即可,即告诉make工具在 <path> 路径下执行编译。方便了在 windows 命令行环境下的执行。

编写 Makefile 的时候,某些变量可以通过外部传递,而且方法也很简单,甚至内部甚至不需要声明,只需要在引用处写明变量名称即可。然后外部调用时以 VARIABLE="value" 的形式进行声明即可。如下:

1
make libmxs -C 20220607 MANIFEST_PATH="F:\Workspace\20220511-galileo-manifest" TOOLCHAIN_PATH="D:\Keil_v528\ARM\ARMCC\bin"

COMPILING CONTROL STRINGS

下面这些编译参数是复制自 KEIL IDE 的,对应的平台是 STM32L4R9。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
--c99
-c
--cpu Cortex-M4.fp
-D__MICROLIB -g -O3 --apcs=interwork --split_sections

-I ../app
-I ../M_BSP
-I ../M_BSP/BMM150
-I ../M_BSP/Sensor_R1
-I ../M_BSP/lps33k
-I ../M_BSP/lcd
-I ../M_BSP/PSRAM
-I ../M_BSP/OSPI_NOR
-I ../Driver
-I ../../../Drivers/CMSIS/Include
-I ../../../Drivers/CMSIS/Device/ST/STM32L4xx/Include
-I ../../../Drivers/STM32L4xx_HAL_Driver/Inc
-I ../../../Drivers/BSP/STM32L4R9I_EVAL
-I ../../../Drivers/BSP/Components/Common

-I./RTE/_Watch_EVAL
-IC:/Users/mixo/AppData/Local/Arm/Packs/ARM/CMSIS/5.5.1/CMSIS/Core/Include
-IDrivers/CMSIS/Device/ST/STM32L4xx/Include
-D__UVISION_VERSION="528" -D_RTE_ -DSTM32L4R9xx -DUSE_HAL_DRIVER -DUSE_GVO_390x390
-o .\Watch\*.o --omf_browse .\Watch\*.crf --depend .\Watch\*.d

TOOLCHAIN

在 Makefile 文件中,往往为了互相兼容,默认编译器的名称就是 gcc ,只是前缀不同而已,而 armcc 编译器在使用时则需清晰指定名称。

下方为 armcc 工具链的指定方式:

1
2
3
4
5
6
# 工具链
CC=$(TOOLCHAIN_PATH)\"armcc.exe"
AS=$(TOOLCHAIN_PATH)\"armasm.exe"
AR=$(TOOLCHAIN_PATH)\"armar.exe"
LINK=$(TOOLCHAIN_PATH)\"armlink.exe"
FROM_ELF=$(TOOLCHAIN_PATH)\"fromelf.exe"

下方为 arm-none-eabi-gcc 工具链的指定(由 stm32 CubeMX 生成)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PREFIX = arm-none-eabi-
# The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx)
# either it can be added to the PATH environment variable.
ifdef GCC_PATH
CC = $(GCC_PATH)/$(PREFIX)gcc
AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp
CP = $(GCC_PATH)/$(PREFIX)objcopy
SZ = $(GCC_PATH)/$(PREFIX)size
else
CC = $(PREFIX)gcc
AS = $(PREFIX)gcc -x assembler-with-cpp
CP = $(PREFIX)objcopy
SZ = $(PREFIX)size
endif
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S

COMPILING PARAMETERS

总结出常见的编译参数如下:

MACRO DEFINITIONS

宏定义参数:-DUSE_HAL_DRIVER / -DSTM32L4R9xx / -D__MICROLIB

其中,前两个还是要依具体芯片的硬件参数来看的

CPU

CPU 参数:--cpu Cortex-M4.fp / --cpu Cortex-M4 等。

使用armcc --cpu list 命令可以查看所有可接受的芯片,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
--cpu=4
--cpu=4T
--cpu=5T
--cpu=5TE
--cpu=5TEJ
--cpu=6-M
--cpu=6S-M
--cpu=7-A
--cpu=7-R
--cpu=7-M
--cpu=7E-M
--cpu=7-A.security
--cpu=ARM7EJ-S
--cpu=ARM7TDMI
--cpu=ARM720T
--cpu=ARM7TDMI-S
--cpu=ARM9TDMI
--cpu=ARM920T
--cpu=ARM922T
--cpu=ARM9E-S
--cpu=ARM926EJ-S
--cpu=ARM946E-S
--cpu=ARM966E-S
--cpu=Cortex-M0
--cpu=Cortex-M0plus
--cpu=SC000
--cpu=Cortex-M1
--cpu=Cortex-M1.os_extension
--cpu=Cortex-M1.no_os_extension
--cpu=Cortex-M3
--cpu=Cortex-M3-rev0
--cpu=SC300
--cpu=Cortex-M4
--cpu=Cortex-M4.fp.sp
--cpu=Cortex-M7
--cpu=Cortex-M7.fp.sp
--cpu=Cortex-M7.fp.dp
--cpu=Cortex-R4
--cpu=Cortex-R4F
--cpu=Cortex-A5
--cpu=Cortex-A5.vfp
--cpu=Cortex-A5.neon
--cpu=Cortex-A7
--cpu=Cortex-A7.no_neon
--cpu=Cortex-A7.no_neon.no_vfp
--cpu=Cortex-A8
--cpu=Cortex-A8.no_neon
--cpu=Cortex-A8NoNEON
--cpu=Cortex-A9
--cpu=Cortex-A9.no_neon
--cpu=Cortex-A9.no_neon.no_vfp
--cpu=Cortex-A12
--cpu=Cortex-A12.no_neon.no_vfp
--cpu=Cortex-A15
--cpu=Cortex-A15.no_neon
--cpu=Cortex-A15.no_neon.no_vfp
--cpu=Cortex-A17
--cpu=Cortex-A17.no_neon.no_vfp

ABOUT STARTUP FILE

CubeMX 针对不同的编译方式和平台生成对应的 startup file 。而使用 Unix Makefile 编译的 startup_stm32l476xx.s 和 使用 Keil MDK-ARM 的是不一样的。

startup_stm32xxxxxx.s 是使用汇编语言写好的基本程序,当STM32 芯片上电启动的时候,会执行此处的汇编程序,从而建立 C 语言的运行环境,所以称之为启动文件。

由于编译器不一致,所以 .s 的启动文件也不能互相兼容,需要使用 CubeMX重新生成。

image-20220609110616631

DEBUG

ERROR

ERROR #35: PLEASE SELECT FIRST THE TARGET STM32L4XX DEVICE USED IN YOUR APPLICATION

image-20220608105439447

没有添加宏定义,添加 -DSTM32L476xx-DUSE_HAL_DRIVER 即可。

ERROR L6050U: THE CODE SIZE OF THE IMAGE EXCEEDS THE MAXIMUM

image-20220608110734097

版权问题,当你在使用keil时,出现 error: L6050U: The code size of this image (45178 bytes) exceeds the maximum allowed for this version of the linker. 的时候,那就是 keil 没有被破解,软件本身的字节数有局限性,需要下载个MDK注册机进行破解!

Error: A1854E: Unknown opcode 'BLX', maybe wrong target CPU?

image-20220608151900214

WARNING

Warning: #1295-D: Deprecated declaration two_wired_resync - give arg types

image-20220608135309057

在传递参数为空的函数中,必须写 void ,armcc要求比较严格,arm-none-eabi 的要求比较宽松。

REFERENCE

  1. keil编译链接过程以及ARMCC、ARMASM、FROMELF、ARMLINK、ARMAR的使用
  2. ARM Compiler v5.06 for uVision armcc User Guide
  3. ARM® Compiler v5.06 for μVision®