《CMake 构建实战—项目开发卷》—实战分享1-QCC74x SDK 编译
<div class='showpostmsg'> 本帖最后由 CoderX9527 于 2024-9-29 16:18 编辑<div> </div>
<h1>SDK介绍</h1>
<div>qcc74xSDK 是由 Qualcomm 为 qcc74x 系列芯片提供的 IOT 和 MCU 开发套件。</div>
<div>代码仓库地址如下:</div>
<div><a href="https://git.codelinaro.org/clo/qcc7xx/QCCSDK-QCC74x">https://git.codelinaro.org/clo/qcc7xx/QCCSDK-QCC74x</a></div>
<div>此仓库包含源码和编译工具,但是文档匮乏,并未描述如何编译。</div>
<div>我在阅读《CMake 构建实战—项目开发卷》时下载了此SDK,折腾了一番,终于摸索出如何编译此工程,仅以此文作为纪念。</div>
<h1>编译框架介绍</h1>
<h2>编译工具链</h2>
<div>位于 QCCSDK-QCC74x/toolchain 下的 riscv64-unknown-elf-gcc 工具链。支持 linux/windows 两个平台。</div>
<div>linux 下的工具链如下图所示</div>
<div></div>
<div>windows 下的工具链如下图所示:</div>
<div></div>
<h2>编译方法</h2>
<div>SDK 目录下的 README.md 文件已有说明,以编译 examples/helloword 为例;</div>
<div>cd examples/helloworld</div>
<div>make CHIP=qcc743 BOARD=qcc743dk</div>
<div>然而编译报错,提示 riscv64-unknown-elf-gcc 工具路径未找到。</div>
<h2>框架介绍</h2>
<div>虽然是从命令行调用 make 开始编译,但是这个SDK的编译框架比较复杂,从 make 读取 examples/helloworld/Makefile 开始,配置 CMake 环境,并由CMake生成 examples/helloworld/build/Makefile ,然后继续执行 Make 命令处理 examples/helloworl/build/Makefile 文件开始编译。</div>
<h1>Linux 环境下编译</h1>
<div>在 examples/helloworld 目录输入命令 make 报错</div>
<div></div>
<div>即所需的编译工具链 riscv64-unknown-elf-gcc 找不到。</div>
<div>编译工具链找不到的解决办法</div>
<div>export PATH=$PATH:$HOME/workspace/QCC74x/QCCSDK-QCC74x-master/toolchain/linux_x86_64/bin</div>
<div>再次输入命令 make 开始编译,编译成功。</div>
<div></div>
<div>编译通过,生成 elf 文件为 helloworld_gcc743.elf 并生成对应的 bin 文件。</div>
<div></div>
<div>但是不仅仅只是生成elf 和对应的 bin 文件,还执行了 post build 指定的其他几个编译产物。</div>
<div></div>
<h1>Windows 环境下编译</h1>
<div>进入 examples/helloworld 输入命令 make编译报错,找不到工具链 riscv64-unknown-elf-gcc</div>
<div></div>
<div>解决办法,临时把 riscv64-unknown-elf-gcc 所在路径添加到PATH 环境变量中。</div>
<div></div>
<div><strong>虽然我曾更改过系统的 </strong><strong>PATH </strong><strong>路径,但是奇怪的是在命令行并未生效</strong>。重新打开 VSCode 或者新打开 CMD 窗口,都不生效。只能临时添加到 PATH 变量中,此方法生效了。</div>
<div></div>
<div></div>
<div></div>
<div>编译完成生产 elf 和对应的 bin 文件。</div>
<div></div>
<div>继续执行 post build 动作,生成其他编译产物。</div>
<div></div>
<div></div>
<h1>编译流程解析</h1>
<div>参见我总结的流程图《QCC74x编译流程解析.png》</div>
<div></div>
<h2>第一步 进入 examples/helloworld 目录,make Makefile 文件</h2>
<div></div>
<h2>第二步 helloworld/Makefile 引入 sdk/project.build 文件</h2>
<div></div>
<h2>第三步 又从 helloworld/CMakeLists.txt 文件开始处理 cmake脚本</h2>
<div></div>
<h2>第四步 上一步中的 helloworld/CMakeLists.txt 文件查找 qcc74xsdk 进而处理 sdk/CMakeLists.txt</h2>
<div></div>
<h1>编译流程总结</h1>
<div>第一次遇见这么复杂的构建流程,总体来说是 make helloworld/Makefile 调用CMake 生成helloworld/build/Makefile make helloworld/build/Makefile。在 make 和 cmake 工具之间反复调用,生成最终的产物。</div>
<div>每一个示例工程目录下,例如 examples/helloworld 文件夹下都有入口 Makefile,也有 CMakeLists.txt。其中 Makefile 中传递一些参数给 project.build 文件,最终调用 cmake 处理 helloworld/CMakeList.stxt 生成最终的配置文件 helloworld/build/Makefile,所有的构建目标和编译后的 post_build 动作都在这个 Makefile 文件中。巧妙、但是复杂。</div>
<div>对于 CMake 新手来说,sdk/cmake 目录下的 CMake 模块文件非常巧妙,有些晦涩难懂。特别是 extension.cmake 模块,定义了很多宏和函数,宏 sdk_set_main_file 和 project 非常巧妙。</div>
<div>sdk_set_main_file() 宏,注意宏中定义的变量对包含这个宏的文件都有效,因此下面的宏 project() 可以直接使用变量 CURRENT_MAIN_FILE。第一次读到这段代码让人迷糊了一阵子。</div>
<div></div>
<div>需要注意的是 project() 已经重定义了,覆盖了原来的定义,但是在里面调用了 _project() 。</div>
<h1>疑问</h1>
<div>不知道宏定义 project 覆盖原来的 CMake 命令,再调用 _project() 这种用法是否合理。chatGPT 也没能给出满意的答案。</div>
<div>似乎用下面 chatGPT 推荐的方法更合适:</div>
<div># 定义一个自定义宏,避免与 CMake 的 project() 冲突</div>
<div>macro(my_project name)</div>
<div># 调用 CMake 的标准 project() 命令</div>
<div>project(${name})</div>
<div># 这里可以加入一些自定义的逻辑,比如打印项目名称</div>
<div>message(STATUS "Project name set to: ${name}")</div>
<div>endmacro()</div>
<div># 使用自定义的宏</div>
<div>my_project(MyApp)</div>
<div> </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> <p>了解一下,准备学习</p>
页:
[1]