CMake构建CCS工程与EMCV编译

  这两天折腾了一些不是那么有用的东西,用CMake构建CCS工程,以及编译EMCV Library(嵌入式计算机视觉库)。为什么说不是那么有用呢?因为虽然可以用CMake编译TI的CCS工程,但是调试还是离不开CCS。用CMake只是让程序编写的开发环境变得轻便了,可以在VS Code的界面下完成代码编写和编译,但最后Emulation还是得用CCS。另外,EMCV是OpenCV1.x移植到C6000 DSP上的计算机视觉库,一开始我没注意OpenCV的版本,原以为现有的软件算法能够比较方便地移植到DSP上,但是OpenCV1.x基本已经没有人用了,数据类型的定义和OpenCV3有较大的差别,所以我暂时还没有用上这个库,只是编译了一下。

CMake入门

  我现在用的CMake是3.22.1版本,网上有很多CMake的教程,官网的教程挺好的,从建立工程,到添加库,package,install,export可以说把编译C/C++工程的方方面面都涉及了。但也正是因为它覆盖全面,所以它不可能方方面面都讲得很详细。
  在看的时候建议同时翻看“cmake-commands”、“cmake-properties”和“cmake-variables”的文档。因为教程里面只说了用什么命令,但是没有具体介绍这个命令里面每个参数的含义。另外也需要多查阅“Reference Manuals”里的其它文档。目前我觉得比较常用的命令有这些:

命令作用
cmake_minimum_required这个在写顶层CMakeLists的时候需要用到,指定cmake的最低需求版本
option添加编译的选项,可以用变量控制生成不同需求的工程
project创建工程,这个必须有,但我一开始经常忘
add_subdirectory添加子目录,有顶层CMakeLists自然有次一层的CMakeLists,这个命令可以用来管理整个目录的所有源文件
add_executable/add_library添加target,指定要编译的目标。编译可执行文件或者编译库。
file(GLOB …)将目录下的符合给定glob表达式的文件名存到一个list里。还有GLOB_RECURSE也常用,可以递归搜索文件。这个在源文件或者头文件很多的情况下很有用
target_include_directories目标的头文件路径
target_link_directories目标的需要链接的文件所在的路径
install指明需要安装的东西,在执行install的时候会将指定的文件放到给定的目录下面

  CMake的语法以及命令的参数官网的文档上都有,每次用的时候多查阅一下自然就记住了。在大概熟悉CMake之后可以VS Code里的CMake Tools插件用起来,这个插件省去了cmake-gui的操作,cmake的configure、generate、build、install包括test都有非常好的支持。相关的设置可以通过settings.json来完成,不好的地方就是它可以设置的变量没有cmake-gui那么可以直观地看到,对自定义的kit支持不是很好,但不管怎样它都已经很强大了。

CMake交叉编译

  在cmake-gui中选择generator,比如确定MinGW或者MSVC,那么CMake自然能够知道用什么编译指令来编译什么类型的源文件或者对目标文件进行链接。但是如果不是它默认支持的编译器,它怎么知道该怎样编译呢?比如TI的编译器,CMake能支持吗?
在这里插入图片描述

CMake支持TI的编译器吗?

  支持。下面是在编译成功后,Makefile依赖的cmake文件。其中的“TI.cmake”就给出了命令的格式。

# The top level Makefile was generated from the following files:
set(CMAKE_MAKEFILE_DEPENDS
  "CMakeCache.txt"
  "C:/Program Files/CMake/share/cmake-3.22/Modules/CMakeCInformation.cmake"
  "C:/Program Files/CMake/share/cmake-3.22/Modules/CMakeCXXInformation.cmake"
  "C:/Program Files/CMake/share/cmake-3.22/Modules/CMakeCommonLanguageInclude.cmake"
  "C:/Program Files/CMake/share/cmake-3.22/Modules/CMakeGenericSystem.cmake"
  "C:/Program Files/CMake/share/cmake-3.22/Modules/CMakeInitializeConfigs.cmake"
  "C:/Program Files/CMake/share/cmake-3.22/Modules/CMakeLanguageInformation.cmake"
  "C:/Program Files/CMake/share/cmake-3.22/Modules/CMakeSystemSpecificInformation.cmake"
  "C:/Program Files/CMake/share/cmake-3.22/Modules/CMakeSystemSpecificInitialize.cmake"
  "C:/Program Files/CMake/share/cmake-3.22/Modules/Compiler/CMakeCommonCompilerMacros.cmake"
  "C:/Program Files/CMake/share/cmake-3.22/Modules/Compiler/TI-C.cmake"
  "C:/Program Files/CMake/share/cmake-3.22/Modules/Compiler/TI-CXX.cmake"
  "C:/Program Files/CMake/share/cmake-3.22/Modules/Compiler/TI.cmake"
  "C:/Program Files/CMake/share/cmake-3.22/Modules/Platform/Generic.cmake"
  "D:/PrjCCS_CMake/Hello/CMakeLists.txt"
  "CMakeFiles/3.22.1/CMakeCCompiler.cmake"
  "CMakeFiles/3.22.1/CMakeCXXCompiler.cmake"
  "CMakeFiles/3.22.1/CMakeSystem.cmake"
  "D:/PrjCCS_CMake/toolchain.cmake"
  )

  一开始我在网上找各种用CMake编译CCS工程的方法,但是都没有比较详细的说法,后来我就在CMake的安装目录下找。最后在Modules目录下找到了一个CMakeAddNewLanguage.txt的文件,后来又摸索了一下大概明白只需要设定编译器的名称,它就能知道需要用什么样的编译命令以及编译器的一些feature。比如我设置编译器的名称里包含cl6x,CMake就能知道这是TI的C6000系列的编译器,支持C89和C++98。

工具链设置

  官方文档中介绍,可以给CMake指定一个toolchain file,这个文件里的设置会被比较早地加载。
  交叉编译的关键是手动设置CMAKE_SYSTEM_NAME这个变量,这个变量表示目标设备的名称,这个变量也不是随便设置的,一般是Modules/Platform目录下的一些前缀,没有操作系统的裸核开发一般都设置成“Generic”。

# toolchain.cmake
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_VERSION 1.0)
set(CMAKE_SYSTEM_PROCESSOR tidsp)

set(C6000_CG_ROOT C:/ti/ccs620/ccsv6/tools/compiler/c6000_7.4.4)
set(CMAKE_C_COMPILER "${C6000_CG_ROOT}/bin/cl6x.exe")
set(CMAKE_CXX_COMPILER "${C6000_CG_ROOT}/bin/cl6x.exe")

set(CMAKE_FIND_ROOT_PATH ${C6000_CG_ROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)

include_directories("${C6000_CG_ROOT}/include")
link_directories("${C6000_CG_ROOT}/lib")

set(CMAKE_C_FLAGS " \
    -mv6600 \
    --abi=eabi \
    --diag_wrap=off \
    --diag_warning=225 \
    --display_error_number")

set(CMAKE_CXX_FLAGS " \
    -mv6600 \
    --abi=eabi \
    --diag_wrap=off \
    --diag_warning=225 \
    --display_error_number")

add_link_options("--rom_model")

  上面是我的toolchain的设置,结合TI的编译器的文档,参考CCS的编译和链接的命令,为编译C和C++文件分别添加的相应的flags。链接是在编译的基础上增加选项,就是链接的时候实际上也用到了前面的编译用的flag。

简单示例

  用最简单的Helloworld来演示,用一份源文件生成TI DSP的目标文件和Windows上的可执行文件。下面是我的源文件目录下的CMakeLists,用变量BUILD_CCS_PROJECT变量来控制生成什么类型的工程。

# CMakeLists.txt
cmake_minimum_required(VERSION 3.22)

option(BUILD_CCS_PROJECT "build ccs project" ON)

project(hello)

if(BUILD_CCS_PROJECT)
    add_executable(hello.out hello.cpp lnk.cmd)
    set_property(SOURCE lnk.cmd PROPERTY EXTERNAL_OBJECT True)
else()
    add_executable(hello hello.cpp)
endif()

cl6x编译

  首先是利用cl6x进行编译,这里值得注意的是,DSP工程里一般都有一个链接脚本文件“xxx.cmd”,在这里我们需要将它当作一个外部输入的object来参与编译,cl6x会自动分辨是object还是链接脚本。下图是用在CCS中打开Terminal,然后在另一个路径“Hello_CCS”下用gmake编译的结果。
在这里插入图片描述
  当时在toolchain设置文件里,在编译的flag里加了“-g”的选项,所以这个编译的结果能拿来在线仿真。下图是上板调试的结果。
在这里插入图片描述

MinGW编译

  然后是利用MinGW进行编译和运行,也得到了正确的结果。
在这里插入图片描述

EMCV(Embedded Computer Vision Library)

  本来准备做软件算法到DSP的移植,然后软件算法中用到了OpenCV3,我本来想,要是DSP也有类似的OpenCV的库就好了,然后就在网上找到了这个EMCV,本来以为这样子移植的工作能轻松很多,但是后来发现这个库是在OpenCV1.x基础上移植的,而OpenCV1和OpenCV3对于数据类型的定义就相差很大,所以我之前的想法是基本上用不上了,还是得自己去相应的数据类型。而且不光是这样,cl6x对C++的支持情况也有待确认。
  EMCV的代码是2013年Yu Shiqi在SourceForge上传的,源代码链接。我用7.4.4版本的cl6x编译器编译后修改了一些小问题。
  一个是下面的类型定义,CvFuncTable是一个用来存放函数指针的结构体,所以应该改成下面这样,而不是void类型的数据指针。这里改了之后,其它相关的地方用(void*)的强制类型转换也需要改为用(void(*)())进行强制函数指针类型转换。

// cxcore/cxmisc.h
...
typedef struct CvFuncTable
{
   // void*   fn_2d[CV_DEPTH_MAX];
   void(*fn_2d[CV_DEPTH_MAX])();
}
CvFuncTable;
...

  另一个改的地方是下面这个EXIT代码无法运行到这里,可以删去。

// cxsumpixels.cpp
...
if( CV_IS_MATND(mat) )
{
    CV_ERROR( CV_StsBadArg, "Only mat are supported here" );
    // EXIT; can't reach
}
...

  修改后的以及用CMakeLists管理的EMCV源码已经上传至Gitee:链接

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,下面是一个使用CMake构建C++工程的示例。 我们假设这个工程有如下目录结构: ``` . ├── CMakeLists.txt ├── include │ └── mylib.h ├── src │ ├── main.cpp │ └── mylib.cpp └── test ├── CMakeLists.txt └── mylib_test.cpp ``` 其中: - `include` 目录包含头文件 `mylib.h` - `src` 目录包含源文件 `main.cpp` 和 `mylib.cpp` - `test` 目录包含测试代码 `mylib_test.cpp` 下面是 `CMakeLists.txt` 文件的内容: ```cmake # 设置 CMake 最低版本需求 cmake_minimum_required(VERSION 3.10) # 设置项目名称和版本号 project(myproject VERSION 1.0) # 设置 C++ 标准 set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) # 添加一个库 target,包含 mylib.cpp 和 mylib.h add_library(mylib src/mylib.cpp include/mylib.h) # 添加一个可执行文件 target,包含 main.cpp,以及 mylib 库 add_executable(myapp src/main.cpp) target_link_libraries(myapp PRIVATE mylib) # 添加一个测试 target,包含 mylib_test.cpp,以及 mylib 库 enable_testing() find_package(GTest REQUIRED) add_executable(mylib_test test/mylib_test.cpp) target_link_libraries(mylib_test PRIVATE mylib GTest::GTest GTest::Main) add_test(NAME mylib_test COMMAND mylib_test) ``` 其中: - `cmake_minimum_required(VERSION 3.10)` 声明了本工程需要 CMake 最低版本 3.10。 - `project(myproject VERSION 1.0)` 声明了本工程的名称和版本号。 - `set(CMAKE_CXX_STANDARD 11)` 设置了 C++ 标准为 C++11。 - `add_library(mylib src/mylib.cpp include/mylib.h)` 添加了一个名为 `mylib` 的库 target,包含 `mylib.cpp` 和 `mylib.h`。 - `add_executable(myapp src/main.cpp)` 添加了一个名为 `myapp` 的可执行文件 target,包含 `main.cpp` 和 `mylib` 库。 - `enable_testing()` 启用了测试功能。 - `find_package(GTest REQUIRED)` 查找 Google Test 库。 - `add_executable(mylib_test test/mylib_test.cpp)` 添加了一个名为 `mylib_test` 的测试 target,包含 `mylib_test.cpp` 和 `mylib` 库。 - `target_link_libraries(mylib_test PRIVATE mylib GTest::GTest GTest::Main)` 将 `mylib` 和 `GTest` 库链接到 `mylib_test` 中。 - `add_test(NAME mylib_test COMMAND mylib_test)` 添加了一个名为 `mylib_test` 的测试。 现在你可以使用以下命令构建和运行工程: ```bash mkdir build cd build cmake .. make ./myapp ctest ``` `make` 命令将编译所有 target,并生成可执行文件和库文件。`./myapp` 命令将运行 `myapp` 可执行文件。`ctest` 命令将运行所有测试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小裘HUST

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值