Skip to main content

LibXR_CppCodeGenerator

LibXR 代码生成工具 / Code generator for LibXR


License GitHub Repo Documentation GitHub Issues CI/CD - Python Package FOSSA Status

LibXR_CppCodeGenerator 由各平台开发工具的工程生成使用 LibXR 的 C++ 代码,以 pip 包 libxr 发布,命令为 libxr。目前支持三个平台:STM32 读取 STM32CubeMX 工程的 .ioc 文件,MSPM0 读取 SysConfig 工程的 .syscfg,HPM 读取 HPM Pinmux Tool 工程的 .hpmpc;三者都 生成外设对象和入口函数 app_main,STM32 的命令另外把 LibXR 接入工程的 CMake 构建。

LibXR_CppCodeGenerator generates C++ code that uses LibXR from the projects of each platform's development tool. It is published as the pip package libxr, with the command libxr. Three platforms are supported: STM32 reads the .ioc file of an STM32CubeMX project, MSPM0 reads the .syscfg of a SysConfig project, and HPM reads the .hpmpc of an HPM Pinmux Tool project; all three generate the peripheral objects and the entry function app_main, and the STM32 commands also add LibXR to the project's CMake build.


🔧 安装 / Installation

需要 Python 3.10 或更高版本。

Requires Python 3.10 or later.

使用 pipx 安装 (Install via pipx)

Windows

python -m pip install --user pipx
python -m pipx ensurepath
python -m pipx install libxr
# 重新打开终端 / Restart your terminal

Linux

sudo apt install pipx
pipx ensurepath
pipx install libxr
# 重新打开终端 / Restart your terminal

使用 pip 安装 (Install via pip)

pip 用于 Windows 或虚拟环境。Debian、Ubuntu 等发行版的系统 Python 由包管理器管理,直接运行 pip install 会报 externally-managed-environment;在这类系统上使用 pipx,或先建立虚拟环境再用 pip 安装。

pip is for Windows or a virtual environment. On Debian, Ubuntu and similar distributions the package manager owns the system Python, and a plain pip install fails with externally-managed-environment; there, use pipx, or create a virtual environment first and install with pip.

Windows

pip install libxr

Linux

sudo apt install python3-venv
python3 -m venv ~/.venvs/libxr
. ~/.venvs/libxr/bin/activate
pip install libxr
# 在激活了虚拟环境的终端中使用 libxr / Use libxr in a terminal with the environment activated

从源码安装 (Install from source)

git clone https://github.com/xrobot-org/LibXR_CppCodeGenerator.git
cd LibXR_CppCodeGenerator
python ./scripts/gen_libxr_version.py
pip install .

scripts/gen_libxr_version.py 记录 LibXR master 当前的提交,libxr stm32 setup 新加入 LibXR 时检出这个 提交。

scripts/gen_libxr_version.py records the current commit of LibXR master, which libxr stm32 setup checks out when it adds LibXR.

以上三种方式只选其一,不要混用。系统中有多份安装时,命令行实际调用的版本可能与预期不同,而不同版本 生成的代码并不一致。当前使用的版本可通过 libxr --version 查看。BSP 所用的版本由 User/libxr_config.yaml 顶层的 generator: 6.0.1 固定:生成器新建这个文件时写入当前的版本,重新 生成时保留这个键;安装的版本应与之一致,例如 pipx install libxr==6.0.1。

Use only one of these methods. With several installations present, the command line may run a different version than expected, and different versions generate different code. libxr --version shows the version in use. The version a BSP uses is pinned by generator: 6.0.1 at the top level of User/libxr_config.yaml: the generator writes the current version when it creates this file, and regeneration keeps the key; install the same version, e.g. pipx install libxr==6.0.1.


📚 基本概念 / Concepts

以一个 STM32F103 的 CubeMX 工程为例:串口 USART1 用作终端,另有 SPI1、I2C1、ADC1、USB、一路 PWM 和 一个标签为 LED 的 GPIO,HAL 时基使用 TIM3,系统为 FreeRTOS。各个概念的对应关系如下:

Take an STM32CubeMX project for an STM32F103: USART1 serves as the terminal, and there are SPI1, I2C1, ADC1, USB, a PWM channel and a GPIO labeled LED; the HAL timebase is TIM3 and the system is FreeRTOS. The concepts correspond as follows:

概念 Concept 在这个例子里 In this example
CubeMX 工程 CubeMX project STM32F103RC.ioc、Core/、Drivers/ 和 CMakeLists.txt(Toolchain / IDE 选择 CMake) STM32F103RC.ioc, Core/, Drivers/ and CMakeLists.txt (Toolchain / IDE set to CMake)
工程 YAML Project YAML .config.yaml,libxr parse 从 .ioc 读出的芯片、引脚、外设、DMA 和 RTOS .config.yaml, the chip, pins, peripherals, DMA and RTOS that libxr parse reads from the .ioc file
入口源文件 Entry source User/app_main.cpp,libxr gen 生成的外设对象和 app_main();User Code 区域中的代码在重新生成时保留 User/app_main.cpp, the peripheral objects and app_main() generated by libxr gen; the code in its User Code regions is kept on regeneration
生成设置 Generation settings User/libxr_config.yaml,缓冲区大小、USB 的 CDC、数据库、终端设备、线程优先级等参数 User/libxr_config.yaml, parameters such as buffer sizes, the CDCs of USB, the database, the terminal device and thread priorities
LibXR 子模块 LibXR submodule Middlewares/Third_Party/LibXR,工程的 gitlink 固定所用的提交 Middlewares/Third_Party/LibXR, pinned to a commit by the project's gitlink
CMake 接入 CMake integration cmake/LibXR.CMake,固定结构,设置块供用户修改,由 CMakeLists.txt include cmake/LibXR.CMake, a fixed structure with a settings block for the user to edit, included by CMakeLists.txt
换行符规则 Line endings .gitattributes,仓库内的文本文件为 LF,签出时按平台转换 .gitattributes, text files are LF in the repository and converted on checkout by platform

🚀 配置工程 / Setting Up a Project

libxr stm32 setup 依次加入 LibXR 子模块、解析 .ioc、生成代码,并接入 CMake。改动工程之前先检查 工程是否有 Core/、一个 .ioc 文件和 CMakeLists.txt,不满足时报错,工程保持原样。-t 指定终端使用的 设备:

libxr stm32 setup adds the LibXR submodule, parses the .ioc file, generates the code and integrates CMake, in that order. Before changing anything it checks that the project has Core/, one .ioc file and CMakeLists.txt, and otherwise stops with an error and leaves the project as it is. -t names the device the terminal uses:

$ libxr stm32 setup -t usart1
[INFO] Default LibXR commit: 4e9670164541b6af6b600a6d544115a9b3e49d98
[INFO] Cloning LibXR from https://github.com/xrobot-org/libxr.git
[INFO] Added the LibXR submodule (https://github.com/xrobot-org/libxr.git).
[INFO] Initializing new LibXR submodule to default commit 4e9670164541b6af6b600a6d544115a9b3e49d98
[INFO] Found .ioc file: .\STM32F103RC.ioc
[INFO] Creating .gitignore file...
[INFO] Creating .gitattributes file...
[INFO] Set terminal_source to usart1 in .\User\libxr_config.yaml
[INFO] Parsing .ioc file...
[INFO] Processing STM32F103RC.ioc...
[INFO] Configuration exported to: .\.config.yaml
[INFO] Generating C++ code...
[INFO] System: FreeRTOS
[INFO] Generated User: wrote app_main.cpp, app_main.h, flash_map.hpp, libxr_config.yaml
[INFO] Generated LibXR.CMake at: cmake\LibXR.CMake
[INFO] LibXR.CMake included in CMakeLists.txt.
[INFO] [Pass] All tasks completed.
[INFO] Next: #include "app_main.h" and call app_main() in the default task StartDefaultTask (Core/Src/main.c), inside USER CODE sections, which CubeMX keeps when it regenerates the code.
[INFO] Build: cmake --preset debug && cmake --build --preset debug

克隆 LibXR 时,libxr 在 GitHub 和镜像中选择响应最快的源。工程中已有的 LibXR 检出保持在原来的提交, 切换版本时使用 --commit。最后两行是接下来的步骤:Core/Src 中还没有源文件调用 app_main() 时, Next 写出调用的位置,FreeRTOS 工程为默认任务,裸机工程为 main();Build 是 CMakePresets.json 中第一个 preset 的构建命令。工程要求和各项参数见 STM32 代码生成。

.gitattributes 写入 * text=auto、*.sh text eol=lf 和 *.bat text eol=crlf:仓库内的文本文件为 LF,签出时按平台转换,所以在 Windows 和 Linux 上用 CubeMX 重新生成,提交的差异里都只有真实的改动。 已有的 .gitattributes 只补上缺少的行。

When LibXR is cloned, libxr picks the fastest of GitHub and the mirrors. A LibXR checkout already in the project stays at its commit; --commit switches it. The last two lines are the next steps: while no source file in Core/Src calls app_main(), Next names where to call it, the default task in a FreeRTOS project and main() in a bare-metal one; Build is the build command of the first preset in CMakePresets.json. Project requirements and all options are described in STM32 code generation.

.gitattributes gets * text=auto, *.sh text eol=lf and *.bat text eol=crlf: text files are LF in the repository and converted on checkout by platform, so regenerating with CubeMX on Windows or on Linux shows only real changes in the commit. An existing .gitattributes only gets the missing lines.


🧩 从 .ioc 到代码 / From .ioc to Code

libxr parse 读出 .ioc 中的外设并打印摘要:

libxr parse reads the peripherals from the .ioc file and prints a summary:

$ libxr parse
[INFO] Processing STM32F103RC.ioc...
[INFO] Configuration exported to: .\.config.yaml

===== [Configuration Summary] =====

MCU: STM32F1 STM32F103RCT6

GPIO (2 pins):
  Outputs: 1
  Inputs: 1
  External Interrupts: 0

Active Peripherals:
  TIM: 1 instance(s)
    TIM2: Channels=CH3
  ADC: 1 instance(s)
    ADC1: Channels=1
  SPI: 1 instance(s)
    SPI1: BaudRate=562.5 KBits/s
  USART: 1 instance(s)
    USART1
  I2C: 1 instance(s)
    I2C1
  USB: 1 instance(s)
    USB

libxr gen 为每个外设生成一个静态对象,CubeMX 中的引脚标签成为对象名。入口源文件按这些部分排列: include 和 extern 声明只列出用到的驱动头文件和 HAL 句柄,DMA 缓冲区每个一行,app_main() 中每组 外设前有一行说明注释。串口为开启了 DMA 的方向分配缓冲区,例子中的 USART1 两个方向都开启了 DMA。 SPI 总是有发送和接收缓冲区,两个方向都开启 DMA 时才使用 DMA;其他情况下最后一个参数(DMA 切换阈值) 为 UINT32_MAX,传输总是走轮询路径。例子中的 SPI1 没有 DMA:

libxr gen generates one static object per peripheral, and the pin labels set in CubeMX become object names. The entry source is arranged in these parts: the includes and the extern declarations list only the driver headers and HAL handles that are used, each DMA buffer takes one line, and every group of peripherals in app_main() has a comment line. UARTs get buffers for the directions with DMA; in the example USART1 has DMA in both directions. An SPI always has transmit and receive buffers and uses DMA only with DMA in both directions; otherwise the last argument (the DMA threshold) is UINT32_MAX and transfers always take the polling path. SPI1 in the example has no DMA:

// User/app_main.cpp(节选 / excerpt)
// DMA buffers (STM32F103RC: no D-cache)
alignas(4) static uint16_t adc1_buf[16];
alignas(4) static uint8_t i2c1_buf[32];
alignas(4) static uint8_t spi1_rx_buf[32];
alignas(4) static uint8_t spi1_tx_buf[32];
alignas(4) static uint8_t usart1_rx_buf[128];
alignas(4) static uint8_t usart1_tx_buf[128];
// ...

extern "C" void app_main(void)
{
  /* User Code Begin 2 */
  /* User Code End 2 */

  // Timebase and platform
  static STM32TimerTimebase timebase(&htim3);
  PlatformInit(static_cast<uint32_t>(Thread::Priority::MEDIUM), 1024);
  static STM32PowerManager power_manager;

  // GPIO
  static STM32GPIO PA8(GPIOA, GPIO_PIN_8);
  static STM32GPIO LED(LED_GPIO_Port, LED_Pin);

  // ADC
  static STM32ADC adc1(&hadc1, adc1_buf, {ADC_CHANNEL_0}, 3.3);
  // ...

  // PWM
  static STM32PWM pwm_tim2_ch3(&htim2, TIM_CHANNEL_3, false);

  // SPI, UART, I2C
  static STM32SPI spi1(&hspi1, spi1_rx_buf, spi1_tx_buf, UINT32_MAX);
  static STM32UART usart1(&huart1, usart1_rx_buf, usart1_tx_buf, 5);
  static STM32I2C i2c1(&hi2c1, i2c1_buf, 3);

  // USB FS: 1 CDC
  // ...

  /* User Code Begin 3 */
  while (true)
  {
    Thread::Sleep(UINT32_MAX);
  }
  /* User Code End 3 */
}

生成的部分已按 LibXR 的 .clang-format(Google 风格、列宽 90、Allman 大括号)排版,clang-format 不会 改动它们。缓冲区的对齐取决于芯片:没有数据 cache 的芯片(F1、F4 等)为 alignas(4);有数据 cache 的 F7、H7 和 N6 按 32 字节的 cache 行对齐,数组大小向上取整到整行,传给驱动的大小仍是配置的值。 libxr_config.yaml 给出 dma_section 时,缓冲区放在这个段:

The generated parts are laid out by the .clang-format of LibXR (Google style, column limit 90, Allman braces), and clang-format leaves them as they are. The alignment of a buffer depends on the chip: a chip without a data cache (F1, F4 and others) gets alignas(4); F7, H7 and N6, which have one, align to the 32-byte cache line and round the array up to a whole line, while the size a driver is told stays the configured one. With dma_section in libxr_config.yaml, the buffers go into that section:

// DMA buffers (STM32H723VG: D-cache, 32-byte lines)
alignas(32) static uint8_t usart1_rx_buf[128] __attribute__((section(".axi_ram")));

/* User Code Begin N */ 与 /* User Code End N */ 之间的代码在重新生成时保留,生成结果没有变化的文件 保持原样。区域中的手写代码用到驱动类(如 STM32Flash)、FLASH_REGIONS 或工程的 HAL 句柄(如 htim5)时,生成的文件保留对应的 include 和 extern 声明:

The code between /* User Code Begin N */ and /* User Code End N */ is kept on regeneration, and files whose content does not change are left as they are. When hand-written code in a region uses a driver class such as STM32Flash, FLASH_REGIONS or a HAL handle of the project such as htim5, the generated file keeps the include and the extern declaration for it:

$ libxr gen -i .config.yaml -o User/app_main.cpp
[INFO] System: FreeRTOS
[INFO] Generated User: unchanged app_main.cpp, app_main.h, flash_map.hpp, libxr_config.yaml

各外设的生成规则见 STM32 代码生成 下的各个页面。

The generation rules of each peripheral are described in the pages under STM32 code generation.


⚙️ 生成设置 / Generation Settings

User/libxr_config.yaml 在第一次生成时按默认值创建,记录各外设的缓冲区大小、终端设备、软件定时器和 终端的参数等。修改其中的值后,重新运行 libxr gen 即按新值生成,文件中的修改和注释在重新生成时保留:

User/libxr_config.yaml is created with the defaults on the first generation and records the buffer sizes of each peripheral, the terminal device, and the parameters of the software timer and the terminal, among others. After a value is changed, running libxr gen again generates with the new value; the changes and comments in the file are kept on regeneration:

# User/libxr_config.yaml(节选 / excerpt)
generator: 6.0.1
terminal_source: usart1
software_timer:
  priority: 2
  stack_depth: 1024
# ...
USART:
  usart1:
    tx_buffer_size: 128
    rx_buffer_size: 128
    dma_section: ''
    tx_queue_size: 5
# ...
USB:
  usb_fs:
    enable: true
    ep0_packet_size: 8
    cdc:
    - {tx_fifo_size: 128, rx_fifo_size: 128, queue_size: 3}
# ...
database:
  enable: false
  block_size: auto

software_timer.priority 以及终端和看门狗的 thread_priority 取 0 到 4 或等级名,0 到 4 依次为 IDLE、LOW、MEDIUM、HIGH、REALTIME。LibXR 按 RTOS 的优先级数把等级换算为 RTOS 优先级,步长 LIBXR_PRIORITY_STEP 为(优先级数 - 1)/ 5:FreeRTOS 的第 n 级为 n 倍步长,configMAX_PRIORITIES 为 56 时 MEDIUM 是 22;ThreadX 数值越小优先级越高,TX_MAX_PRIORITIES 为 32 时 MEDIUM 是 12。 libxr 5.x 把这个数原样作为 RTOS 优先级,步长为 1 的 FreeRTOS 工程两者相同。

software_timer.priority and the thread_priority of the terminal and the watchdog take 0 to 4 or a level name; 0 to 4 are IDLE, LOW, MEDIUM, HIGH and REALTIME in that order. LibXR converts the levels to RTOS priorities by the RTOS priority count, with the step LIBXR_PRIORITY_STEP being (priority count - 1) / 5: level n on FreeRTOS is n steps, so MEDIUM is 22 with configMAX_PRIORITIES 56; on ThreadX lower numbers are higher priorities, and MEDIUM is 12 with TX_MAX_PRIORITIES 32. libxr 5.x passed the number to the RTOS as it was, which gives the same priority on a FreeRTOS project with a step of 1.

CubeMX 中处于设备模式的 USB 生成 USB 设备和 CDC 串口 usb_fs_cdc。USB.usb_fs.enable 为 false 时 不生成;工程启用了 CubeMX 的 USB 中间件(如 USB_DEVICE)时,enable 的默认值为 false。设备对象 以 USB 实例命名,例如 USB(FSDEV)为 usb_fs,OTG 为 usb_otg_fs 和 usb_otg_hs。libxr 5.x 按速度 把 OTG 的设备对象命名为 usb_fs 和 usb_hs,CDC 串口的名字没有变化。

A USB in device mode in CubeMX produces a USB device and the CDC serial port usb_fs_cdc. With USB.usb_fs.enable set to false it is not generated; when the project enables a CubeMX USB middleware such as USB_DEVICE, enable defaults to false. The device object is named after the USB instance, such as usb_fs for USB (FSDEV) and usb_otg_fs and usb_otg_hs for OTG. libxr 5.x named the OTG device objects usb_fs and usb_hs after their speed; the names of the CDC serial ports are unchanged.

cdc 每路 CDC 写一项,一个 USB 设备可以有几路 CDC。第 N 路(N 从 1 起)生成 usb_otg_hs_cdc、 usb_otg_hs_cdc2 这样的 USB::CDCUart 对象,按顺序分配端点:数据 IN 端点为 EP(2N-1),通知端点为 EP(2N),OTG 的数据 OUT 端点为 EP(N)。端点缓冲区随路数增减,terminal_source 可以指向任意一路,例如 usb_otg_hs_cdc2。cdc_tx_fifo_size、cdc_rx_fifo_size 和 cdc_queue_size 转换为 cdc 的一项, 写回时使用 cdc 的形式:

cdc has one item per CDC, and a USB device can have several. The N-th CDC (N from 1) produces a USB::CDCUart object such as usb_otg_hs_cdc or usb_otg_hs_cdc2 and takes the endpoints in order: the data IN endpoint is EP(2N-1), the notification endpoint EP(2N), and on OTG the data OUT endpoint EP(N). The endpoint buffers follow the number of CDCs, and terminal_source can name any of them, such as usb_otg_hs_cdc2. cdc_tx_fifo_size, cdc_rx_fifo_size and cdc_queue_size convert to one item of cdc and are written back in the form of cdc:

USB:
  usb_otg_hs:
    enable: true
    cdc:
    - {tx_fifo_size: 128, rx_fifo_size: 128, queue_size: 3}
    - {tx_fifo_size: 128, rx_fifo_size: 128, queue_size: 3}

每一项可以加上 interface,作为这路 CDC 控制接口和数据接口的名字。几路 CDC 的 VID:PID 相同,主机按接口名 区分它们;没有 interface 的一路使用 LibXR 的默认名 XRUSB CDC Control 和 XRUSB CDC Data:

Each item can add interface, the name of the control and data interfaces of that CDC. The CDCs share VID:PID, and the host tells them apart by the interface name; a CDC without interface keeps the LibXR default names XRUSB CDC Control and XRUSB CDC Data:

USB:
  usb_otg_hs:
    enable: true
    cdc:
    - {tx_fifo_size: 128, rx_fifo_size: 128, queue_size: 3, interface: Console}
    - {tx_fifo_size: 128, rx_fifo_size: 128, queue_size: 3, interface: Telemetry}

database.enable 为 true 时,app_main() 生成 STM32Flash flash(FLASH_REGIONS, FLASH_REGION_NUMBER) 和 DatabaseRaw<N> database(flash),数据库以 database 注册;FLASH_REGIONS 来自 User/flash_map.hpp,数据库使用 Flash 末尾的两个扇区。模板参数 N 是 Flash 的最小写入单元,单位为 字节,由 block_size 决定:写成正整数时使用这个数,例如 block_size: 32 生成 DatabaseRaw<32>; 默认值 auto 生成 STM32Flash::MIN_WRITE_SIZE,即 LibXR 按芯片的 HAL 得出的值:

With database.enable set to true, app_main() generates STM32Flash flash(FLASH_REGIONS, FLASH_REGION_NUMBER) and DatabaseRaw<N> database(flash), and the database is registered as database; FLASH_REGIONS comes from User/flash_map.hpp, and the database uses the last two sectors of the Flash. The template argument N is the minimum write unit of the Flash in bytes and follows block_size: a positive integer is used as it is, e.g. block_size: 32 generates DatabaseRaw<32>, and the default auto generates STM32Flash::MIN_WRITE_SIZE, the value LibXR derives from the HAL of the chip:

  // Flash and database
  static STM32Flash flash(FLASH_REGIONS, FLASH_REGION_NUMBER);
  static DatabaseRaw<STM32Flash::MIN_WRITE_SIZE> database(flash);

数值在生成时检查,不合要求时生成停止,报错写出文件、键和值:

Values are checked during generation; an invalid one stops generation with an error naming the file, the key and the value:

$ libxr gen -i .config.yaml -o User/app_main.cpp
[INFO] System: FreeRTOS
[ERROR] Generation failed: User\libxr_config.yaml: USART.usart1.tx_queue_size 'five' is not a positive integer

🤖 XRobot 集成 / XRobot Integration

--xrobot 在入口源文件中以 XR_REGISTER 注册生成的对象,并在 User Code 区域之后调用 XROBOT_MAIN()。XRobot 的模块按这些名字使用外设。之后的 libxr gen 和 libxr stm32 setup 沿用入口源文件现在的选择,--no-xrobot 取消注册:

With --xrobot, the entry source registers the generated objects with XR_REGISTER and calls XROBOT_MAIN() after the User Code regions. The Modules of XRobot use the peripherals by these names. Later runs of libxr gen and libxr stm32 setup keep the entry source's current choice, and --no-xrobot removes the registrations:

$ libxr gen -i .config.yaml -o User/app_main.cpp --xrobot
[INFO] System: FreeRTOS
[INFO] Generated User: wrote app_main.cpp; unchanged app_main.h, flash_map.hpp, libxr_config.yaml

XR_REGISTER 按种类分组,每组之间空一行;已注册的对象不再写 UNUSED(...):

XR_REGISTER lines are grouped by kind with a blank line between groups, and registered objects need no UNUSED(...):

// User/app_main.cpp(节选 / excerpt)
  // Hardware registration
  XR_REGISTER(power_manager, LibXR::PowerManager);

  XR_REGISTER(PA8, LibXR::GPIO);
  XR_REGISTER(LED, LibXR::GPIO);

  XR_REGISTER(adc1_adc_channel_0, LibXR::ADC);

  XR_REGISTER(pwm_tim2_ch3, LibXR::PWM);

  XR_REGISTER(spi1, LibXR::SPI);

  XR_REGISTER(usart1, LibXR::UART);
  XR_REGISTER(usb_fs_cdc, LibXR::UART);

  XR_REGISTER(i2c1, LibXR::I2C);
  // ...

  /* User Code Begin 3 */
  /* User Code End 3 */
  XROBOT_MAIN();
}

已有入口源文件的 User Code 3 仍是不带 --xrobot 时生成的默认循环时,加上 --xrobot 重新生成会清空 这个循环,使其后的 XROBOT_MAIN() 能够执行;User Code 3 的其他内容保持不变。

When User Code 3 of an existing entry source still holds the default loop generated without --xrobot, regenerating with --xrobot empties the loop, so that the XROBOT_MAIN() after it runs; any other content of User Code 3 is kept.

libxr stm32 cmake 和 libxr stm32 setup 按入口源文件的选择在 cmake/LibXR.CMake 的设置块中加入或 删除 XROBOT_MODULES_DIR,XRobot 的模块随之参与构建:

libxr stm32 cmake and libxr stm32 setup add or remove XROBOT_MODULES_DIR in the settings block of cmake/LibXR.CMake according to the entry source's choice, so that the XRobot Modules are built with the project:

$ libxr stm32 cmake
[INFO] LibXR.CMake: added set(XROBOT_MODULES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Modules"), as User/app_main.cpp uses XRobot
[INFO] Updated existing LibXR.CMake for system: FreeRTOS
[INFO] LibXR.CMake already included in CMakeLists.txt.

使用 XRobot 的工程,libxr stm32 setup、libxr mspm0 setup 和 libxr hpm setup 在最后给出 XRobot 的 下一步:BSP 根目录还没有 Modules/modules.yaml 时,依次列出 XRobot 的设置命令 xrobot init、 xrobot module add、xrobot setup 和 xrobot instance add;已经有了时,提醒运行 xrobot gen, 因为 User/xrobot_main.hpp 由 XRobot 生成,libxr 的 setup 不更新它。

For a project that uses XRobot, libxr stm32 setup, libxr mspm0 setup and libxr hpm setup end with the next XRobot step: while the BSP root has no Modules/modules.yaml yet, they list the XRobot setup commands in order, xrobot init, xrobot module add, xrobot setup and xrobot instance add; once it exists, they remind to run xrobot gen, since XRobot generates User/xrobot_main.hpp and the libxr setup does not update it.

详见 与 XRobot 集成。

See XRobot integration.


🔨 CMake 与工具链 / CMake and Toolchains

libxr stm32 cmake 整体生成 cmake/LibXR.CMake,并在 CMakeLists.txt 中 include 它;libxr stm32 setup 已包含这一步。文件的结构固定,设置块在最前,其后依次是 LibXR、Application、库的优化设置和固件镜像:

libxr stm32 cmake generates cmake/LibXR.CMake as a whole and includes it from CMakeLists.txt; libxr stm32 setup already does this. The structure of the file is fixed: the settings block comes first, followed by LibXR, Application, the optimization of the libraries and the firmware images:

# Generated by `libxr stm32 setup`; edit the values in the "Project settings" block only.

# ---- Project settings --------------------------------------------------------
set(LIBXR_SYSTEM FreeRTOS)
set(LIBXR_DRIVER st)
set(XROBOT_MODULES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Modules")
# User sources of the application; "" when CMakeLists.txt adds them itself.
set(LIBXR_USER_SOURCES_GLOB "${CMAKE_CURRENT_SOURCE_DIR}/User/*.cpp")
# Optimization level of the application in Debug builds and of everything in Release builds;
# "" keeps the level of the toolchain file.
set(LIBXR_OPT_DEBUG "-Og")
set(LIBXR_OPT_RELEASE "")

# ---- LibXR -------------------------------------------------------------------
# ...

重写时设置块中用户改过的值和增加的内容保留,LIBXR_SYSTEM 取 Core/Inc 中的 FreeRTOSConfig.h 或 app_threadx.h 所决定的系统,XROBOT_MODULES_DIR 与入口源文件的选择一致,其余 各块重新生成。已有的 LibXR.CMake 按这个结构重写:设置的值保留,LIBXR_OPT_DEBUG 和 LIBXR_OPT_RELEASE 取已用的优化级别(工具链文件中的 CMAKE_CXX_FLAGS_DEBUG 和 CMAKE_CXX_FLAGS_RELEASE,两个工具链文件不同时留空),重新生成的语句之外的内容保留在 Kept from the earlier LibXR.CMake 块中;旧文件 Debug 块中用户改过的库优化选项也原样放在这里, 包在同样的 if(CMAKE_BUILD_TYPE STREQUAL "Debug") 中,排在库的 -O2 之后,因此仍然生效。 LIBXR_OPT_DEBUG 是应用的 Debug 优化级别,LIBXR_OPT_RELEASE 是应用、xr 和 CubeMX 生成的库在 Release 构建中的优化级别;Debug 构建中 xr 和 CubeMX 生成的全部库目标使用 -O2(libxr 5.x 只包括 FreeRTOS、STM32_Drivers 和 USB_Device_Library,ThreadX 等其他库目标使用工具链的 Debug 级别)。 目标的编译选项排在工具链的 CMAKE_<LANG>_FLAGS_<CONFIG> 之后,所以最后一个 -O 就是这里设置的级别。 值为 "" 时沿用工具链文件中的级别,CubeMX 写出的 GCC 为 -Os、ST Arm Clang 为 -Oz;新工程的 LIBXR_OPT_RELEASE 为 ""。

On a rewrite the values the user changed in the settings block, and what the user added there, stay; LIBXR_SYSTEM takes the system that FreeRTOSConfig.h or app_threadx.h in Core/Inc decides, XROBOT_MODULES_DIR agrees with the entry source's choice, and the other blocks are generated again. An existing LibXR.CMake is rewritten in this structure: the values of the settings stay, LIBXR_OPT_DEBUG and LIBXR_OPT_RELEASE take the optimization levels in use (the CMAKE_CXX_FLAGS_DEBUG and CMAKE_CXX_FLAGS_RELEASE of the toolchain files, empty when the two toolchain files differ), and what is not among the regenerated statements stays in the Kept from the earlier LibXR.CMake block; the library optimization options the user changed in the Debug block of the old file go there as written too, inside the same if(CMAKE_BUILD_TYPE STREQUAL "Debug") and after the -O2 of the libraries, so they still apply. LIBXR_OPT_DEBUG is the Debug optimization level of the application, and LIBXR_OPT_RELEASE the Release level of the application, xr and the libraries CubeMX generates; in Debug builds xr and every library target CubeMX generates use -O2 (libxr 5.x covered only FreeRTOS, STM32_Drivers and USB_Device_Library, and other library targets such as ThreadX used the Debug level of the toolchain). Target compile options come after the toolchain's CMAKE_<LANG>_FLAGS_<CONFIG>, so the last -O is the level set here. With "" the level of the toolchain file applies, -Os for GCC and -Oz for ST Arm Clang as CubeMX writes them; a new project has LIBXR_OPT_RELEASE set to "".

应用每次链接之后,固件镜像块用工具链文件中的 CMAKE_OBJCOPY 由 ELF 生成 <工程名>.hex(Intel HEX) 和 <工程名>.bin(二进制镜像),三个文件位于同一目录,用 CubeMX 的 preset 构建时为 build/<preset>/。

After each link of the application, the firmware image block makes <project>.hex (Intel HEX) and <project>.bin (binary image) from the ELF with the CMAKE_OBJCOPY of the toolchain file; the three files are in the same directory, build/<preset>/ when built with a CubeMX preset.

cmake/starm-clang.cmake 和 cmake/gcc-arm-none-eabi.cmake 保持 CubeMX 写出的内容。libxr stm32 toolchain 切换 CMakePresets.json 中默认的工具链,在 GCC 与 ST Arm Clang 之间切换时删除以前的构建目录,下次 构建重新配置;ST Arm Clang 还可以选择标准库,这时只改写 CubeMX 在 starm-clang.cmake 中写出的 set(STARM_TOOLCHAIN_CONFIG ...) 一行:

cmake/starm-clang.cmake and cmake/gcc-arm-none-eabi.cmake keep what CubeMX wrote. libxr stm32 toolchain switches the default toolchain in CMakePresets.json; switching between GCC and ST Arm Clang removes the old build directories, and the next build configures again. ST Arm Clang can also select its standard library, which rewrites only the set(STARM_TOOLCHAIN_CONFIG ...) line that CubeMX wrote in starm-clang.cmake:

$ libxr stm32 toolchain gcc
[INFO] Switched the default preset to cmake/gcc-arm-none-eabi.cmake
[INFO] Removed build, configured with the previous toolchain
[INFO] Done.

$ libxr stm32 toolchain clang --newlib
[INFO] Switched the default preset to cmake/starm-clang.cmake
[INFO] Set STARM_TOOLCHAIN_CONFIG to "STARM_NEWLIB" in cmake\starm-clang.cmake
[INFO] Done.

💾 Flash 布局 / Flash Layout

libxr stm32 flash-info 按型号推算 Flash 扇区表,libxr gen 据此生成 User/flash_map.hpp:

libxr stm32 flash-info derives the flash sector table of a model, from which libxr gen generates User/flash_map.hpp:

$ libxr stm32 flash-info STM32F103RCT6
model: STM32F103RCT6
flash_base: '0x08000000'
flash_size_kb: 256
sectors:
- index: 0
  address: '0x08000000'
  size_kb: 2.0
- index: 1
  address: '0x08000800'
  size_kb: 2.0
# ...
- index: 127
  address: '0x0803F800'
  size_kb: 2.0

🧩 从 .syscfg 到代码 / From .syscfg to Code

libxr mspm0 setup 面向 SysConfig 工程:根目录有一份 .syscfg 文件,main.c 调用 SysConfig 生成的 SYSCFG_DL_init() 后进入 app_main()。命令写 .gitignore(已有的不动),解析工程到 .config.yaml, 生成 User/app_main.cpp、app_main.h 和 libxr_config.yaml。设置了环境变量 SYSCONFIG_TOOL 和 MSPM0_SDK_INSTALL_DIR 时,解析运行一次 SysConfig;没有设置时复用构建目录中比 .syscfg 新的 SysConfig 输出。下例设置了这两个变量:

libxr mspm0 setup works on a SysConfig project: one .syscfg file at the root, and a main.c that calls the SysConfig-generated SYSCFG_DL_init() before entering app_main(). The command writes .gitignore (an existing one stays), parses the project into .config.yaml, and generates User/app_main.cpp, app_main.h and libxr_config.yaml. With the environment variables SYSCONFIG_TOOL and MSPM0_SDK_INSTALL_DIR set, parsing runs SysConfig once; without them it reuses a SysConfig output newer than the .syscfg in the build directories. The example has both variables set:

$ libxr mspm0 setup
[INFO] Processing mspm0g3507_minidb48.syscfg...
[INFO] Running SysConfig on mspm0g3507_minidb48.syscfg
[INFO] Configuration exported to: .\.config.yaml
[INFO] System: bare metal
[INFO] .\User\libxr_config.yaml does not exist; creating it with the default settings
[INFO] terminal_source is not set; using uart0
[INFO] Generated User: wrote app_main.cpp, app_main.h, libxr_config.yaml
[INFO] Next: run `xrobot gen` to bring User/xrobot_main.hpp up to date; libxr setup does not update it

===== [Configuration Summary] =====

MCU: MSPM0 MSPM0G3507

GPIO (4 pins):
  LED1: PB8, OUTPUT
  LED2: PA16, OUTPUT
  KEY1: PB24, INPUT, FALL interrupt
  KEY2: PB20, INPUT, FALL interrupt

Active Peripherals:
  UART: 2 instance(s)
    UART_0
    UART_1
  I2C: 2 instance(s)
    I2C_0
    I2C_1
  SPI: 1 instance(s)
    SPI_1
  PWM: 1 instance(s)
    PWM_TIMA1
  Other: 5 instance(s)
    ADC12_0
    ADC12_1
    DAC0
    MCAN_0
    QEI_TIMG8

缓冲区大小等设置在 libxr_config.yaml 中。GPIO 以引脚标签命名(LED1),UART、I2C、SPI 以小写的外设名 命名(uart0、i2c0),PWM 为 pwm_tima1_c0;terminal_source 指定终端使用的串口,未设置时用第一个 UART。 生成总是包含 static MSPM0PowerManager power_manager;,使用 XRobot 时把它登记为 PowerManager。 流程、设置与约束的完整说明见 MSPM0 代码生成。

The settings such as the buffer sizes live in libxr_config.yaml. GPIO objects are named after the pin labels (LED1), UART, I2C and SPI after their lowercase peripheral names (uart0, i2c0), and a PWM is pwm_tima1_c0; terminal_source names the UART the terminal uses, the first one when it is not set. The generation always emits static MSPM0PowerManager power_manager;, registered as a PowerManager with XRobot. The flow, the settings and their constraints are described in MSPM0 code generation.


🧩 从 .hpmpc 到代码 / From .hpmpc to Code

libxr hpm setup 面向 HPM SDK 工程:根目录有 app.yaml,boards/<board>/ 下有唯一的 .hpmpc 文件。 步骤与 MSPM0 相同,输出也是同样的三个文件;引脚从 .hpmpc 中 selectPins 的信号和 main.c 在预处理 条件之外调用的引脚函数读出,main 完全没有调用引脚函数时用 boards/<board>/pinmux.c 的 init_bsp_pins()。 生成的对象按平台命名:GPIO 为 pa10 这样的引脚名,其余为小写的实例(i2c3);GPTMR 输出为 pwm_gptmr0_ch1,在 SoC 没有 PWM 外设时生成(HPM5301 生成,HPM5361 归入 Other):

libxr hpm setup works on an HPM SDK project: app.yaml at the root and the single .hpmpc file of boards/<board>/. The steps are the ones of MSPM0, and the output is the same three files; the pins are read from the signals selectPins selects in the .hpmpc and from the pinmux functions main.c calls outside preprocessor conditions, falling back to the init_bsp_pins() of boards/<board>/pinmux.c when main calls no pinmux function at all. The generated objects are named after the platform: GPIO takes the pin name (pa10) and the others the lowercase instance (i2c3), and a GPTMR output becomes pwm_gptmr0_ch1, generated when the SoC has no PWM peripheral (HPM5301 generates it, on HPM5361 it is listed under Other):

$ libxr hpm setup
[INFO] Configuration exported to: .\.config.yaml
[INFO] System: bare metal
[INFO] .\User\libxr_config.yaml does not exist; creating it with the default settings
[INFO] Generated User: wrote app_main.cpp, app_main.h, libxr_config.yaml
[INFO] Next: run `xrobot gen` to bring User/xrobot_main.hpp up to date; libxr setup does not update it

===== [Configuration Summary] =====

SoC: HPM5301 (QFN48)

GPIO (2 pins):
  pa10: PA10
  pa3: PA03

Active Peripherals:
  I2C: 1 instance(s)
    I2C3
  PWM: 1 instance(s)
    GPTMR0
  Other: 7 instance(s)
    UART0
    UART3
    SPI1
    ADC0
    ACMP
    USBPHY
    USB0

支持 HPM5301(QFN48)和 HPM5361(LQFP100、LQFP64、QFN48)。UART、SPI 等外设目前只识别,生成时列入 Other。生成总是包含 static HPMPowerManager power_manager;,使用 XRobot 时把它登记为 PowerManager。流程、命名与设置的完整说明见 HPM 代码生成。

HPM5301 (QFN48) and HPM5361 (LQFP100, LQFP64, QFN48) are supported. Peripherals such as UART and SPI are recognized for now and listed under Other in the generation. The generation always emits static HPMPowerManager power_manager;, registered as a PowerManager with XRobot. The flow, the naming and the settings are described in HPM code generation.


📌 引脚布局 / Pin Layout

libxr pins 按型号给出芯片的封装和引脚布局:每个引脚的封装位置、名称、类型和全部可选信号。型号的前缀决定平台,目前支持 STM32、MSPM0 和 HPM;HPM 的型号就是 SoC 名(HPM5301),有多个封装的 SoC(HPM5361)用 --package 选择(LQFP100、LQFP64、QFN48)。输出为 YAML,--format json 输出 JSON。

libxr pins prints the package and pin layout of a chip model: for each pin its position on the package, name, type and all selectable signals. The prefix of the model chooses the platform; STM32, MSPM0 and HPM are supported. The model of an HPM is the SoC name (HPM5301), and a SoC with several packages (HPM5361) selects one with --package (LQFP100, LQFP64, QFN48). The output is YAML, or JSON with --format json.

$ libxr pins MSPM0G3507SPMR
model: MSPM0G3507SPMR
platform: mspm0
part: MSPM0G3507
package: LQFP-64(PM)
pin_count: 64
# ...
- position: '33'
  name: PA0
  type: Default
  signals:
  - PA0
  - UART0.TX
  - I2C0.SDA
  # ...
  iomux_pincm: 1
  modes:
    PA0: 1
    UART0.TX: 2
    I2C0.SDA: 3
    # ...
  • libxr pins -d <工程目录> 叠加工程已选的信号:STM32 读 CubeMX 的 .ioc,MSPM0 读根目录的 .syscfg(型号取自工程,封装取自 SysConfig 的 --package 或 --board 对应的 LaunchPad),HPM 读 boards/ 下的 .hpmpc 和 main.c 在预处理条件之外调用的引脚函数(封装由工程解析得到,也可用 --package 指定)。输出多一个 project 段:assignments 是每个引脚选了什么(信号、外设、功能、GPIO 标签和是否在器件数据中匹配),peripherals 是每个外设用到的引脚和它在 libxr_config.yaml 中的设置条目(config 是列表,每项有段、键、文件中是否已存在和当前参数);文件默认为 User/libxr_config.yaml,可用 -c 指定。HPM 的 GPIO 是整段改名:config 一项的键为 null,params 是段内引脚名到新名的映射。

  • STM32 的封装由型号决定(STM32H723VGT6 为 LQFP100);MSPM0 的封装取自型号后缀中的代码(MSPM0G3507SPMR 的 PM),型号中没有时用 --package 给出(LQFP-64、PM 或 LQFP-64(PM));HPM 的型号是 SoC 名,只有一种封装的 SoC(HPM5301)不必给出封装,-d 时封装取自 .hpmpc。

  • pin_count 是封装上的位置数。一个位置可以有多个条目:STM32G0 的 PA9 和 PA11 可以互换,共用一个位置。

  • peripherals 列出从信号名识别出的全部外设和每个功能可选的引脚(USART1 的 TX 可以接 PA9、PB6、PB14)。识别只看信号名,ETH、FMC、OctoSPI 这些 LibXR 没有对应抽象的外设也会列出。普通 GPIO 按端口列出(GPIOA 的 P9 是 PA9);STM32 的外部中断列为 EXTI,LINE9 可以来自任一端口的第 9 脚,STM32 的引脚另有 gpio_modes(Input、Output、Analog、EXTI 等);有输出通道的定时器带 capabilities: [pwm]。TI 的器件数据没有中断信息,所以 MSPM0 不列 EXTI。

  • MSPM0 的引脚还有 iomux_pincm 和每个信号的模式号 modes。

  • MSPM0 外设的设置取自 .syscfg(SysConfig 的配置脚本):每个已选外设的 sysconfig 有它的模块、名字(UART_0)和参数(targetBaudRate、enabledInterrupts 等),project.sysconfig_file 是读取的文件。只读,修改在 SysConfig 里进行;表达式原样保留为字符串,引脚的指定和求解器内部的项不收。

  • 数据来自厂商:STM32 来自 ST 的 STM32_open_pin_data(BSD-3-Clause),MSPM0 来自 TI SysConfig 的器件数据(TI 有限许可,只可用于 TI 器件),HPM 来自 HPM SDK 的 hpm_iomux.h、hpm_soc_ip.h(BSD-3-Clause)和 HPM5300 数据手册的引脚表。数据文件和各份许可证文本在 src/libxr/pin_data/,随包分发;用 scripts/build_pin_data.py 重新生成。 MSPM0 的 .syscfg 里可能只写了 --board(LaunchPad),封装由 MSPM0 SDK 的板子定义得到(mspm0_boards.json,BSD-3-Clause,许可证文本为 LICENSE-TI-BOARDS.txt)。

  • libxr pins -d <project directory> overlays the signals a project has selected: the CubeMX .ioc for an STM32, the .syscfg at the root for an MSPM0 (the model comes from the project, and the package from SysConfig's --package or the LaunchPad its --board names), and the .hpmpc under boards/ plus the pinmux functions main.c calls outside preprocessor conditions for an HPM (the package comes from the project, or from --package). The output gets a project section: assignments is what each pin selected (signal, peripheral, function, GPIO label and whether it matched the device data), and peripherals the pins each peripheral uses and its entries in libxr_config.yaml (config is a list whose items carry the section, the key, whether the file already has it and the current parameters); the file is User/libxr_config.yaml by default or the one given with -c. The GPIO rename of an HPM is one whole section: the config item has the key null, and params maps the pin names of the section to their new names.

  • The package of an STM32 is part of the model (STM32H723VGT6 is LQFP100); that of an MSPM0 comes from the code in the model suffix (PM of MSPM0G3507SPMR), or from --package when the model has none (LQFP-64, PM or LQFP-64(PM)); the model of an HPM is the SoC name, a SoC with one package (HPM5301) needs no package, and with -d the package comes from the .hpmpc.

  • pin_count is the number of positions on the package. A position can have several entries: PA9 and PA11 of an STM32G0 can be swapped and share one position.

  • peripherals lists every peripheral recognized from the signal names, with the pins that can carry each function (TX of USART1 can use PA9, PB6 or PB14). Recognition looks at the signal names only, so peripherals LibXR has no abstraction for, such as ETH, FMC and OctoSPI, are listed too. Plain GPIO is listed by port (P9 of GPIOA is PA9); the external interrupts of an STM32 are listed as EXTI, where LINE9 can come from pin 9 of any port, and an STM32 pin also has gpio_modes (Input, Output, Analog, EXTI, ...); a timer with output channels carries capabilities: [pwm]. TI's device data has no interrupt information, so an MSPM0 lists no EXTI.

  • An MSPM0 pin also has iomux_pincm and modes, the mode of each signal.

  • The settings of an MSPM0 peripheral come from the .syscfg, the configuration script of SysConfig: each selected peripheral has a sysconfig with its module, its name (UART_0) and its parameters (targetBaudRate, enabledInterrupts, ...), and project.sysconfig_file is the file read. They are read-only, edited in SysConfig; an expression is kept as written, as a string, and pin assignments and the solver's own items are left out.

  • The data comes from the vendors: STM32 from ST's STM32_open_pin_data (BSD-3-Clause), MSPM0 from the device data of TI SysConfig (TI limited license, for TI devices only), and HPM from the hpm_iomux.h and hpm_soc_ip.h of the HPM SDK (BSD-3-Clause) and the pin tables of the HPM5300 datasheet. The data files and the license texts are in src/libxr/pin_data/ and are distributed with the package; scripts/build_pin_data.py rebuilds them. A .syscfg of an MSPM0 may name only a --board (a LaunchPad); the package then comes from the board definitions of the MSPM0 SDK (mspm0_boards.json, BSD-3-Clause, license text in LICENSE-TI-BOARDS.txt).


🚀 命令一览 / Commands

parse 和 gen 按工程所属的平台选择解析器和生成器,只属于某个平台的命令放在平台名之下。

parse and gen choose the parser and the generator by the project's platform; commands that belong to one platform sit under its name.

命令 Command 说明 Description
libxr parse 解析工程,写出工程 YAML Parse a project into the project YAML
libxr gen 由工程 YAML 生成入口源文件 Generate the entry source from the project YAML
libxr pins 打印某个型号的封装和引脚布局 Print the package and pin layout of a model
libxr stm32 setup 为 CubeMX 工程加入 LibXR,生成代码并接入 CMake Add LibXR to a CubeMX project, generate the code and integrate CMake
libxr mspm0 setup 为 SysConfig 工程生成 LibXR 代码 Generate LibXR code for a SysConfig project
libxr hpm setup 为 HPM 工程生成 LibXR 代码 Generate LibXR code for an HPM project
libxr stm32 cubemx-gen 以脚本模式运行 STM32CubeMX,由 .ioc 重新生成 CubeMX 工程 Run STM32CubeMX in script mode to regenerate the CubeMX project from the .ioc file
libxr stm32 cmake 把 LibXR 接入 CubeMX 的 CMake 工程 Integrate LibXR into the CubeMX CMake project
libxr stm32 flash-info 打印某个型号的 Flash 布局 Print the flash layout of a model
libxr stm32 toolchain 切换工具链和 ST Arm Clang 的标准库 Switch the toolchain and the ST Arm Clang standard library

入门教程和完整说明见文档 / Tutorials and reference: https://xrobot.work/docs/code_gen · https://xrobot.work/en/docs/code_gen

旧命令 / Old commands

6.0.0 之前的 xr_* 命令仍可使用,参数与原来相同,运行时提示对应的新命令,将在 7.0.0 删除。以下几处 行为与 libxr 5.2.4 不同:xr_gen_code 和 xr_gen_code_stm32 收到 --hw-cntr 时报错退出,它生成的 HardwareContainer 已从 LibXR 删除,XRobot 工程改用 --xrobot;xr_parse 和 xr_parse_ioc 在含有 多个 .ioc 文件的目录中报错退出,不再逐个解析;xr_stm32_toolchain_switch clang 不带 -g、-n 或 -p 时保持当前的标准库,不再报错;xr_stm32_toolchain_switch 在 GCC 与 ST Arm Clang 之间切换时删除 build/ 和 cmake-build*,xr_stm32_cmake 则不再删除它们,CMake 在下次构建时重新配置。

The xr_* commands of versions before 6.0.0 still work with the same arguments; they name their new command when run and are removed in 7.0.0. A few behaviors differ from libxr 5.2.4: xr_gen_code and xr_gen_code_stm32 stop with an error on --hw-cntr, as LibXR no longer has the HardwareContainer it generated, and XRobot projects use --xrobot instead; xr_parse and xr_parse_ioc stop with an error in a directory with several .ioc files instead of parsing each; xr_stm32_toolchain_switch clang without -g, -n or -p keeps the current standard library instead of failing; xr_stm32_toolchain_switch removes build/ and cmake-build* when it switches between GCC and ST Arm Clang, while xr_stm32_cmake no longer removes them, and CMake configures again on the next build.

旧命令 Old 新命令 New
xr_parse、xr_parse_ioc libxr parse
xr_gen_code、xr_gen_code_stm32 libxr gen
xr_cubemx_cfg libxr stm32 setup
xr_cubemx_generate libxr stm32 cubemx-gen
xr_stm32_cmake libxr stm32 cmake
xr_stm32_flash libxr stm32 flash-info
xr_stm32_toolchain_switch libxr stm32 toolchain

🧪 测试 / Tests

pip install clang-format==21.1.8
python -m unittest discover -s tests -v

生成的 C++ 文件按 LibXR 的风格排版,测试用固定版本 21.1.8 的 clang-format 核对 DevC、MC02 和随机工程的 输出;没有安装这个版本时,这些测试被跳过。

The generated C++ files follow the style of LibXR, and the tests check the output for DevC, MC02 and random projects against clang-format 21.1.8; they are skipped without that version.


📖 更多信息 / More Information

Metadata

Release files for libxr 6.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for libxr 6.0.1
File Size Uploaded
libxr-6.0.1.tar.gz 1.4 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for libxr 6.0.1
File Interpreter ABI Platform
libxr-6.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 2.6 MB

Release files / libxr-6.0.1.tar.gz

Download URL libxr-6.0.1.tar.gz
Size 1.4 MB
Tags Source
SHA-256 checksum
How to use checksums
3df17894fe597c5dff8d6337a5cdcc99bee1f7a819a4232b35db31a15def3faa
BLAKE2b-256 checksum
How to use checksums
c48b0b8c471de383a7205144d1c60c8efbc8405a0d7955e76b6241a4b5eba74c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release files / libxr-6.0.1-py3-none-any.whl

Download URL libxr-6.0.1-py3-none-any.whl
Size 1.2 MB
Tags Python 3
SHA-256 checksum
How to use checksums
a577f553523cd4eeda99d72d22ad39362c4e0d8f0c44cd051800b75e74f362a2
BLAKE2b-256 checksum
How to use checksums
a047db7150c0a89ef191eeaabdbff343b93d7afd3bf2dfe8e2580def18101c47
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

6.0.1 This release

2 release files

6.0.0

2 release files

5.2.4

2 release files

5.2.3

2 release files

5.2.2

2 release files

5.2.1

2 release files

5.2.0

2 release files

5.1.9

2 release files

5.1.8

2 release files

5.1.7

2 release files

5.1.6

2 release files

5.1.5

2 release files

5.1.4

2 release files

5.1.3

2 release files

5.1.2

2 release files

5.1.1

2 release files

5.1.0

2 release files

0.4.9

2 release files

0.4.8

2 release files

0.4.7

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.9

2 release files

0.3.8

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.9

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.2

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page