2025-03-10 00:00:00
Su7出的时候创始版没抢就有点后悔了,没想到后面一车难求,甚至开一年还能接近原价卖出去,属实离谱,雷总的饥饿营销+车子本身确实不错,让Su7一直维持供不应求的程度,二手车基本都是秒转。
对于我自己来说没啥开车的需求,出门都是打车,至少这三十年打车都能满足我。这次本不打算买的,但是基于Su7的盛况,Ultra也会供不应求,既然如此不如买来玩一下,拿个赛照,下下赛道,总不能浪费了我的模拟器(成天吃灰)。记录一下Su7 Ultra提车全过程,看看我一年后能亏多少。
24.10.29,提交了小定,也没打算买,反正小定只要1w,而且发售时也能退,就无所谓了,主要还是81w太贵了。
25.1.18,租了一辆Su7 Pro给老爹过年玩了一个月,体验还行,本想租一个Max的,可惜没租到
25.2.27,81w降到52w,犹豫了2分钟,还是在22.02下了大定,选了现车
不是很喜欢大鼻孔,还是低调一点,银色更好看一些
由于是现车,选项有限,只能选了这个,最后总价541900。银色配黄色拉花非常难看,和销售及售后都联系过,无奈没有去掉拉花的服务。后续雷总直播里也说到了很多人不想要这个拉花,太难看了。
之前销售是说大概三月五号左右车能到,不过由于要周转资金,还交不了全款,一直到三月六号支付了全款,最早一批似乎4号还是5号就已经拿到了车。
7号就在问销售能否8号提车,但是死活不给准确答复,一直到8号晚才收到短信提示车已经到了,可以提车了
销售基本立马就跟我确认了交付时间,9号上午10点就可以提车了。
提车之前还有一些东西可以提前处理,比如保险、物联网卡认证,小米把这一部分完全集成到了APP里,除了支付的部分还得去外面,其他的都可以一站式解决,还是很简单的,适合第一次买车的人
Ultra的保险只有两种,一个基础版(13327),一个尊享版(13918),就差在这个车上人员责任险这里
据说深圳险比较贵,广州等其他城市便宜一些。支付完成以后立马就能拿到保单了
这没啥说的,正常实名而已,到这里基本提车前的一些准备工作都做完了,剩下就是带身份证去现场提车和办理临牌了
在小米汽车APP里面有一个独立的购车协议的页面,协议签印藏得很深,我甚至在没有签印合同的情况下就已经做完了支付和上面所有操作
这很是疑惑,为什么可以在没合同之前做这些事情,这里的风险是谁承担的
看起来这个签印合同更像是给公司或者贷款之类的需要实际合同才能打款准备的
3.9一大早去提车,在前面东西都做好的前提下,提车流程非常简单,也非常快。提车专员先是领你看一下车,确认交车的配置、车辆没啥外观明显的异常,然后就可以去申请指标和临牌,不需要排队,立马就能办理。全流程都只需要身份证和粤省事就行了
牌照选择了官方的代办,只需要加268就行了,全流程都有人帮忙处理,只需要去一次车管所验车就行了,其他都有人帮忙处理
由于买的太早了,车管所还没有这个车的备案,还需要等通知,所以临牌最多可以续2次,一次一个月
办理完手续就开始正式交付车辆,提车专员会讲解车机相关功能,讲解完成,拍照合影,然后就会帮你把车开出去了,外面就可以直接开回家了
车钥匙是2个NFC卡,同时也指导你把手机蓝牙和车绑定了,手机就可以直接解锁。
提车礼物(看其他人视频提前知道了):
简单说300km以内最大速度只有140km/s,超过以后解禁,无论你是什么人都会有这个限制。
当天就开满了300,在300公里的时候,停下来切到P档再切回D档,就会提示解锁安全模式,此时这个车就解锁了1500匹马力?并不是,需要你开启赛道模式,赛道模式需要一个学习和答题考试,大概十五分钟内就行了,我是在别人在开的时候答的题,基本都是常识,大概四五分钟就能考试通过了。默认的运动模式和Max是一样的673匹。
赛道模式又分几种:
赛道模式没有电子围栏,也就是不需要在赛道才能开启。
赛道模式下开启排位赛,加速度确实非常恐怖,提前做好心理准备,实际推背感非常猛
回头率不如当初的Su7发售,但是还是不错的,很多人都会回头看,殊不知车里三个长枪短炮拍着车外回头的人
Ultra订单界面还有一个Club的会员,看了一下,入会3999,送6w积分,大概就是6000,可以直接换购一个充电桩11kW(5999),刚好消耗完。
如果买其他东西,把商店买空都花不了6000,所以可以留一下看后续还能推出一些啥东西
Club说是只有2000会员,但是实际会员号能有1w个,按照顾问的话,后续可能会有赛道活动什么的,但是目前一问三不知,真不知道这个顾问有啥用,回复个问题慢的要死,还不如机器人,建议下次这样就别叫什么专属顾问了,还不如24小时客服秒回呢
第一个问题,在悬挂是最高的情况下,实际车比想象的要低一点的,这个大概有个三四cm?,前铲下面有一个类似挡泥板的东西,这个会额外凸出一点,在上一个小坡的时候蹭到了,边缘稍微有点卷边了,应该不是大问题
好像这个突出来的是衬套?官方建议检查一下,有空再说吧
第二个问题,在正常行驶过程中,已经开启导航和hud,hud同时也有导航线路显示,但是如果此时再开赛道大师,开启排位或者任意模式,此时hud中的导航线路会消失,此时退出赛道大师、退出导航,重开hud,都无法在hud中显示导航线路。在无导航线路的情况下开了大概半小时以后,hud的导航线路自动恢复了。
第三个问题,今天几次智能泊车时,都出现车位刚开始提示有,但是泊车过程中刹停以后,车位消失,提示搜索但是持续一段时间都找不到。泊车时扫到玻璃门,一开始应该是没扫描到,直接往门方向走的,等到接近以后扫到了直接刹停了。
充电还遇到一点问题,今天用小鹏的专用桩,刚开始充电正常,中间吃饭时再看停止充电了,后续发现似乎是充电桩无响应了,原因未知,远程也无法重新开启充电,也无法停止充电。
特斯拉的超充,可以直接用,半小时不到从60%充到100%,对比家里的这个龟速,强太多了。
其他问题
暂时就遇到这些问题,后续再补充吧,目前看好像Su7 Ultra没有车友群,也没任何组织,官方似乎也有意推动这样?不是很懂
感谢我的小伙伴们一路肝爆到解禁
2025-03-06 00:00:00
全网找不到几个LLVM工具链进行交叉编译的例子,如果只是Linux环境,那可能随便弄,但是Windows下要拉哪个库,环境变量什么的要怎么弄都没找到例子。东拼西凑了几个Blog的内容,总算是完整可以编译了
如果直接用Keil的AC6,那没啥难度,如果抛弃他,改用开源又要怎么弄
GNU GCC编译流程:
源代码 → GCC前端 → GIMPLE(中间表示) → RTL → 汇编代码 → GNU汇编器 → 目标代码
Clang/LLVM编译流程:
源代码 → Clang前端 → LLVM IR → LLVM优化器 → LLVM后端 → 汇编代码 → 目标代码
同时也有各种魔改的类型,使用混合的,Clang的前端+GNU的后端,Clang的前端目前公认是比GNU要快很多的
目前开源可用的LLVM的交叉编译工具链,只看到了这一个
https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/releases
官方版本的工具链目前还在建设阶段,根本没有Release可用
https://github.com/arm/arm-toolchain/tree/arm-software
下一个,解压,将bin目录加入到环境变量中
CMake、Make、Ninja(如果需要)也同样需要安装
如果是用MSYS2,可以通过下面的方式安装
安装make
pacman -S make
安装cmake
pacman -S cmake
安装ninja
pacman -S ninja
查看所有安装的包
pacman -Sg
编译工程,以这个为例,他没有说明具体环境怎么弄,而LLVM最麻烦的就是环境问题了
https://github.com/wuwbobo2021/arm-llvm-stm32f103-blinky
他是make构建的整个工程,所以只需要make工具即可,目前LLVM需要人工指定libc、libm的目录或者引用
所以需要这么写
make "ARM_LIB_DIR=I:\llvm\LLVM-ET-Arm-19.1.5-Windows-x86_64\lib\clang-runtimes\arm-none-eabi\armv7m_soft_nofp"
需要指定你的LLVM的armv7m_soft_nofp路径,才能正确找到libc和libm
这样就能正常编译完成了
对比一下和arm-gnu-none-eabi的编译有什么区别
# output name
TARGET = arm-llvm-stm32f103-blinky
# debug build?
DEBUG = 0
# optimization
OPT = -O3 -flto
ASM_SOURCES = stm32f10x/startup_stm32f103xb.s
LD_SCRIPT = stm32f103c8tx_flash.ld
C_DIRS = arm \
stm32f10x \
.
C_DEFS = -DUSE_STDPERIPH_DRIVER \
-DSTM32F10X_MD
# 主要这里指定库路径,不知道还没有没有啥办法自动寻找,而不用指定路径
# it must be set for libc and libm, like
# <LLVM Embedded Toolchain for Arm>/lib/clang-runtimes/arm-none-eabi/armv7m_soft_nofp
ARM_LIB_DIR =
# 这个路径却能自动寻找到
# leave empty if the original llvm/clang should be used
ARM_LLVM_PATH =
# 修改替换使用的一些工具
CC = $(ARM_LLVM_PATH)clang
AS = $(ARM_LLVM_PATH)clang
CP = $(ARM_LLVM_PATH)llvm-objcopy
SZ = $(ARM_LLVM_PATH)llvm-size
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S
OPENOCD = openocd \
-f /usr/share/openocd/scripts/interface/stlink.cfg \
-f /usr/share/openocd/scripts/target/stm32f1x.cfg
GDB = gdb-multiarch
ifeq '$(findstring ;,$(PATH))' ';'
# Windows
RM = del /Q
else
RM = rm -f
endif
# 一些flag的写法或者表示和gnu不太一样了,需要独立区分
FLAGS = -mthumb -mcpu=cortex-m3 --target=thumbv7m-none-unknown-eabi -mfpu=none
C_INCLUDES = $(foreach d, $(C_DIRS), -I$(d)) -I$(ARM_LIB_DIR)/include
C_SOURCES = $(foreach d, $(C_DIRS), $(foreach c, $(wildcard $(d)/*.c), $(c)))
CFLAGS = $(C_DEFS) $(C_INCLUDES) $(FLAGS) -std=c99 -fdata-sections -ffunction-sections
OBJS = $(C_SOURCES:.c=.o) $(ASM_SOURCES:.s=.o)
LD_FLAGS = $(FLAGS) -Wl,--gc-sections -T$(LD_SCRIPT) -nostdlib -lc -lm -L $(ARM_LIB_DIR)/lib
ifeq ($(DEBUG), 1)
C_DEFS += -DDEBUG
CFLAGS += -g -gdwarf-2
else
CFLAGS += $(OPT)
LD_FLAGS += $(OPT)
endif
$(TARGET).bin: $(TARGET).elf
$(BIN) $< $@
$(TARGET).elf: $(OBJS)
$(CC) $(LD_FLAGS) $(OBJS) -o $@
$(SZ) $@
%.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
%.o: %.s
$(AS) -c $(FLAGS) $< -o $@
.PHONY: clean flash debug
clean:
$(RM) $(foreach d, $(C_DIRS), $(d)/*.o) *.elf *.bin
flash: $(TARGET).bin
$(OPENOCD) -c "program $(TARGET).bin preverify verify reset exit 0x08000000"
debug: $(TARGET).elf
$(GDB) -iex "target extended | $(OPENOCD) -c 'gdb_port pipe'" \
-iex 'monitor reset halt' -ex 'break main' -ex 'c' -ex '-' $<
这个的写法是与GNU最大的不同点,他的组合比较固定,没有GNU那么灵活
--target=thumbv7m-none-unknown-eabi -mfpu=none
--target=thumbv7m-unknown-none-eabihf -mfpu=fpv5-d16
如果是在CMakeLists中需要额外指定库文件位置,否则还是会提示问题
# Link directories setup
target_link_directories(${CMAKE_PROJECT_NAME} PRIVATE
# Add user defined library search paths
"I:/llvm/LLVM-ET-Arm-19.1.5-Windows-x86_64/lib/clang-runtimes/arm-none-eabi/armv7m_soft_nofp/include"
)
# Add linked libraries
target_link_libraries(${CMAKE_PROJECT_NAME}
# Add user defined libraries
-l:libc.a
-l:libm.a
)
类似这种通不过cmake的test程序,这种都是库没定义好,缺少必要的库,导致连cmake内部的检测程序都无法正常调用编译器完成编译,进而提出错误
LLVM-ET-Arm-19.1.5-Windows-x86_64/bin/clang.exe"
is not able to compile a simple test program.
网上一般有两种解决方案,一种是直接修改对应报错的cmake的测试程序,一种是传递一个宏,让这个检测程序不运行,建议都别用。还是正常解决库路径的问题,否则后面还会有更多问题的
经典问题_exit
没有定义,这个是GNU里,可以使用--specs=nosys.specs
直接靠编译器帮我们实现一个替代,我们就不用写了
ld.lld: error: undefined symbol: _exit
>>> referenced by signal.c:151 ...
>>> referenced by abort.c:63 ...
但是似乎LLVM里没有这个东西,那就得手动实现一个
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
extern "C" {
// 系统调用实现
void _exit(int status) {
while(1) {
// 一个断点,方便调试
__asm__ volatile("bkpt #0");
}
}
int _close(int file) { return -1; }
int _fstat(int file, struct stat *st) {
st->st_mode = S_IFCHR;
return 0;
}
int _isatty(int file) { return 1; }
int _lseek(int file, int ptr, int dir) { return 0; }
int _read(int file, char *ptr, int len) { return 0; }
int _write(int file, char *ptr, int len) { return len; }
// C++ 运行时支持
void __cxa_pure_virtual() { while (1); }
int __cxa_atexit(void (*destructor) (void *), void *arg, void *dso) { return 0; }
void __cxa_finalize(void *f) {}
void *__dso_handle = nullptr;
}
大致类似这样的一个文件即可,如果没有c++就去掉c++部分,其他的适配c
目前GNU和LLVM都可以正常编译完成整个工程了
对比两种工程编译时间:
LLVM Build completed: 00:04:27.449
GNU Build completed: 00:02:19.536
不知道哪里有问题,导致LLVM实际反而比GNU要慢,甚至慢了一倍
https://hustlei.github.io/2018/11/msys2-pacman.html
https://github.com/ARM-software/LLVM-embedded-toolchain-for-Arm/blob/main/docs/migrating.md
https://github.com/astronmax/stm32-llvm
https://www.eet-china.com/mp/a103863.html
2025-02-27 00:00:00
之前看到CMake有这么多选项,感觉不简单,还是看下别人在这里设计了多少东西
整体来说CMake遵循这样一套结构
操作-操作预设(如果有的话)-操作目标(如果有的话)
比如
Configure-ConfigurePreset
Build-BuildPreset-Build_Target
Launch-Launch_Target
Test-TestPreset
Pack-PackPreset
Workflow-WorkflowPreset
这个不用多说,最基础的配置了
Kit是作为configure中的一个环境,也就是编译工具链的配置
同时默认的CMake把工具链和生成配置类型,这个区分开了,实际我之前做的demo也区分开了二者
而这个Kit是不需要你写的,直接通过扫描环境就能识别,感觉这样更好,可以去掉自己写的工具链
简单说Variant就是允许你对Kit和优化输出等级进行打包和重命名,这样的话不同编译工具链+优化输出等级就形成了一个新组合,这个组合就叫Variant,这样用起来其实就更灵活了
这只有2种元素进行组合,如果元素多了,这个组合就非常恐怖了,但是它可以自动帮你排列组合好
对于那种超级兼容性的大工程,做自动化流程的时候就比较方便
Build就不说了,正常配置,Build内可以选择Target,这样的话其实很多东西都能写到配置文件里去,通过Target选择不同的编译结果
Launch包含调试和运行,也可以选择调试的目标
Debug都是调用外部程序完成的,本身没这个能力,launch可以做一些调试前或者后的操作
特性 / 框架 | CTest | JUnit | PyTest | Google Test |
---|---|---|---|---|
语言支持 | C/C++ | Java | Python | C++ |
集成度 | 与CMake紧密集成,适合CMake项目 | 与Java开发环境集成 | Python生态中集成度高 | 良好的C++环境集成 |
测试类型支持 | 支持单元测试、集成测试、性能测试 | 主要支持单元测试 | 支持多种类型的测试 | 主要支持单元测试 |
可扩展性 | 通过CMake脚本可扩展 | 可以通过插件扩展 | 强大的插件系统 | 可以通过宏和参数化扩展 |
测试发现 | 自动化测试发现 | 一般 | 强大的自动化测试发现 | 自动化测试发现 |
结果报告 | 详细的测试结果报告 | 结果报告清晰 | 结果报告详细且支持插件扩展 | 结果报告详细 |
社区和文档 | 较小的社区,文档适中 | 大社区,丰富的文档 | 大社区,丰富的文档 | 大社区,丰富的文档 |
适用场景 | 适用于需要CMake构建系统的C/C++项目 | 适用于Java项目 | 适用于Python项目 | 适用于需要详细测试报告的C++项目 |
add_executable(TestInstantiator TestInstantiator.cxx)
target_link_libraries(TestInstantiator vtkCommon)
add_test(NAME TestInstantiator
COMMAND TestInstantiator)
简单说就是可以直接执行测试指令,类似VS里面的单元测试,只不过这个测试是调用外部的程序完成的
实际上直接做代码覆盖测试也可以,需要引入gtest等额外的模块,同样的对于测试目标,也可以debug
简单的编译完成以后,运行一下自己,就看到了测试结果
CTest只是一个调用方,不是具体的测试框架,测试框架可能得需要gtest之类的东西来做
CPack有两个作用,第一个自动添加缺少的包
cmake_policy(SET CMP0135 NEW)
find_package(GTest)
if(NOT GTest_FOUND)
message("GTest not found, download it...")
include(FetchContent)
FetchContent_Declare(googletest URL https://github.com/google/googletest/archive/refs/heads/main.zip)
FetchContent_MakeAvailable(googletest)
endif()
比如这里自动下载gtest的包
第二个就是自动打包,当编译测试都做完了,那就还剩下打包发布了,CPack就是用来将生成结果进行打包的,支持很多类型的打包
cmake_minimum_required(VERSION 3.0)
project(MyProject)
# 添加源代码
add_executable(MyProject main.cpp)
# 添加依赖库
find_package(Boost REQUIRED)
target_link_libraries(MyProject PRIVATE Boost::boost)
# 安装文件
install(TARGETS MyProject DESTINATION bin)
# 打包
set(CPACK_PACKAGE_NAME "MyProject")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_GENERATOR "ZIP")
include(CPack)
运行之后就会自动打包为zip
简单说workflow就可以把前面所有的东西组合在一起,他们可以一一对应起来变成一个个工作流
配置-构建-测试-打包
下面就是工作流的预设,这样的工作流可以简单的配置很多个
"workflowPresets": [
{
"name": "wf",
"description": "",
"displayName": "工作流",
"steps": [
{
"type": "configure",
"name": "gcc13"
},
{
"type": "build",
"name": "all"
},
{
"type": "test",
"name": "test_Project"
},
{
"type": "package",
"name": "all"
}
]
}
]
点一下就可以把上面的步骤来一遍,直接实现CICD流程
VSCode中CMake Tools相关的教程还是太少了,很多东西都对不上,而VSCode把各个之间的一些参数或者设置隐藏了,导致实际如果出问题想要调试找到具体位置有些困难,不如原生的CMake,是啥就是啥都能看到
https://blog.csdn.net/witton/article/details/130170686
https://blog.csdn.net/witton/article/details/130216777
https://blog.csdn.net/witton/article/details/145307607?spm=1001.2014.3001.5502
https://github.com/microsoft/vscode-cmake-tools/blob/main/docs/cmake-presets.md#test
https://cmake.org/cmake/help/latest/manual/ctest.1.html#ctest-1
https://blog.csdn.net/m0_49302377/article/details/130264041
2025-02-27 00:00:00
VSCode CMake Debug 嵌入式MCU有好几种方案
https://elmagnifico.tech/2023/07/22/Vllink-DapLink-Debug/
OpenOCD,需要专门的调试工具,ST-Link或者这里的VLink,支持CMSIS-DAP的
增加而一个build做为前置任务,然后启动openodcd
tasks.json
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "shell",
"command": "make",
"args": [
],
"group": "build"
},
{
"label": "download",
"type": "shell",
"command": "openocd",
"args": [
"-f",
"cmsis-dap.cfg",
"-f",
"stm32h7x.cfg",
"-c",
"program build/stm32h7_demo.elf verify reset exit"
],
"group": "build"
}
]
}
launch.json 主要给openocd输入调试配置
{
"version": "0.2.0",
"configurations": [
{
"cwd": "${workspaceRoot}",
"executable": "./build/stm32h7_demo.elf",
"name": "Debug Microcontroller",
"request": "launch",
"type": "cortex-debug",
"showDevDebugOutput": false,
"servertype": "openocd",
"configFiles": [
"cmsis-dap.cfg",
"stm32h7x.cfg"
]
}
]
}
顾名思义JLink需要配合JLink来使用
需要注意JLink的对应路径也需要在环境变量里,否则可能调用不到
JLinkGDBServerCL.exe -singlerun -nogui -if swd -port 50000 -swoport 50001 -telnetport 50002 -device STM32H743VI
在VSCode里新建一个launch,主要是svd和elf路径,device填正确就行了
{
"version": "0.2.0",
"configurations": [
{
"name": "Cortex Debug-jlink",
"cwd": "${workspaceRoot}/",
"executable": "${workspaceFolder}/build/bin/demo.elf",
"request": "launch",
"type": "cortex-debug",
"servertype": "jlink",
"device": "STM32H743VI",
"interface": "swd",
"runToEntryPoint": "main",
"showDevDebugTimestamps": true,
"svdFile": "${workspaceRoot}/config/STM32H743.svd",
// "preLaunchTask": "build",
// "postDebugTask": "run"
}
]
}
通过VSCode这种方式调用,启动非常慢,和SES对比就拉跨
之前用过的一个插件
https://elmagnifico.tech/2022/03/15/Embedded-Software-Development-VS-VSC/
本质上还是调用gdb然后配合openocd来实现调试的
{
"name": "Launch",
"type": "cppdbg",
"request": "launch",
"cwd": "${workspaceFolder}",
"program": "${workspaceFolder}/build/app/mxchip_azure_iot.elf",
"MIMode": "gdb",
"miDebuggerPath": "arm-none-eabi-gdb",
"miDebuggerServerAddress": "localhost:3333",
"debugServerPath": "openocd",
"debugServerArgs": "-f board/stm32f4discovery.cfg",
"serverStarted": "Listening on port .* for gdb connections",
"filterStderr": true,
"stopAtConnect": true,
"hardwareBreakpoints": {
"require": true,
"limit": 6
},
"preLaunchTask": "Flash",
"svdPath": "${workspaceFolder}/STM32F412.svd"
}
跳过VSCode,直接使用专业的Ozone来调试
https://elmagnifico.tech/2023/12/07/SES-Ozone-FreeRTOS/
配合我自己写的调用程序,很小30k,自动找到Ozone的路径,然后调用对应的调试文件,如果没有的话会自动新建一个
同样的烧写我也用了自己的程序去调用jlink完成烧写,比调用第三方插件可控性高多了
新建一个task,对应还有输入选择模板,否则一个配置要写一个task,太繁杂了
{
"version": "2.0.0",
"tasks": [
{
"label": "Debug",
"type": "shell",
"command": "${workspaceFolder}/Ozone/flash.exe",
"args": [
"--o",
"--path",
"${input:debugPath}"
],
"group": {
"kind": "build",
"isDefault": false
},
"problemMatcher": [],
"options": {
"env": {
"DEBUG_PATH": "${input:debugPath}"
}
}
}
],
"inputs": [
{
"id": "debugPath",
"type": "pickString",
"description": "Select the debug configuration",
"options": [
"${workspaceFolder}/Ozone/test.jdebug",
"${workspaceFolder}/Ozone/test2.jdebug",
"${workspaceFolder}/Ozone/test3.jdebug",
"${workspaceFolder}/Ozone/test4.jdebug",
],
"default": "${workspaceFolder}/Ozone/test.jdebug"
}
]
}
总体来说VSCode的调试不是很好用,还是原生的更好一些。
总感觉VSCode这里给的接口实在是太多了,选择太多了,但是每个选择其实做的都一般,没做到极致的水平
这些插件更像是一个整合工具,然后再接入另外一个整合工具,层层套娃,最后糊了一个勉强能用的东西
https://blog.csdn.net/pyt1234567890/article/details/122522700
https://blog.csdn.net/xiaoyuanwuhui/article/details/128085237
https://github.com/microsoft/vscode-cmake-tools/blob/main/docs/debug-launch.md
2025-02-25 00:00:00
本篇解决一下CMake和VScode怎么整合到一起
适配VSCode
VSCode只需要一个CMake Tools,不需要安装其他CMake插件
Kconfig格式化和代码高亮,还是用nRF的好一些,另外那个Kconfig会识别出错
C/C++提示全家桶也需要安装,会影响到代码提示和跳转体验
vscode cmake 缺少选择Select a Kit
,主要原因是目录已经有了CMakePresets.json
,有预设的情况下不会给你选kit,这个问题找了半天,发现官方文档就写了
但是你搜索的命令又有,只能说官方弄的有点乱,而且本身使用预设和可以选kit我觉得也不矛盾
CMake:Scan for compiles
去掉预设文件以后,这个kit果然就有了,就可以正常选择了
实际上这一步根本不需要,建议不要浪费实际调整这个,预设文件早就把这些设置好了,唯一需要处理的就是搜索本地的编译器,否则VSCode不知道编译的gcc在哪里
CMake:Scan for compiles
默认的 status bar 实在是冗余太多了,从config,build,pack,ctest,cpack,workflow,很多用不上的我就给他隐藏了,而CMake Tools也支持自定义
{
"cmake.options.statusBarVisibility": "visible",
"cmake.options.advanced": {
"folder": {
"statusBarVisibility": "hidden",
"inheritDefault": "hidden",
"statusBarLength": 20,
"projectStatusVisibility": "hidden",
},
"configure": {
"projectStatusVisibility": "visible",
},
"configurePreset": {
"statusBarVisibility": "visible",
"inheritDefault": "visible",
"statusBarLength": 20
},
"kit": {
"statusBarVisibility": "hidden",
"inheritDefault": "hidden",
"statusBarLength": 20
},
"variant": {
"statusBarVisibility": "hidden",
"inheritDefault": "hidden",
},
"build": {
"statusBarVisibility": "visible",
"inheritDefault": "hidden",
"projectStatusVisibility": "visible",
},
"buildPreset": {
"statusBarVisibility": "hidden",
"inheritDefault": "hidden",
"statusBarLength": 20
},
"buildTarget": {
"statusBarVisibility": "hidden",
"inheritDefault": "hidden",
"statusBarLength": 20
},
"ctest": {
"statusBarVisibility": "hidden",
"inheritDefault": "hidden",
"statusBarLength": 20,
"color": true,
"projectStatusVisibility": "hidden",
},
"cpack": {
"statusBarVisibility": "hidden",
"inheritDefault": "hidden",
"statusBarLength": 20,
"color": true,
"projectStatusVisibility": "hidden",
},
"testPreset": {
"statusBarVisibility": "hidden",
"inheritDefault": "hidden",
"statusBarLength": 20
},
"launchTarget": {
"statusBarVisibility": "hidden",
"inheritDefault": "hidden",
"statusBarLength": 20
},
"debug": {
"statusBarVisibility": "hidden",
"inheritDefault": "hidden",
"projectStatusVisibility": "hidden",
},
"launch": {
"statusBarVisibility": "hidden",
"inheritDefault": "hidden",
"projectStatusVisibility": "hidden",
},
"workflow": {
"statusBarVisibility": "hidden",
"inheritDefault": "hidden",
"projectStatusVisibility": "hidden",
},
"workflowPreset": {
"statusBarVisibility": "hidden",
"inheritDefault": "hidden",
"projectStatusVisibility": "hidden",
},
"packagePreset": {
"statusBarVisibility": "hidden",
"inheritDefault": "hidden",
"projectStatusVisibility": "hidden",
}
}
}
将上面代码加入到setting.json就可以隐藏大部分没用的细节了
常用方法修改c_cpp_properties.json
在其中手动加入对应的宏即可
如果我们有多个配置,那就可以有多个配置不同的宏,然后通过右下角去切换C/C++的配置项,从而切换整体的宏定义
切换C++的配置和编译的configure不是一个配置,而且他们也不能联动,这就导致你改一下必须得手动切换配置才行
对于一般的宏(区分feature、驱动等等,用来选择文件的宏),这样还是有点傻了,其实我们生成了”autoconf.h”,只需要把他引入项目就可以自动识别宏了
可能有些宏是用户自定义的,类似这样的
# macro defines
set(USER_MACRO_DEFINES
"HSE_VALUE=8000000"
"USE_HAL_DRIVER"
"USE_FULL_LL_DRIVER"
"USE_USB_OTG_FS"
"STM32F767xx"
)
这种方式稍微有点傻了,其实只要把他们全部加入到Kconfig里,利用Kconfig去生成这个宏即可,虽然Kconfig的宏是包含了CONFIG_
这个头的,但是我们可以在CMake里通过一些手段去掉CONFIG_
还有一种办法是不去掉CONFIG,但是通过引入一个万能的头文件,里面预埋一个宏和其对应即可
#ifdef CONFIG_USE_HAL_DRIVER
#define USE_HAL_DRIVER
#endif
#ifdef HSE_VALUE8000000
#define HSE_VALUE 8000000
#endif
经过一番研究,发现其实CMAKE有一个生成compile_commands.json
的操作,这个会生成每个文件的编译命令,如果C++补全或者是高亮读取了这个文件,那么他就知道具体这个文件编译的时候使用了什么宏,那么对应宏是亮起还是灰掉,他就能智能识别
下面的命令就是在cmake编译的时候传递一个参数,让他自己生成这个json
"cmake.configureOnOpen": true,
"cmake.configureArgs": [
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
],
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools"
实际上这个命令在我们CMakeLists的前几句就写了
但是目前看效果不明显,似乎不会生效,感觉他需要额外再配置一下这个路径才能正确识别(前面的配置文件和自动识别会冲突)
经过测试发现他自动识别了在CMakeLists中增加宏,但是Kconfig的.config里的宏并没有识别,还是需要将头文件引入,才能正常识别
如果把同样的宏放到被排除编译的文件中,会发现所有宏都处于不被激活的状态
反查compile_commands.json
也可以知道,这个文件直接就不存在,自然不会有任何反应
继续优化,可以通过C_CPP配置手动将某些文件夹或者文件给排除出去(这里理论上靠compile_commands.json应该也能实现啊)
{
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
"C_Cpp.exclusionPolicy": "checkFilesAndFolders",
"C_Cpp.files.exclude": {
"**/node_modules": true,
"**/build": true,
"**/*.min.js": true
},
"cmake.configureOnOpen": true
}
项目里一些不需要显示的内容可以通过配置进行排除,让整个目录看起来更清爽
"files.exclude": {
"**/Battery": true,
"**/*.jlink": true,
"**/*.emProject": true,
"**/*.emSession": true,
"**/*.bin": true,
"**/*.bat": true,
"**/Boot": true
},
第一次编译可能过不去,这是config没有正确生成
VSCode第一次可能找不到编译器,需要使用Scan搜索一下
第二次编译可能还是过不去,需要clean一下工程,然后重新再编译
有时候需要调试一下,为什么某些文件被加入了,可以通过下面的代码输出当前加入的源文件,进而确定问题
# 输出当前目标的所有源文件
get_target_property(TARGET_SOURCES ${CMAKE_PROJECT_NAME} SOURCES)
message(STATUS "Current target sources:")
foreach(source ${TARGET_SOURCES})
message(STATUS " ${source}")
endforeach()
如果不整合到VSCode中,也有一些办法可以用来简化工作量
#!/bin/bash
# 提示用户选择预设
echo "请选择一个预设:"
options=("Debug" "Release" "Test")
# 设置自定义提示符
PS3="请输入选项编号: "
select opt in "${options[@]}"
do
case $opt in
"Debug"|"Release"|"Test")
PRESET=$opt
break
;;
*) echo "无效选项 $REPLY";;
esac
done
echo "您选择了 $PRESET, 开始构建项目...请先确认config变换"
CONFIG_FILE="./$PRESET.config"
if [ ! -f "$CONFIG_FILE" ]; then
echo "配置文件 $CONFIG_FILE 不存在,创建一个空白文件..."
touch "$CONFIG_FILE"
fi
# change project properties
export KCONFIG_CONFIG=./$PRESET.config
python -m guiconfig
# generate .config file
echo "生成config文件..."
python tools/kconfig.py Kconfig $PRESET.config autoconf.h kconfigLog.txt $PRESET.config
# create a build directory and make project
echo "创建预设目录..."
cmake --preset $PRESET
# build project
echo "开始build..."
cmake --build --preset $PRESET
相当于是一键build,只需要选好build的配置和确认Kconfig配置就可以自动进行下一步了
VSCode作为一个独立编辑器,距离IDE还是有点差距,整体性就是差了那么一点。想要做到完美,那就得自己开发插件,把好几个插件结合到一起,把他们之间的数据传递给弥补上
https://blog.csdn.net/weixin_39306574/article/details/103763144
https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html#id1
https://github.com/microsoft/vscode-cmake-tools/blob/fad04c8b3fef0ba80b61df1856bc747770042dc9/docs/cmake-settings.md
2025-02-23 00:00:00
继续上篇,解决一些未完成的问题
Linux内有一些模块化的操作,但是如果直接模仿,会发现无效。
比如类型中的tristate
是三状态,比如y、m、n,表示启用模块、动态加载 、禁用,三种情况,但是如果直接像下面这么写是无法启用的,你会看到怎么设都是启动和禁止,没有动态加载的选项
menu "New Module Configuration"
config NewModule
tristate "NewModule"
choice
prompt "Feature selection"
tristate
config Feature1
tristate "Feature 1"
help
"This is the first feature"
config Feature2
tristate "Feature 2"
help
"This is the second feature"
endchoice
endmenu
只有开启modules 才能在三态中增加显示m状态
menu "New Module Configuration"
config MODULES
prompt "Enable Modules"
def_bool y
option modules
config NewModule
tristate "NewModule"
choice
prompt "Feature selection"
tristate "Choose a feature"
config Feature1
tristate "Feature 1"
help
"This is the first feature"
config Feature2
tristate "Feature 2"
help
"This is the second feature"
endchoice
endmenu
开启以后就有了M选项,否则只有X和空
不过这种模块化,在MCU这里用不上,建议不要增加复杂度
现在如果新加了一个module,希望可以不改动架构的Kconfig的情况下,自动完成新文件夹内Kconfig的识别和加入
menu "Module Configuration"
config Motors
bool "Motors"
config Flash
bool "Flash"
source "module/*/Kconfig"
endmenu
通过通配符的方式可以自动索引第一级子目录的kconfig
据说这种方式可以索引所有子目录,但是实际我这里不行
source "module/**/Kconfig"
至于第二级、第三级就必须要在其上一级这么写了才能索引到,source只能索引从主kconfig出发的路径,就必须要写全所有路径,这就有点不合理
source "module/NewModule/*/Kconfig"
source "module/NewModule2/*/Kconfig"
第三级就要写更多了
source "module/NewModule/SubModule/*/Kconfig"
但是kconfiglib有拓展,它支持rsource,顾名思义,他就是相对路径,从当前kconfig路径开始算,上级路径会自动帮你引用
menu "Module Configuration"
config Motors
bool "Motors"
config Flash
bool "Flash"
rsource "*/Kconfig"
endmenu
这样就有效解决了,未知新模块需要写所有路径的问题,只需要写好引用下层路径即可
上面解决了Kconfig,同时还有一个CMake也得自动引用,二者才能搭配完成目的
一般作为独立模块,有可能其内部是一个xxx.cmake,也有可能是一个CMakeLists,先说两者差别。
如果是CMakeLists,那么这个模块是可以独立编译的,完全不依赖当前工程他就能自己编译完成。
如果是一个xxx.cmake,那这个模块是非独立的,他需要依赖当前工程中的一些东西,需要和工程整体一起编译
先说xxx.cmake,还是利用相对路径取下一级的所有cmake,然后被引用
# sources
if(CONFIG_FLASH)
message(STATUS "Flash module is enabled")
file(GLOB_RECURSE DRIVER_SOURCES
# 加入文件夹
${CMAKE_CURRENT_LIST_DIR}/Flash/*.*
)
target_sources(${CMAKE_PROJECT_NAME} PRIVATE ${DRIVER_SOURCES})
# include
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
${CMAKE_CURRENT_LIST_DIR}/Flash
)
endif()
# 引入当前路径下的所有CMake文件
message(STATUS "CMAKE_CURRENT_LIST_DIR: ${CMAKE_CURRENT_LIST_DIR}")
file(GLOB CMAKE_FILES "${CMAKE_CURRENT_LIST_DIR}/*/*.cmake")
foreach(CMAKE_FILE ${CMAKE_FILES})
include(${CMAKE_FILE})
endforeach()
对应的模块内的NewModule.cmake,就可以写成这样,将自己内部的文件加入,如果还需要套娃,那么继续使用上面的方式即可
message(STATUS "NewModule Add")
# sources
if(CONFIG_NewModule)
file(GLOB_RECURSE DRIVER_SOURCES
# 加入文件夹
${CMAKE_CURRENT_LIST_DIR}/*
)
target_sources(${CMAKE_PROJECT_NAME} PRIVATE ${DRIVER_SOURCES})
# include
target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE
${CMAKE_CURRENT_LIST_DIR}
)
endif()
demo对应工程里的NewModule和SubModule
如果是CMakeLists,那么要用下面的方式加入CMakeLists
# 引入当前路径下的所有子目录中的CMakeLists.txt文件
file(GLOB SUBDIRS RELATIVE ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/*)
foreach(SUBDIR ${SUBDIRS})
if(IS_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/${SUBDIR})
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/${SUBDIR}/CMakeLists.txt)
add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/${SUBDIR})
endif()
endif()
endforeach()
demo对应工程里的NewModule2和SubModule2
以上解决方案或者示例都加入到了演示的仓库中
https://github.com/LuckkMaker/apm32-kconfig-example
https://docs.zephyrproject.org/latest/build/kconfig/extensions.html