CoderX9527 发表于 2024-10-30 19:21

《CMake 构建实战-项目开发卷》实战分享3—从零开始给MCU项目增加CMake支持

<div class='showpostmsg'><div>&nbsp;</div>

<h1>背景</h1>

<div>我在芯片原厂做BSP开发,公司的项目原本只支持Keil MDK AC6编译器,领导让我增加个GCC编译器支持。当前我先增加了第一个版本的 CMake + GCC 编译支持,并且在 VS Code 中可以调用 J-Link 调试器进行调试,后续再完善 CMake 目录结构。</div>

<h1>搭建嵌入式MCU 编译环境</h1>

<div>安装软件清单</div>

<ol>
        <li>GCC 编译器,这里以 2021.10 版本为例;</li>
        <li>CMake 工具,这里以 v3.28.1 为例;</li>
        <li>Ninja 或者 Make 工具,这里安装 ninja 绿色版本;</li>
        <li>JLink V752d,烧写程序、调试程序</li>
</ol>

<h2>安装 GCC 编译器</h2>

<div>文件 gcc-arm-none-eabi-10.3-2021.10-win32.exe 可以从 ARM Developer 官网下载,地址如下:</div>

<div><a href="https://developer.arm.com/downloads/-/gnu-rm/10-3-2021-10">https://developer.arm.com/downloads/-/gnu-rm/10-3-2021-10</a></div>

<div>下载后双击安装,一路 NEXT,安装到 &ldquo;C:\Program Files (x86)\GNU Arm Embedded Toolchain\10 2021.10\bin&rdquo; 目录下。安装结束打开一个新的命令行窗口输入 &ldquo;arm-none-eabi-gcc.exe --version&rdquo; 检查是否看到正确的版本信息。</div>

<div></div>

<div>如果没有,就把此目录添加到系统环境变量 PATH 中。(后续各个软件也需要把安装路径添加到 PATH 变量中)</div>

<h2>安装 CMake 工具</h2>

<div>从 CMake 官网下载最新的版本,我这里以 3.28.1 版本为例。</div>

<div>点击安装,一路 NEXT 即可。</div>

<div></div>

<h2>安装 Ninja 工具</h2>

<div>ninja 是一个绿色软件,github 官方释放地址为:<a href="https://github.com/ninja-build/ninja/releases">https://github.com/ninja-build/ninja/releases</a></div>

<div>它的作用和 make 一样,区别是 make 读取 Makefile 文件调用编译器命令,而 ninja 读取 build.ninja 文件调用编译器命令,而且 ninja 没有隐含规则,编译速度更快。</div>

<div>解压 ninja 到某个磁盘,然后添加到系统 PATH 路径,打开新的命令行输入 &ldquo;ninja --version&rdquo; 检查版本。</div>

<div></div>

<h2>安装 JLink V752d</h2>

<div>从 Segger 官网下载,点击安装一路 NEXT 即可。</div>

<h1>编写 CMake</h1>

<div>编写 CMake 目录程序,围绕着以下几点:</div>

<ol>
        <li>编译器配置:设定编译工具链路径,二进制文件和库文件输出路径;</li>
        <li>针对处理器的编译选项:即C编译选项,针对处理器的宏定义,调试选项,链接脚本路径;</li>
        <li>二进制目标文件的规则,库文件的导入导出:一般要指定可执行文件依赖源文件、头文件、库文件的路径;</li>
        <li>编译后的elf/bin文件处理:即 elf/axf 如何加工生成 bin 文件,如何生成反汇编文件,以及调用外部工具处理 bin 文件;</li>
</ol>

<div>这里直接列出工程修改后的大致结构:</div>

<ol>
        <li>cmake 目录,存放 cmake 模块文件;</li>
        <li>test 目录,有一个 CMakeLists.txt 文件,实际上它继续添加下面的 testcase 目录,指导包含可执行文件所在目录;</li>
        <li>链接脚本,这里有两个链接脚本,区分运行在Flash和 RAM 版本;</li>
        <li>CMakeLists.txt 主目录文件,工程入口</li>
</ol>

<div></div>

<h2>cmake 目录中的模块文件</h2>

<div>简单介绍此目录中的4个文件。</div>

<h3>functions.cmake</h3>

<div>定义了一些 cmake 通用函数,例如:</div>

<div></div>

<h3>gcc_compiler_flags.cmake</h3>

<div>定义了编译选项,包括针对处理器的选项,通用选项、调试选项以及链接器选项。下图仅截取一部分:</div>

<div></div>

<h3>gcc_custom_build.cmake</h3>

<div>定义了一些自定义目标,用来处理 axf/elf 文件到 bin 文件的转换。</div>

<div>这个文件用到了生成器语法和 CMAKE 命令(跨平台),比写 Makefile 方便多了。</div>

<div></div>

<h3>gcc_toolchain_setup.cmake</h3>

<div>此文件定义了编译工具链路径。</div>

<div></div>

<h2>主目录 CMakeLists.txt 文件</h2>

<div>此文件太长了,就不截图了。大致可以分为以下几个部分:</div>

<ol>
        <li>导入 cmake/ 目录下的模块;</li>
        <li>调用 add_executable() 新增一个二进制构建目标,但是还没有增加源文件路径;</li>
        <li>调用 include_directories() 为工程设置全局的头文件搜索路径;</li>
        <li>调用 add_subdirectory(test) 把子目录加进来;</li>
        <li>调用 include(cmake/gcc_custom_build.cmake) 设定编译后的 elf/axf 文件处理规则;</li>
</ol>

<h2>可执行文件指定源文件</h2>

<div>前面说了顶层目录的 CMakeLists.txt 文件仅添加了可执行文件目标,但是没有指定源文件。通过调用 add_subdirectory() 层层依赖,最终到了我们的示例工程,文件内容如下:</div>

<div></div>

<ol>
        <li>使用 file(GLOB_RECURSE) 命令搜索当前目录下的C源程序添加到 USER_APP_SRCS 变量中;</li>
        <li>设置 APP_DEP_SRCS 变量,加入GCC 版本的启动文件、system 文件以及标准输入输出重定向文件;</li>
        <li>调用 target_sources() 命令为最终的可执行目标设置源文件路径。</li>
</ol>

<h2>编译后的动作</h2>

<div>见上面的 gcc_custom_build.cmake 文件,调用编译工具链中的命令把 elf/axf 文件转换为 hex/bin 文件,并生成反汇编文件。</div>

<h1>调试支持</h1>

<div>VS Code 安装 Cortex-Debug 插件。</div>

<div>然后先点击(1)处的 Run and Debug 按钮,在点击(2)处的齿轮,配置调试选项。</div>

<div></div>

<div>在打开的 launch.json 文件输入以下内容,配置调试文件为 RADAR_CHIPX.elf 文件,调试器类型为 jlink,调试器接口为 swd,并配置进入调试时要执行的 JLink 命令。</div>

<div></div>

<h1>运行</h1>

<div>JLink 链接电脑和开发板之后,按 F5 键开始调试。</div>

<div>刚进入调试模式会弹出 TERMINAL 窗口,打印 JLink 调试器加载信息</div>

<div></div>

<div>然后 DEBUG CONSOLE 窗口会打印 JLink 调试器执行命令的信息</div>

<div></div>

<div>最后成功进入 main() 函数并打印信息</div>

<div></div>

<div></div>

<h1>总结</h1>

<div>编写 CMake 程序,主要是指定源文件、头文件、库文件路径,设置编译器选项、链接器参数等。当然还需要注意链接脚本设置的启动文件。</div>

<div>这个项目是为了赶时间所以CMake程序写的潦草,后期可以参考我的第一个分享 QCC74x SDK 的写法虽然复杂,但是每个example 都可以独立进入编译,而我这个项目需要修改顶层目录中的 CMakeLists.txt 文件,修改一个全局变量,有点麻烦。</div>

<div>多学习其他SDK的CMake写法,从实战中收获新知识。</div>

<div>&nbsp;</div>

<div>&nbsp;</div>

<p><!--importdoc--></p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

freebsder 发表于 2024-10-31 11:42

<p>谢谢分享,期待后续!</p>
页: [1]
查看完整版本: 《CMake 构建实战-项目开发卷》实战分享3—从零开始给MCU项目增加CMake支持