当前位置: 首页 > news >正文

单片机工程使用链接优化-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&#xff1a; CLion HOST&#xff1a; Windows 11 MinGW&#xff1a;x86_64-14.2.0-release-posix-seh-ucrt-rt_v12-rev0 GCC&#xff1a; arm-gnu-toolchain-13.3.rel1-mingw-w64-i686-arm-none-eabi 示例工程&#xff1a;https://github.com/ichliebedich-DaCapo/STM…...

UniTask/Unity的PlayerLoopTiming触发顺序

开始尝试在项目中使用UniTask&#xff0c;发现其中的UniTask.Yield确实很好用&#xff0c;还可以传入PlayerLoopTiming来更细致的调整代码时机&#xff0c;不过平常在Mono中接触的只有Awake&#xff0c;Start&#xff0c;Update等常用Timing&#xff0c;其他的就没怎么接触了&a…...

【报错记录】Steam迁移(移动)游戏报:移动以下应用的内容失败:XXX: 磁盘写入错误

前言 由于黑神话悟空&#xff0c;导致我的2TB的SSD系统盘快满了&#xff0c;我又买了一块4TB的SSD用来存放游戏&#xff0c;我就打算把之前C盘里的游戏移动到D盘&#xff0c;结果Steam移动游戏居然报错了&#xff0c;报的还是“磁盘写入错误”&#xff0c;如下图所示&#xff…...

C 语言学习-04【结构化程序设计】

1、单分支结构语句 用单分支结构进行奇偶判断&#xff1a; #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…...

机器视觉:轮廓匹配算法原理

轮廓匹配的模板变量主要包括模板图像&#xff08;Template&#xff09;和待检测图像&#xff08;Source Image&#xff09; 在轮廓匹配中&#xff0c;模板变量主要包括一下几个关键部分&#xff1a; ‌模板图像&#xff08;Template&#xff09;‌&#xff1a;这是进行匹配的…...

动力商城-02 环境搭建

1.父工程必须满足&#xff1a;1.1删除src目录 1.2pom 2.依赖继承 //里面的依赖&#xff0c;后代无条件继承<dependencies></dependencies>//里面的依赖&#xff0c;后代想要继承&#xff0c;得自己声明需要使用&#xff0c;可以不写版本号&#xff0c;自动继承&l…...

【react】Redux基础用法

1. Redux基础用法 Redux 是一个用于 JavaScript 应用的状态管理库&#xff0c;它不依赖于任何 UI库&#xff0c;但常用于与 React 框架配合使用。它提供了一种集中式的状态管理方式&#xff0c;将应用的所有状态保存在一个单一的全局 Store&#xff08;存储&#xff09;中&…...

使用Python分析股票价格数据并计算移动平均线的实用指南

使用Python分析股票价格数据并计算移动平均线的实用指南 在金融市场中,移动平均线(Moving Average, MA)是一种常用的技术分析工具,用于平滑价格数据,帮助投资者识别趋势。本文将详细介绍如何使用Python分析股票价格数据,并计算移动平均线。我们将通过一个实际的案例来演…...

如何解决FPS低的问题?代码优化方法有哪些?

如果你是一名游戏开发者&#xff0c;或者对电脑性能有所追求的用户&#xff0c;那么你一定遇到过帧率&#xff08;FPS&#xff09;低的问题。帧率低会导致游戏卡顿、画面不流畅等问题&#xff0c;极大地影响了用户体验。本文将从代码层面探讨FPS低的原因&#xff0c;并提供一些…...

QT信号和槽与自定义的信号和槽

QT信号和槽与自定义的信号和槽 1.概述 这篇文章介绍下QT信号和槽的入门知识&#xff0c;通过一个案例介绍如何创建信号和槽&#xff0c;并调用他们。 2.信号和槽使用 下面通过点击按钮关闭窗口的案例介绍如何使用信号和槽。 创建按钮 在widget.cpp文件中创建按钮代码如下 …...

LC:二分查找——杂记

文章目录 268. 丢失的数字162. 寻找峰值 268. 丢失的数字 LC将此题归类为二分查找&#xff0c;并且为简单题&#xff0c;下面记一下自己对这道题目的思考。 题目链接&#xff1a;268.丢失的数字 第一次看到这个题目&#xff0c;虽然标注的为简单&#xff0c;但肯定不能直接排…...

GA/T1400视图库平台EasyCVR多品牌摄像机视频平台前端监控摄像头镜头的基础知识

在现代安全监控系统中&#xff0c;摄像机镜头作为捕捉图像的关键组件&#xff0c;其选择和应用直接影响到监控图像的质量和系统的整体性能。随着技术的发展&#xff0c;摄像机镜头的种类和功能也在不断扩展&#xff0c;以适应各种复杂的监控环境和需求。对于相机成像来讲&#…...

【C++】踏上C++的学习之旅(六):深入“类和对象“世界,掌握编程的黄金法则(一)

文章目录 前言1. "面向过程"和"面向对象"的碰撞1.1 面向过程1.2 面向对象 2. "类"的引入3. "类"的定义3.1 &#x1f349;语法展示&#xff1a;3.2 "类"的两种定义方式3.3 "类"的命名规则 4. 类的访问限定符以及封…...

【物联网技术】ESP8266 WIFI模块在STA模式下作为TCP客户端上电自动进入透传数据模式

前言:讲解如何在ESP8266 WIFI模块在STA模式下作为TCP客户端与网络调试助手(TCP服务器)上电自动进入透传数据模式,而不需重新再发指令配置进入透传模式。 演示视频: ESP8266 WIFI模块在STA模式下作为TCP客户端上电自动进入透传数据模式 wifi模块在STA模式下作为TCP客户端相…...

重构代码之用委托替代继承

在代码重构中&#xff0c;用委托替代继承 是一种用于改善代码设计和提高灵活性的重要技术。它的核心思想是&#xff0c;将子类与父类的直接继承关系转换为委托关系&#xff0c;即子类不再直接继承父类&#xff0c;而是通过持有父类的实例来访问所需的功能。 一、为什么需要用委…...

软件设计师下午题UML15分

一、涉及到的图及对应关系 二、例题 1.用例图和类图的例题 解析及答案 2.状态图和类图的例题 3.通信图和类图例题 例题...

css background-image背景图片轮播

1、CSS背景样式有以下几种&#xff1a; 背景颜色&#xff08;background-color&#xff09;&#xff1a;设置元素的背景颜色。背景图片&#xff08;background-image&#xff09;&#xff1a;设置元素的背景图片。背景重复&#xff08;background-repeat&#xff09;&#xff…...

java---认识异常(详解)

还有大家来到权权的博客~欢迎大家对我的博客提出意见哦&#xff0c;有错误会及时改进的~点击进入我的博客主页 目录 一、异常的概念及体系结构1.1 异常的概念1.2 异常的体系结构1.3异常的分类 二、异常的处理2.1防御式编程2.2 异常的抛出2.3 异常的捕获2.3.1异常声明throws2.3.…...

Linux基础学习笔记

Linux基础学习笔记 Linux目录结构&#xff1a; 具体的目录结构: /bin [重点] (/usr/bin 、 /usr/local/bin) • 是Binary的缩写, 这个目录存放着最经常使用的命令 /home [重点] • 存放普通用户的主目录&#xff0c;在Linux中每个用户都有一个自己的目录&#xff0c;一…...

自动泊车端到端算法 ParkingE2E 介绍

01 算法介绍 自主泊车是智能驾驶领域中的一项关键任务。传统的泊车算法通常使用基于规则的方案来实现。因为算法设计复杂&#xff0c;这些方法在复杂泊车场景中的有效性较低。 相比之下&#xff0c;基于神经网络的方法往往比基于规则的方法更加直观和多功能。通过收集大量专家…...

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

Spring Boot面试题精选汇总

&#x1f91f;致敬读者 &#x1f7e9;感谢阅读&#x1f7e6;笑口常开&#x1f7ea;生日快乐⬛早点睡觉 &#x1f4d8;博主相关 &#x1f7e7;博主信息&#x1f7e8;博客首页&#x1f7eb;专栏推荐&#x1f7e5;活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

Aspose.PDF 限制绕过方案:Java 字节码技术实战分享(仅供学习)

Aspose.PDF 限制绕过方案&#xff1a;Java 字节码技术实战分享&#xff08;仅供学习&#xff09; 一、Aspose.PDF 简介二、说明&#xff08;⚠️仅供学习与研究使用&#xff09;三、技术流程总览四、准备工作1. 下载 Jar 包2. Maven 项目依赖配置 五、字节码修改实现代码&#…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...

02.运算符

目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&&#xff1a;逻辑与 ||&#xff1a;逻辑或 &#xff01;&#xff1a;逻辑非 短路求值 位运算符 按位与&&#xff1a; 按位或 | 按位取反~ …...