当前位置: 首页 > 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})

 

http://www.lryc.cn/news/480338.html

相关文章:

  • UniTask/Unity的PlayerLoopTiming触发顺序
  • 【报错记录】Steam迁移(移动)游戏报:移动以下应用的内容失败:XXX: 磁盘写入错误
  • C 语言学习-04【结构化程序设计】
  • 机器视觉:轮廓匹配算法原理
  • 动力商城-02 环境搭建
  • 【react】Redux基础用法
  • 使用Python分析股票价格数据并计算移动平均线的实用指南
  • 如何解决FPS低的问题?代码优化方法有哪些?
  • QT信号和槽与自定义的信号和槽
  • LC:二分查找——杂记
  • GA/T1400视图库平台EasyCVR多品牌摄像机视频平台前端监控摄像头镜头的基础知识
  • 【C++】踏上C++的学习之旅(六):深入“类和对象“世界,掌握编程的黄金法则(一)
  • 【物联网技术】ESP8266 WIFI模块在STA模式下作为TCP客户端上电自动进入透传数据模式
  • 重构代码之用委托替代继承
  • 软件设计师下午题UML15分
  • css background-image背景图片轮播
  • java---认识异常(详解)
  • Linux基础学习笔记
  • 自动泊车端到端算法 ParkingE2E 介绍
  • 《手写Spring渐进式源码实践》实践笔记(第十七章 数据类型转换)
  • W3C HTML 活动
  • 机器学习—为什么我们需要激活函数
  • 软考系统架构设计师论文:论软件的可靠性评价
  • C++:线程(thread)的创建、调用及销毁
  • 关于随身wifi,看了再决定要不要买!2024年最受欢迎的随身wifi品牌推荐!
  • SpringMVC总结 我的学习笔记
  • DevCheck Pro手机硬件检测工具v5.33
  • 数据分析ReAct工作流
  • Rust-AOP编程实战
  • Flutter鸿蒙next 中的 Expanded 和 Flexible 使用技巧详解