ARM架构与编程(基于I.MX6ULL): keil_gcc_Makefile(八)(上)

简介: ARM架构与编程(基于I.MX6ULL): keil_gcc_Makefile(八)

1.IDE背后的命令


1.1 IDE是什么


IDE指集成开发环境(Integrated Development Environment)。

我们开发STM32F103等单片机程序时使用是keil就是一种IDE。


使用IDE,很容易操作,点点鼠标就可完成:


添加文件

指定文件路径(头文件路径、库文件路径)

指定链接库

编译、链接

下载、调试


1.2 IDE的背后是命令


现场使用keil来演示命令的操作。


注意


使用GitBash执行命令的话

由于GitBash采用类似Linux的文件路径表示方法(比如 /d/abc,而非 d:\abc),命令行中windows格式的路径名要加上双引号,比如".\objects\main.o"

使用dos命令行执行命令的话

不需要加双引号

在某个Keil工程所在目录下,打开Git Bash:

doc_and_source_for_mcu_mpu\STM32MF103\source\02_录制视频时现场编写的源码\01_led_c


编译main.c

执行命令:

"C:\Keil_v5\ARM\ARMCC\Bin\ArmCC" --c99 --gnu -c --cpu Cortex-M3 -D__EVAL -g -O0 --apcs=interwork --split_sections -I.\RTE\_led_c -I"C:\Users\thisway_diy\AppData\Local\Arm\Packs\Keil\STM32F1xx_DFP\2.3.0\Device\Include" -I"C:\Keil_v5\ARM\CMSIS\Include" -D__UVISION_VERSION="527" -DSTM32F10X_HD -o ".\objects\main.o" --omf_browse ".\objects\main.crf" --depend ".\objects\main.d" "main.c"


编译start.S

执行命令:

"C:\Keil_v5\ARM\ARMCC\Bin\ArmAsm" --cpu Cortex-M3 --pd "__EVAL SETA 1" -g --apcs=interwork -I.\RTE\_led_c -I"C:\Users\thisway_diy\AppData\Local\Arm\Packs\Keil\STM32F1xx_DFP\2.3.0\Device\Include" -I"C:\Keil_v5\ARM\CMSIS\Include" --pd "__UVISION_VERSION SETA 527" --pd "STM32F10X_HD SETA 1" --list ".\listings\start.lst" --xref -o ".\objects\start.o" --depend ".\objects\start.d" "start.s"


链接

执行命令:

"C:\Keil_v5\ARM\ARMCC\Bin\ArmLink" --cpu Cortex-M3 ".\objects\main.o" ".\objects\start.o" --ro-base 0x08000000 --entry 0x08000000 --rw-base 0x20000000 --entry Reset_Handler --first __Vectors --strict --summary_stderr --info summarysizes --map --load_addr_map_info --xref --callgraph --symbols --info sizes --info totals --info unused --info veneers --list ".\Listings\led_c.map" -o ".\Objects\led_c.axf"


1.3. 提出几个问题


头文件在哪?


库文件在哪?库文件是哪个?


源文件有哪些?


源文件怎么编译?可以指定编译参数吗?


多个源文件怎么链接成一个可执行程序?


有a.c, b.c, c.c,我只修改了a.c,就只需要编译a.c,然后在链接:怎么做到的?


1.4. 要解决这些疑问,需要了解命令行


如果你只学习单片机,只想使用keil,当然可以不学习命令行。

但是如果想升级到Linux、各类RTOS,需要掌握命令行。


1.5. 有两套主要的编译器


armcc


ARM公司的编译器

keil使用的就是armcc

gcc


GNU工具链

Linux等开源软件经常使用gcc

后面以GNU工具链为例讲解,所涉及的知识可以平移到armcc上。


2.准备工作


2.1. arm-linux-gcc和gcc是类似的


arm-linux-gcc

给ARM芯片编译程序

gcc

在x86编译程序

用法基本一样

为方便演示,我们使用gcc

为了方便在windows下演示,我们使用Code::Blocks

它的安装程序自带gcc


2.2. Code::Blocks


它是一款基于GCC的windows IDE,可以用来开发C/C++/Fortran。

官网地址:http://www.codeblocks.org/


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wYAE27YT-1649769892187)(lesson\gcc\003_download_codeblocks.png)]


在我们提供的GIT仓库里也有:git clone https://e.coding.net/weidongshan/noos/cortexA7_windows_tools.git

下载GIT后,在apps目录下。


2.2.1 安装


双击安装。


2.2.2 设置windows环境变量


在Path环境变量中添加:C:\Program Files\CodeBlocks\MinGW\bin


2.2.3 命令行示例


启动Git Bash,编译程序hello.c:

#include <stdio.h>
int main(void)
{
  printf("hello, world!\n");
  return 0;
}


编译、运行命令如下:

gcc -o hello  hello.c
./hello.exe


3. gcc编译过程详解


3.1. 程序编译4步骤


1670932751838.jpg

我们经常使用“编译”泛指上面的4个步骤之一,甚至有时候会囊括这四个步骤。


3.2. gcc的使用方法


gcc  [选项]   文件名


3.2.1 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       // 再链接


3.2.2 gcc常用选项


3.2.2.1 手工控制编译过程

选项 功能
-v 查看gcc编译器的版本,显示gcc执行时的详细过程
-o 指定输出文件名为file,这个名称不能跟源文件名同名
-E 只预处理,不会编译、汇编、链接t
-S 只编译,不会汇编、链接
-c 编译和汇编,不会链接


一个c/c++文件要经过预处理、编译、汇编和链接才能变成可执行文件。

(1)预处理

C/C++源文件中,以“#”开头的命令被称为预处理命令,如包含命令“#include”、宏定义命令“#define”、条件编译命令“#if”、“#ifdef”等。预处理就是将要包含(include)的文件插入原文件中、将宏定义展开、根据条件编译命令选择要使用的代码,最后将这些东西输出到一个“.i”文件中等待进一步处理。

(2)编译

编译就是把C/C++代码(比如上述的“.i”文件)“翻译”成汇编代码。

(3)汇编

汇编就是将第二步输出的汇编代码翻译成符合一定格式的机器代码,在Linux系统上一般表现为ELF目标文件(OBJ文件)。“反汇编”是指将机器代码转换为汇编代码,这在调试程序时常常用到。

(4)链接

链接就是将上步生成的OBJ文件和系统库的OBJ文件、库文件链接起来,最终生成了可以在特定平台运行的可执行文件。


hello.c(预处理)->hello.i(编译)->hello.s(汇编)->hello.o(链接)->hello

详细的每一步命令如下:

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


上面一连串命令比较麻烦,gcc会对.c文件默认进行预处理操作,使用-c再来指明了编译、汇编,从而得到.o文件,

再将.o文件进行链接,得到可执行应用程序。简化如下:

gcc -c -o hello.o hello.c
gcc -o hello hello.o


3.2.2.2 使用后缀名决定编译过程


参考《嵌入式Linux应用开发完全手册》:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C6TVJjQq-1649770002021)(lesson\gcc\002_gcc_default_operation.png)]


总结

输入文件的后缀名和选项共同决定gcc到底执行那些操作

在编译过程中,最后的步骤都是链接

除非使用了-E、-S、-c选项

或者编译出错阻止了完整的编译过程


3.2.2.3 指定头文件目录


头文件在哪里?


系统目录

系统目录在哪?工具链里的某个include目录


怎么确定?

echo 'main(){}'| gcc -E -v -  // 它会列出头文件目录、库目录(LIBRARY_PATH)


可以不使用系统include目录吗?可以,编译时指定参数-nostdinc


可以自己指定头文件目录

-I <头文件目录>


3.2.2.4 指定库文件


库文件在哪里?


系统目录

系统目录在哪?工具链里的某个lib目录


怎么确定?

echo 'main(){}'| gcc -E -v -  // 它会列出头文件目录、库目录(LIBRARY_PATH)


可以不使用系统lib目录吗?可以,编译时指定参数-nostdlib


可以自己指定库文件目录

-L <库文件目录>


指定库文件

-l  <abc>   // 链接 libabc.so 或 lib.a


3.3. 开发板程序编译示例


最后链接时,使用arm-linux-ld而不是使用arm-linux-gcc


前者可以完全自己指定所连接的文件

后者会链接一些默认的启动文件


3.4. 参考书籍


《嵌入式Linux应用开发完全手册》中的《3.1 交叉编译工具选项说明》


4.makefile


4.1 Makefile的引入及规则


使用keil, mdk,avr等工具开发程序时点击鼠标就可以编译了,它的内部机制是什么?它怎么组织管理程序?怎么决定编译哪一个文件?


答:实际上windows工具管理程序的内部机制,也是Makefile,我们在linux下来开发裸板程序的时候,使用Makefile组织管理这些程序,本节我们来讲解Makefile最基本的规则。Makefile要做什么事情呢?

组织管理程序,组织管理文件,我们写一个程序来实验一下:


文件a.c

02  #include <stdio.h>
03
04  int main()
05  {
06  func_b();
07  return 0;
08}


文件b.c

2 #include <stdio.h>
3
4 void func_b()
5 {
6  printf("This is B\n");
7 }


编译:

gcc -o test a.c b.c


运行:

./test


结果:

This is B


gcc -o test a.c b.c 这条命令虽然简单,但是它完成的功能不简单。


我们来看看它做了哪些事情,


我们知道.c程序 ==》 得到可执行程序它们之间要经过四个步骤:


1.预处理

2.编译

3.汇编

4.链接

相关文章
|
30天前
|
Docker 容器
docker:记录如何在x86架构上构造和使用arm架构的镜像
为了实现国产化适配,需将原x86平台上的Docker镜像转换为适用于ARM平台的镜像。本文介绍了如何配置Docker buildx环境,包括检查Docker版本、安装buildx插件、启用实验性功能及构建多平台镜像的具体步骤。通过这些操作,可以在x86平台上成功构建并运行ARM64镜像,实现跨平台的应用部署。
586 2
|
1月前
|
编解码 弹性计算 应用服务中间件
阿里云服务器Arm计算架构解析:Arm计算架构云服务器租用收费标准价格参考
阿里云服务器架构分为X86计算、Arm计算、高性能计算等多种架构,其中Arm计算架构以其低功耗、高效率的特点受到广泛关注。本文将深入解析阿里云Arm计算架构云服务器的技术特点、适用场景以及包年包月与按量付费的收费标准与最新活动价格情况,以供选择参考。
|
1月前
|
机器学习/深度学习 弹性计算 编解码
阿里云服务器计算架构X86/ARM/GPU/FPGA/ASIC/裸金属/超级计算集群有啥区别?
阿里云服务器ECS提供了多种计算架构,包括X86、ARM、GPU/FPGA/ASIC、弹性裸金属服务器及超级计算集群。X86架构常见且通用,适合大多数应用场景;ARM架构具备低功耗优势,适用于长期运行环境;GPU/FPGA/ASIC则针对深度学习、科学计算、视频处理等高性能需求;弹性裸金属服务器与超级计算集群则分别提供物理机级别的性能和高速RDMA互联,满足高性能计算和大规模训练需求。
|
1月前
|
设计模式 人工智能 算法
编程之旅:从代码到架构的感悟
【9月更文挑战第33天】在编程的世界里,代码不仅是实现功能的工具,更是连接思想与现实的桥梁。本文将通过个人的编程经历,分享从编写第一行代码到设计系统架构的旅程,探索编程背后的哲学和技术演变。我们将一起思考,如何在代码的海洋中找到自己的航向,以及在这个过程中如何不断成长和适应变化。
|
1月前
|
存储 Docker 容器
ARM架构鲲鹏主机BClinux离线安装docker步骤
下载并安装适用于ARM架构的Docker CE二进制文件,解压后移动至/usr/bin目录。创建docker组,配置systemd服务脚本(docker.service、docker.socket、containerd.service),重载systemd配置,启动并启用docker服务。编辑daemon.json配置存储驱动、镜像加速地址等,最后拉取所需镜像。
44 0
|
1月前
|
NoSQL MongoDB Docker
求助,有没有大神可以找到arm64架构下mongodb的3.6.8版本的docker镜像?
在Docker Hub受限的情况下,寻求适用于ARM架构的docker镜像资源或拉取链接,以便在x86架构上获取;内网中的机器为ARM架构,因此优先请求适合ARM的Docker镜像或Dockerfile,非常感激您的帮助。
|
8天前
|
缓存 负载均衡 JavaScript
探索微服务架构下的API网关模式
【10月更文挑战第37天】在微服务架构的海洋中,API网关犹如一座灯塔,指引着服务的航向。它不仅是客户端请求的集散地,更是后端微服务的守门人。本文将深入探讨API网关的设计哲学、核心功能以及它在微服务生态中扮演的角色,同时通过实际代码示例,揭示如何实现一个高效、可靠的API网关。
|
6天前
|
Cloud Native 安全 数据安全/隐私保护
云原生架构下的微服务治理与挑战####
随着云计算技术的飞速发展,云原生架构以其高效、灵活、可扩展的特性成为现代企业IT架构的首选。本文聚焦于云原生环境下的微服务治理问题,探讨其在促进业务敏捷性的同时所面临的挑战及应对策略。通过分析微服务拆分、服务间通信、故障隔离与恢复等关键环节,本文旨在为读者提供一个关于如何在云原生环境中有效实施微服务治理的全面视角,助力企业在数字化转型的道路上稳健前行。 ####
|
7天前
|
Dubbo Java 应用服务中间件
服务架构的演进:从单体到微服务的探索之旅
随着企业业务的不断拓展和复杂度的提升,对软件系统架构的要求也日益严苛。传统的架构模式在应对现代业务场景时逐渐暴露出诸多局限性,于是服务架构开启了持续演变之路。从单体架构的简易便捷,到分布式架构的模块化解耦,再到微服务架构的精细化管理,企业对技术的选择变得至关重要,尤其是 Spring Cloud 和 Dubbo 等微服务技术的对比和应用,直接影响着项目的成败。 本篇文章会从服务架构的演进开始分析,探索从单体项目到微服务项目的演变过程。然后也会对目前常见的微服务技术进行对比,找到目前市面上所常用的技术给大家进行讲解。
17 1
服务架构的演进:从单体到微服务的探索之旅
|
6天前
|
Cloud Native 安全 API
云原生架构下的微服务治理策略与实践####
—透过云原生的棱镜,探索微服务架构下的挑战与应对之道 本文旨在探讨云原生环境下,微服务架构所面临的关键挑战及有效的治理策略。随着云计算技术的深入发展,越来越多的企业选择采用云原生架构来构建和部署其应用程序,以期获得更高的灵活性、可扩展性和效率。然而,微服务架构的复杂性也带来了服务发现、负载均衡、故障恢复等一系列治理难题。本文将深入分析这些问题,并提出一套基于云原生技术栈的微服务治理框架,包括服务网格的应用、API网关的集成、以及动态配置管理等关键方面,旨在为企业实现高效、稳定的微服务架构提供参考路径。 ####
29 5