嵌入式Linux平台使用Cmake交叉编译构建C/C++生成Makefile构建项目

发布时间:2023年12月18日

机缘

本周一,mentor给我的一个需求,在一套客户新的SDK开发套件中(原先是基于makefile构建的),且makefile互相嵌套. 任务就是找一个独立的例程,比如vin -> isp turning 在线调试图像 这一例程,以下统称为 例程· 把makefile 构建改成cmake构建.以交叉编译的方式,最终在开发板上跑起来.

所以本次作文,不仅是对CMake进行交叉编译的总结,也是从Makefile转变到Cmake构建的一些经验.


工作流

  1. 原来的构建过程是makefile构建, 且存在嵌套的关系,这时需要关注makefile的嵌套关系.一般情况下,最上层(一般和你要编译的C/CPP代码放在同一目录下)的Makefile会指定头文件和依赖的库,有些SDK用makefile构建会同时生成依赖动态库的可执行程序和依赖静态库的可执行程序.是makefile中的内容makefile中的内容makefile中的内容
    这里特别需要注意一下if条件可能会包含一些其他的配置,比如说CLIB,CLFAGS.
    特别是CFLAGS,正如CFLAGS += -dl 这又把链接的库包含上了.

在 Makefile 中,CFLAGS 是一个常用的变量,用于指定 C 语言编译器(如 gcc 或 g++)的编译选项。这个变量用于设置编译器的参数和标志,以控制编译过程中的行为。一些常见的 CFLAGS 包括:
-Wall:启用所有警告信息。
-O2:优化级别2,启用较高级别的优化。
-ggdb3:生成适用于 gdb 调试器的调试信息。
-l库名: 链接某个库.这一点我构建的时候就没注意
-D某个宏: 这个宏会参与预编译.需要考虑

  1. 由上面可知,我们要构建自己的Cmake来代替makefile,需要考虑
  1. 源文件
  2. 链接的库 通常在CLIB,CFLAGS,LDFLAGS出现(经过查询,发现使用 LDFLAGS 变量来指定链接选项更常见)
  3. 预编译宏,比如define xxx
  4. makefile中的if条件生效情况.
  1. 创建CMakeLists.txt(名字不能更改),一般还会创建个build目录.
  2. 创建交叉编译的toolchain(工具链文件)如xxxx_toolchain.cmake 一般原厂都这样命名.如下图,因为这个要在cmake中指定,为了跨平台的需要,一般是手动指定工具链文件

目录结构

具体示例CMakeLists.txt和toolchain.make(工具链文件)参考

CMakeLists.txt

  • 实现编译成可执行文件(以链接动态库的形式)
  • target为可执行文件并设置生成路径为当前目录.
  • 支持make install 拷贝到指定目录下.
  • 根据之前的makefile包含了一些 配置选项,如预编译宏 等等
# this sample is test of vin
cmake_minimum_required(VERSION 3.17)
project(Test)

# mannual assign and it  is necessary
if(CMAKE_TOOLCHAIN_FILE)
    include(${CMAKE_TOOLCHAIN_FILE})
endif()

set(CUR_PATH  ${CMAKE_CURRENT_SOURCE_DIR})
set(HOME_PATH ${CUR_PATH}/../../..)
set(OUT_PATH ${HOME_PATH}/msp/out)
set(SRC_PATH  ${CUR_PATH})
set(BASE_PATH  ${HOME_PATH}/msp/component)
set(COMMON_PATH  ${BASE_PATH}/isp/common)
set(SYS_DRV_PATH  ${HOME_PATH}/kernel/osdrv/private_drv/sys)
set(ROOTFS_TARGET_PATH  ${OUT_PATH})
set(APP  "TEST_APP2")
set(SAMPLE_PATH ${CUR_PATH}/../common)
set(SSL_PATH ${HOME_PATH}/third-party/openssl)
set(preview "yes")
set(ircut   "yes")
   
  
 


file(GLOB SOURCES 
        "${SRC_PATH}/rtsp/src/*.cpp"
        "${SRC_PATH}/run_joint/src/*.cpp"
        "${SRC_PATH}/utils/*.cpp"
        "${SRC_PATH}/*.c"
        "${SAMPLE_PATH}/*.c"
        "${SAMPLE_PATH}/common_codec/*.c"
        "${SRC_PATH}/run_joint/src/*.c"


)
 
 
 
# set output path  
set(EXECUTABLE_OUTPUT_PATH ${CUR_PATH})

# target 
add_executable(${APP} ${SOURCES} )
# support install target to  appointed path
install(TARGETS ${APP} DESTINATION ${OUT_PATH}/bin )

# indicate lib path 
target_link_directories(${APP}
PRIVATE
${OUT_PATH}/lib
${SSL_PATH}/lib
${SRC_PATH}/rtsp/lib
)

# assign include path
target_include_directories(${APP}
PRIVATE
${SRC_PATH}
${SSL_PATH}/include
${OUT_PATH}/include
${SAMPLE_PATH}
${OUT_PATH}/include/npu_cv_kit
${COMMON_PAHT}
${SAMPLE_PATH}/common_codec
${SRC_PATH}/run_joint/inc
${SRC_PATH}/rtsp/inc
${SRC_PATH}/rtsp/inc/BasicUsageEnvironment
${SRC_PATH}/rtsp/inc/groupsock
${SRC_PATH}/rtsp/inc/liveMedia
${SRC_PATH}/rtsp/inc/UsageEnvironment
${SRC_PATH}/utils
)



#  assign link needful lib
target_link_libraries(${APP}
# ${OUT_PATH}/lib/libax_sys.so
# ${OUT_PATH}/lib/libax_3a.so
# ${OUT_PATH}/lib/libax_mipi.so
# ${OUT_PATH}/lib/libax_proton.so
# ${OUT_PATH}/lib/libax_interpreter_external.so
# ${OUT_PATH}/lib/libaxsyslog.so
# ${OUT_PATH}/lib/libax_npu_cv_kit.so
# ${OUT_PATH}/lib/libax_ivps.so
# ${OUT_PATH}/lib/libax_cap.so
# ${OUT_PATH}/lib/libax_venc.so
# ${OUT_PATH}/lib/libax_run_joint.so
# ${OUT_PATH}/lib/libax_dma_hal.so
ax_sys 
ax_3a
ax_mipi
ax_proton
ax_interpreter_external
axsyslog
ax_npu_cv_kit
ax_ivps
ax_cap
ax_venc
ax_run_joint
ax_dma_hal
ssl 
crypto 
liveMedia 
groupsock 
BasicUsageEnvironment 
UsageEnvironment   
m
dl
pthread
stdc++


 
)




 # if configue

if(NOT preview STREQUAL "no")
        target_link_libraries(${APP}
        ${OUT_PATH}/lib/libax_nt_stream.so
        ${OUT_PATH}/lib/libax_nt_ctrl.so
        )
        add_compile_definitions(TUNING_CTRL)
endif()

if (ircut STREQUAL "yes")
    add_compile_definitions(SAMPLE_IRCUT)
endif()


 
# on the basic of  debug  to set  CFLAGS
set (debug "no")
if (debug STREQUAL "yes")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O0 -ggdb3")
else()
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O2")
endif()

# on the basic of  620U_LITTLE_FLASH to set  CFLAGS
set(620U_LITTLE_FLASH "FALSE")
if (620U_LITTLE_FLASH STREQUAL "TRUE")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DSAMPLE_620U_NAND")
endif()

# extra target for  construct
# add_custom_target(  test001
#     ALL
#     COMMAND  echo "test001\r\n"
#     COMMENT "do nothing"
# )

 

在此有必要说明下注意事项.

  • 必须加上if(CMAKE_TOOLCHAIN_FILE) include(${CMAKE_TOOLCHAIN_FILE}) endif() 这段代码,不然无法手动指定交叉编译器文件.

  • target_link_libraries target_include_directories target_link_directories 必须放在构建的目标之后.不然会报错.target_link_directories 需要的cmake的版本在3.13以上.不然用不了.

  • 关于target_link_directories target_include_directories target_link_libraries
    这三个与 link_directories include_directories link_libraries 的区别是什么?
    回答:
    target_link_directories:指定与一个目标链接的库的目录。
    target_include_directories:为一个目标(如库或可执行文件)设置包含目录,以便CMake可以在构建时找到所需的头文件。
    target_link_libraries:用于将库链接到目标。它将其他库链接到给定的目标(例如,链接库到可执行文件或库文件)。
    相对应的命令有:
    link_directories:指定要在链接期间搜索库文件的目录。
    include_directories:设置项目中源文件包含的头文件目录。
    link_libraries:链接要链接到所有目标的库。
    主要区别在于 target_ 命令是为特定目标设置属性的,而不是全局设置。这意味着它们更具有定向性,并且可以针对特定目标进行设置,以确保在构建过程中为该目标使用特定的库和包含路径。

  • file(GLOB 源文件名 目录) 这里的目录可以批量指定,为了就是让一个变量包含所有需要的源文件.

  • 注意加上一些if条件来进行构建(如果需要的话)

交叉编译xxx_toolchain.make

set(CMAKE_SYSTEM_NAME Linux)

message(STATUS "cross compile ax720 ")
set(TOOLCHAIN_PATH /home/yzh/yzh/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf)
set(CMAKE_C_COMPILER ${TOOLCHAIN_PATH}/bin/arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PATH}/bin/arm-linux-gnueabihf-gcc)

  • 指定gcc和g++的工具链路径.

这样就能在build目录下执行

cmake -DCMAKE_TOOLCHAIN_FILE=/home/yzh/m55/M55SDK/V2.0.2/cyclops_1r1v_emmc_SDK_V2.0.2_20231010142128_NO303/msp/sample/vin_ivps_joint_venc_rtsp_bak/ax720_toolchain.cmake(你的工具链文件路径)     ..(CMakeLists.txt所在目录)
make clean all install

在这里插入图片描述

文章来源:https://blog.csdn.net/PHILICS7/article/details/134952507
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。