From 44fc09eecd65032e2e6f7da2f64d8533b7d4055a Mon Sep 17 00:00:00 2001 From: guozhanxin Date: Mon, 16 May 2022 18:16:50 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E6=9B=B4=E6=96=B0=E3=80=91scons=20?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../build-config-system/SCons.md | 36 ++++++------------ .../figures/buildconfig20.png | Bin 0 -> 14563 bytes ...fc4640958ffdb11d9741.png => stm32f10x.png} | Bin 3 files changed, 12 insertions(+), 24 deletions(-) create mode 100644 development-tools/build-config-system/figures/buildconfig20.png rename development-tools/build-config-system/figures/{b1e0b39d090bfc4640958ffdb11d9741.png => stm32f10x.png} (100%) diff --git a/development-tools/build-config-system/SCons.md b/development-tools/build-config-system/SCons.md index 633503d..2109c3a 100644 --- a/development-tools/build-config-system/SCons.md +++ b/development-tools/build-config-system/SCons.md @@ -1,8 +1,6 @@ # SCons -## 1 构建工具(系统) - -### 1.1 什么是构建工具(系统) +### 什么是构建工具 构建工具 (software construction tool) 是一种软件,它可以根据一定的规则或指令,将源代码编译成可执行的二进制程序。这是构建工具最基本也是最重要的功能。实际上构建工具的功能不止于此,通常这些规则有一定的语法,并组织成文件。这些文件用来控制构建工具的行为,在完成软件构建之外,也可以做其他事情。 @@ -10,17 +8,17 @@ 由于历史原因,Makefile 的语法比较混乱,不利于初学者学习。此外在 Windows 平台上使用 Make 也不方便,需要安装 Cygwin 环境。为了克服 Make 的种种缺点,人们开发了其他构建工具,如 CMake 和 SCons 等。 -### 1.2 RT-Thread 构建工具 +### RT-Thread 构建工具 RT-Thread 早期使用 Make/Makefile 构建。从 RT-Thread 0.3.0 开始,RT-Thread 开发团队逐渐引入了 SCons 构建系统,引入 SCons 唯一的目是:使大家从复杂的 Makefile 配置、IDE 配置中脱离出来,把精力集中在 RT-Thread 功能开发上。 有些读者可能会有些疑惑,这里介绍的构建工具与 IDE 有什么不同呢?IDE 通过图形化界面的操作来完成构建。大部分 IDE 会根据用户所添加的源码生成类似 Makefile 或 SConscript 的脚本文件,在底层调用类似 Make 或 SCons 的工具来构建源码。 -## 2 SCons 简介 +## SCons 简介 SCons 是一套由 Python 语言编写的开源构建系统,类似于 GNU Make。它采用不同于通常 Makefile 文件的方式,而是使用 SConstruct 和 SConscript 文件来替代。这些文件也是 Python 脚本,能够使用标准的 Python 语法来编写。所以在 SConstruct、SConscript 文件中可以调用 Python 标准库进行各类复杂的处理,而不局限于 Makefile 设定的规则。 -### 2.1 RT-Thread中Scons的脚本结构 +### RT-Thread中Scons的脚本结构 SCons 使用 SConscript 和 SConstruct 文件来组织源码结构并进行构建,SConstruct是scons构建的主脚本,SConscript存放在源代码的子目录下,通常放在项目的子目录,以达到分层构建的目的。一个项目 (BSP) 只有一 SConstruct,但是会有多个 SConscript。一般情况下,每个存放有源代码的子目录下都会放置一个 SConscript。 @@ -46,25 +44,15 @@ SCons 使用 SConscript 和 SConstruct 文件来组织源码结构并进行构 RT-Thread当前的构建系统由以下几个部分组成: -```mermaid -flowchart LR - A(RT-Thread构建系统)-->Kconfig - A(RT-Thread构建系统)-->rtconfig.py - A(RT-Thread构建系统)-->SCons - SCons --> SConscript - SCons --> SConstruct - SConscript --> Scons标准函数 - SConscript --> RT-Thread自定义函数 - SConscript --> Python函数 -``` +![buildconfig20](./figures/buildconfig20.png) -## 3 SCons 基本命令 +## 常用 SCons 命令 RT-Thread 构建系统支持多种编译器。目前支持的编译器包括 ARM GCC、MDK、IAR、VisualStudio、Visual DSP。主流的 ARM Cortex M0、M3、M4 平台,基本上 ARM GCC、MDK、IAR 都是支持的。有一些 BSP 可能仅支持一种,读者可以阅读该 BSP 目录下的 rtconfig.py 里的 CROSS_TOOL 选项查看当前支持的编译器。 打开 Env 工具,如果是 ARM 平台的芯片,输入 scons 命令直接编译 BSP,这时候默认使用的是 ARM GCC 编译器,因为 Env 工具带有 ARM GCC 编译器。 如下图所示使用 `scons` 命令编译 BSP。 -![使用 scons 命令编译 stm32f10x-HAL BSP](figures/b1e0b39d090bfc4640958ffdb11d9741.png) +![使用 scons 命令编译 stm32f10x-HAL BSP](figures/stm32f10x.png) 如果用户要使用其他的 BSP 已经支持的编译器编译工程,或者 BSP 为非 ARM 平台的芯片,那么不能直接使用 scons 命令编译工程,需要自己安装对应的编译器,并且指定使用的编译器路径。在编译工程前,可以在 Env 命令行界面使用下面的 2 个命令指定编译器为 MDK 和编译器路径为 MDK 的安装路径: @@ -185,11 +173,11 @@ er\inc -ILibraries\CMSIS\CM3\DeviceSupport\ST\STM32F10x -IF:\Project\git\rt-thre ... ``` -## 4 SCons 函数 +## SCons 函数 本章节将介绍在使用编写 SConscript 脚本中常用的函数,包含 SCons 原生标准函数以及RT-Thread扩展的函数。关于 SCons 原生标准函数,在 [SCons](http://www.scons.org/doc/production/HTML/scons-user/index.html) 的网站上可以找到详细的 SCons 原生函数介绍。 -### 4.1 Scons 原生标准函数 +### Scons 原生标准函数 #### 4.1.1 Import(vars) @@ -245,7 +233,7 @@ src = ['shell.c', 'msh.c'] src = Glob('shell.c') ``` -### 4.2 RT-Thread 自定义 Scons 函数 +### RT-Thread 自定义 Scons 函数 #### 4.2.1 SrcRemove(src, remove) @@ -315,9 +303,9 @@ if GetDepend('MSH_USING_BUILT_IN_COMMANDS'): # 判断是否启用MSH的内建命 Sconscript 脚本中可以使用任何 Python 库函数,使用方式和正常的 Python 脚本无异。这也是 Scons 构建工具强大之处所在,可以借助 Python 灵活的语法和丰富的库,完成 CMake 或者 Makefile 无法做到的事情。例如可以导入 os 标准库,实现对文件和目录的相关操作。 -## 5 Scons 函数在 SConscript 中的经典示例 +## Scons 构建示例 -下面我们将以几个 SConscript 为例讲解 scons 构建工具的使用方法。 +下面我们将以几个 SConscript 为例讲解如果使用 scons 构建。 ### 5.1 构建一个基本的 Group diff --git a/development-tools/build-config-system/figures/buildconfig20.png b/development-tools/build-config-system/figures/buildconfig20.png new file mode 100644 index 0000000000000000000000000000000000000000..f43d60a3b2650052878fc51026d78dc5665f3b79 GIT binary patch literal 14563 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