单片机工程使用链接优化-flto找不到定义_链接静态库
IDE: CLion
HOST: Windows 11
MinGW:x86_64-14.2.0-release-posix-seh-ucrt-rt_v12-rev0
GCC: arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi
示例工程:https://github.com/ichliebedich-DaCapo/STM32F407VET6
一、链接过程
在单片机开发中,我希望尽可能开发“低耦合高内聚”的代码,我理想中的工程依赖关系如下图:

(后续还考虑加入FreeRTOS、DSP、FATS什么的)
基于上面目的,于是把工程分成各个模块,采用独立编译成静态库,最后再链接的方法。
对于HAL库的静态编译可以使用file()先收集需要文件到变量DRIVERS_SRC中,然后使用set()设置需要包含的头文件目录DRIVERS_DIR,之后就可以使用add_library()添加要编译生成的库的名称和所需的资源文件,STATIC是属性,表示要编译的是静态库
再使用target_include_directories()添加库所需的头文件目录
最后可以使用属性ARCHIVE_OUTPUT_DIRECTORY来专门指定静态库的生成目录
# 官方驱动库 file(GLOB_RECURSE DRIVERS_SRC "Drivers/STM32F4xx_HAL_Driver/Src/*.c") set(DRIVERS_DIRDriversDrivers/STM32F4xx_HAL_Driver/IncDrivers/STM32F4xx_HAL_Driver/Inc/LegacyDrivers/CMSIS/Device/ST/STM32F4xx/IncludeDrivers/CMSIS/Include ) add_library(libdrivers STATIC ${DRIVERS_SRC}) target_include_directories(libdrivers PUBLIC ${DRIVERS_DIR}) # 设置静态库的输出目录 set_target_properties(libdrivers PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${LIB_DIR})库的名称也是有规范的,一般都是“lib+xxx”组成的,比如这次,编译的库用于驱动,所以起名为lib+drivers -> libdrivers。当然由于这是基于STM32提供的HAL,所以也可以起名为libhal
依此方法,编译BSP时,由于BSP依赖HAL库,所以需要链接HAL库(即libdrivers)。即下方中的target_link_libraries()函数,使用这种方法自然也可以链接一些第三方库,比如SDL
target_link_libraries(libbsp PUBLIC libdrivers)# ------BSP库------ file(GLOB_RECURSE BSP_SRC "BSP/src/*.c") set(BSP_DIRBSP/inc ) add_library(libbsp STATIC ${BSP_SRC}) target_include_directories(libbsp PUBLIC ${BSP_DIR}) target_link_libraries(libbsp PUBLIC libdrivers) # 设置静态库的输出目录 set_target_properties(libbsp PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${LIB_DIR})
根据上面的方法可以链接成不同的静态库,再使用target_link_libraries()把它们全部链接为可执行文件
# 设置链接目标 add_executable(${PROJECT_NAME}.elf ${SOURCES} ${LINKER_SCRIPT}) target_link_libraries(${PROJECT_NAME}.elf PRIVATE libapp libdsp libdata libgui libbsp libmodule) # 设置可执行文件的输出目录 set_target_properties(${PROJECT_NAME}.elf PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${BIN_DIR})
二、链接问题
1,链接缺失系统调用函数
只不过不是所有文件都能采用上面链接方法的,比如系统调用、启动文件等一同链接成一个库,此时会显示缺少各种定义,而这些缺失的定义却显然是系统调用里的函数
这个我也不晓得是什么原因,可能是单独链接这些系统调用文件成静态库时,还需要添加编译器所带的库如libgcc等。
总之把这些底层文件单独收集起来
file(GLOB_RECURSE SOURCES "Core/*.*" "Application/Base/ISR.cpp")然后添加到可执行目标中,其他地方不变
add_executable(${PROJECT_NAME}.elf ${SOURCES} ${LINKER_SCRIPT})最后再链接时就不会出现问题了
2,使用链接优化出现缺失定义的错误
如果像前面把各种库独立编译,那么在开启链接优化时,会出先下面的报错,总之就是各种找不到定义,连main都找不到
这个其实很好理解,使用-flto链接优化时,会把所有资源文件编译后再链接优化一下。那么问题就出现在了编译这块,因为LTO 无法跨静态库边界进行优化,可能导致一些符号无法正确解析。
所以需要把所有资源文件统一添加到可执行目标时,LTO 优化的范围涵盖了所有源文件,这样才能正确地处理跨文件的优化和符号解析。
当然这也与编译器和连接器有关,不同的编译器和链接器在处理 LTO 时可能有不同的行为。某些编译器在处理多个静态库时可能不够智能,无法正确处理跨库的优化。
虽然理论上可以使用-flto=full选项,但有的编译器没有这个选项
当然,还有一种解决办法,就是使用ar工具手动把各种静态库合并,比如下面把lib1.a、lib2.a、lib3.a都合并为liball.a 。
# 合并静态库 add_custom_command(OUTPUT liball.aCOMMAND ${CMAKE_AR} crs liball.a $<TARGET_FILE:lib1> $<TARGET_FILE:lib2> $<TARGET_FILE:lib3>DEPENDS lib1 lib2 lib3 )对于此处用到的编译器,上面两种方法都不如直接添加文件到可执行目标中快捷省事
include_directories(Application/Conf ${APP_DIR}${DRIVERS_DIR}${LVGL_DIR}# ${FREERTOS_DIR}${BSP_DIR}${DATA_DIR}${GUI_DIR}${MODULE_DIR}${APPLICATION_DIR})file(GLOB_RECURSE SOURCES "Core/*.*" "Application/Base/ISR.cpp"${DRIVERS_SRC}${LVGL_SRC}# ${FREERTOS_SRC}${BSP_SRC}${DATA_SRC}${GUI_SRC}${MODULE_SRC}${APPLICATION_SRC})
相关文章:
单片机工程使用链接优化-flto找不到定义_链接静态库
IDE: CLion HOST: Windows 11 MinGW:x86_64-14.2.0-release-posix-seh-ucrt-rt_v12-rev0 GCC: arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi 示例工程:https://github.com/ichliebedich-DaCapo/STM…...
UniTask/Unity的PlayerLoopTiming触发顺序
开始尝试在项目中使用UniTask,发现其中的UniTask.Yield确实很好用,还可以传入PlayerLoopTiming来更细致的调整代码时机,不过平常在Mono中接触的只有Awake,Start,Update等常用Timing,其他的就没怎么接触了&a…...
【报错记录】Steam迁移(移动)游戏报:移动以下应用的内容失败:XXX: 磁盘写入错误
前言 由于黑神话悟空,导致我的2TB的SSD系统盘快满了,我又买了一块4TB的SSD用来存放游戏,我就打算把之前C盘里的游戏移动到D盘,结果Steam移动游戏居然报错了,报的还是“磁盘写入错误”,如下图所示ÿ…...
C 语言学习-04【结构化程序设计】
1、单分支结构语句 用单分支结构进行奇偶判断: #include <stdio.h>int main() {int num;printf("Please enter an integer: ");scanf("%d", &num);if (num % 2 ! 0) {printf("%d is odd! \n", num);}if (num % 2 0) {prin…...
机器视觉:轮廓匹配算法原理
轮廓匹配的模板变量主要包括模板图像(Template)和待检测图像(Source Image) 在轮廓匹配中,模板变量主要包括一下几个关键部分: 模板图像(Template):这是进行匹配的…...
动力商城-02 环境搭建
1.父工程必须满足:1.1删除src目录 1.2pom 2.依赖继承 //里面的依赖,后代无条件继承<dependencies></dependencies>//里面的依赖,后代想要继承,得自己声明需要使用,可以不写版本号,自动继承&l…...
【react】Redux基础用法
1. Redux基础用法 Redux 是一个用于 JavaScript 应用的状态管理库,它不依赖于任何 UI库,但常用于与 React 框架配合使用。它提供了一种集中式的状态管理方式,将应用的所有状态保存在一个单一的全局 Store(存储)中&…...
使用Python分析股票价格数据并计算移动平均线的实用指南
使用Python分析股票价格数据并计算移动平均线的实用指南 在金融市场中,移动平均线(Moving Average, MA)是一种常用的技术分析工具,用于平滑价格数据,帮助投资者识别趋势。本文将详细介绍如何使用Python分析股票价格数据,并计算移动平均线。我们将通过一个实际的案例来演…...
如何解决FPS低的问题?代码优化方法有哪些?
如果你是一名游戏开发者,或者对电脑性能有所追求的用户,那么你一定遇到过帧率(FPS)低的问题。帧率低会导致游戏卡顿、画面不流畅等问题,极大地影响了用户体验。本文将从代码层面探讨FPS低的原因,并提供一些…...
QT信号和槽与自定义的信号和槽
QT信号和槽与自定义的信号和槽 1.概述 这篇文章介绍下QT信号和槽的入门知识,通过一个案例介绍如何创建信号和槽,并调用他们。 2.信号和槽使用 下面通过点击按钮关闭窗口的案例介绍如何使用信号和槽。 创建按钮 在widget.cpp文件中创建按钮代码如下 …...
LC:二分查找——杂记
文章目录 268. 丢失的数字162. 寻找峰值 268. 丢失的数字 LC将此题归类为二分查找,并且为简单题,下面记一下自己对这道题目的思考。 题目链接:268.丢失的数字 第一次看到这个题目,虽然标注的为简单,但肯定不能直接排…...
GA/T1400视图库平台EasyCVR多品牌摄像机视频平台前端监控摄像头镜头的基础知识
在现代安全监控系统中,摄像机镜头作为捕捉图像的关键组件,其选择和应用直接影响到监控图像的质量和系统的整体性能。随着技术的发展,摄像机镜头的种类和功能也在不断扩展,以适应各种复杂的监控环境和需求。对于相机成像来讲&#…...
【C++】踏上C++的学习之旅(六):深入“类和对象“世界,掌握编程的黄金法则(一)
文章目录 前言1. "面向过程"和"面向对象"的碰撞1.1 面向过程1.2 面向对象 2. "类"的引入3. "类"的定义3.1 🍉语法展示:3.2 "类"的两种定义方式3.3 "类"的命名规则 4. 类的访问限定符以及封…...
【物联网技术】ESP8266 WIFI模块在STA模式下作为TCP客户端上电自动进入透传数据模式
前言:讲解如何在ESP8266 WIFI模块在STA模式下作为TCP客户端与网络调试助手(TCP服务器)上电自动进入透传数据模式,而不需重新再发指令配置进入透传模式。 演示视频: ESP8266 WIFI模块在STA模式下作为TCP客户端上电自动进入透传数据模式 wifi模块在STA模式下作为TCP客户端相…...
重构代码之用委托替代继承
在代码重构中,用委托替代继承 是一种用于改善代码设计和提高灵活性的重要技术。它的核心思想是,将子类与父类的直接继承关系转换为委托关系,即子类不再直接继承父类,而是通过持有父类的实例来访问所需的功能。 一、为什么需要用委…...
软件设计师下午题UML15分
一、涉及到的图及对应关系 二、例题 1.用例图和类图的例题 解析及答案 2.状态图和类图的例题 3.通信图和类图例题 例题...
css background-image背景图片轮播
1、CSS背景样式有以下几种: 背景颜色(background-color):设置元素的背景颜色。背景图片(background-image):设置元素的背景图片。背景重复(background-repeat)ÿ…...
java---认识异常(详解)
还有大家来到权权的博客~欢迎大家对我的博客提出意见哦,有错误会及时改进的~点击进入我的博客主页 目录 一、异常的概念及体系结构1.1 异常的概念1.2 异常的体系结构1.3异常的分类 二、异常的处理2.1防御式编程2.2 异常的抛出2.3 异常的捕获2.3.1异常声明throws2.3.…...
Linux基础学习笔记
Linux基础学习笔记 Linux目录结构: 具体的目录结构: /bin [重点] (/usr/bin 、 /usr/local/bin) • 是Binary的缩写, 这个目录存放着最经常使用的命令 /home [重点] • 存放普通用户的主目录,在Linux中每个用户都有一个自己的目录,一…...
自动泊车端到端算法 ParkingE2E 介绍
01 算法介绍 自主泊车是智能驾驶领域中的一项关键任务。传统的泊车算法通常使用基于规则的方案来实现。因为算法设计复杂,这些方法在复杂泊车场景中的有效性较低。 相比之下,基于神经网络的方法往往比基于规则的方法更加直观和多功能。通过收集大量专家…...
国防科技大学计算机基础课程笔记02信息编码
1.机内码和国标码 国标码就是我们非常熟悉的这个GB2312,但是因为都是16进制,因此这个了16进制的数据既可以翻译成为这个机器码,也可以翻译成为这个国标码,所以这个时候很容易会出现这个歧义的情况; 因此,我们的这个国…...
Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
【JavaSE】绘图与事件入门学习笔记
-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角,以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。 坐标体系-像素 …...
算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...
scikit-learn机器学习
# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...
Linux操作系统共享Windows操作系统的文件
目录 一、共享文件 二、挂载 一、共享文件 点击虚拟机选项-设置 点击选项,设置文件夹共享为总是启用,点击添加,可添加需要共享的文件夹 查询是否共享成功 ls /mnt/hgfs 如果显示Download(这是我共享的文件夹)&…...
验证redis数据结构
一、功能验证 1.验证redis的数据结构(如字符串、列表、哈希、集合、有序集合等)是否按照预期工作。 2、常见的数据结构验证方法: ①字符串(string) 测试基本操作 set、get、incr、decr 验证字符串的长度和内容是否正…...


