目录
目录
1、add_executable和add_subdirectory命令
2、add_library 命令和 target_link_libraries 命令
3.aux_source_directory查找指定目录所以的文件添加成一个变量
4、include_directories指定头文件搜索路径
cmake的使用场景和功能:cmake 的诞生主要是为了解决直接使用 make+Makefile 这种方式无法实现跨平台的问题,所以 cmake 是可以实现跨平台的编译工具这是它最大的特点。cmake 仅仅只是根据不同平台生成对应的 Makefile,最终还是通过 make工具来编译工程源码,但是 cmake 却是跨平台的
所以需要我们需要修改CMakeLists.txt文件,最后编译出Makefile
cmake --version
cmake ./
//检查版本和运行cmakelist.txt
执行完 cmake 之后,除了源文件 main.c 和 CMakeLists.txt 之外,可以看到当前目录下生成了很多其它的文件或文件夹,包括: CMakeCache.txt、 CmakeFiles、 cmake_install.cmake、 Makefile
通常是建立一个build文件夹,cmake ../让cmake产生的文件都在一个目录下,就不会看起来混乱
Cmake常用命令介绍
1、add_executable和add_subdirectory命令
add_executable(hello ./main.c)
add_executable 同样也是一个命令,用于生成一个可执行文件, 在本例中传入了两个参数,第一个参数表示生成的可执行文件对应的文件名,第二个参数表示对应的源文件;
add_executable(hello ./main.c)表示需要生成一个名为 hello 的可执行文件,所需源文件为当前目录下的 main.c。
add_subdirectory告诉 cmake 去指定的目录中寻找源码并执行CMakeLists.txt,这个命令在大型工程的时候用的特别多,每一级目录下都有自己的CMakeLists.txt的文件。
# 告诉 cmake 去 src 目录下寻找 CMakeLists.txt
add_subdirectory(src)
2、add_library 命令和 target_link_libraries 命令
add_library 命令用于生成库文件,在本例中我们传入了两个参数,第一个参数表示库文件的名字,需要注意的是,这个名字是不包含前缀和后缀的名字; 在 Linux 系统中,库文件的前缀是 lib,动态库文件的后缀是.so,而静态库文件的后缀是.a;最终生成的库文件对应的名字会自动添加上前缀和后缀。
find_package(Boost REQUIRED COMPONENTS filesystem system
):查找外部库BOOST,如果找到,会设置相关的变量(如 Boost_FOUND
Boost_INCLUDE_DIRS
、Boost_LIBRARIES
等),并提供目标(如 Boost::filesystem
和 Boost::system
)
add_library(libhello SHARED hello.c) #生成动态库文件
add_library(libhello STATIC hello.c) #生成静态库文件
add_executable(hello main.c)#可执行文件hello
target_link_libraries(hello liblibhello)#指定依赖库
target_link_libraries 命令为目标指定依赖库,hello.c 被编译为库文件, 并将其链接进 hello 程
序
3.aux_source_directory查找指定目录所以的文件添加成一个变量
Cmake的命令,刚刚的add_library就是命令。在 CMakeLists.txt 中,命令名不区分大小写,可以使用大写字母或小写字母书写命令名
# 查找 src 目录下的所有源文件
aux_source_directory(src SRC_LIST)
message("${SRC_LIST}") # 打印 SRC_LIST 变量
4、include_directories指定头文件搜索路径
如果需要包含多个头文件时,可以把头文件放在include文件夹中,当调用 add_subdirectory 命令加载子源码时, 会将 include_directories 命令包含的目录列表向下传递给子源码(子源码从父源码中继承过来)
include_directories(include)
add_executable(hello main.c)
5.Cmake的变量
手动添加自定义变量,当然是变量就存在作用域,set变量作用域的范围如下:
# 全局作用域
set(GLOBAL_VAR "global" CACHE INTERNAL "")
# 目录作用域
set(DIR_VAR "directory")
function(my_function)
# 函数作用域
set(FUNC_VAR "function")
# 提升到父作用域
set(PARENT_VAR "parent" PARENT_SCOPE)
endfunction()
if(TRUE)
# 块作用域
set(BLOCK_VAR "block")
endif()
#设置变量 MY_VAL
set(MY_VAL "Hello World!")
#引用变量 MY_VAL
message(${MY_VAL})
CMAKE常用变量介绍
6.install命令
install
命令用于指定在构建过程中需要安装的文件、目录、可执行文件等。在构建大型工程的时候会将编译出来的文件最终都安装到一个目录下,例如/output
install安装命令解释:
TARGETS:
表示要安装的是 CMake 构建目标(如可执行文件、库等),而不是普通文件my_executable
和 my_library:
my_executable
:通常是通过 add_executable
定义的可执行文件。my_library
:通常是通过 add_library
定义的库文件(可以是共享库 .so
或静态库 .a
)
install(TARGETS my_executable my_library
RUNTIME DESTINATION bin # 可执行文件安装到 bin 目录
LIBRARY DESTINATION lib # 共享库安装到 lib 目录
ARCHIVE DESTINATION lib) # 静态库安装到 lib 目录
# 安装头文件到 include 目录
install(FILES my_header.h DESTINATION include)
# 安装整个目录到 share 目录
install(DIRECTORY my_data/ DESTINATION share/my_project)
# 安装脚本到 bin 目录
install(PROGRAMS my_script.sh DESTINATION bin)
CMAKE交叉编译
如果不设置交叉编译,默认情况下, cmake 会使用主机系统(运行 cmake 命令的操作系统)的编译器来编译我们的工程,那么得到的可执行文件或库文件只能在 Ubuntu 系统运行(X86架构),为了能在arm(arch)芯片上运行需要使用交叉编译器
# 配置 ARM 交叉编译
set(CMAKE_SYSTEM_NAME Linux) #设置目标系统名字
set(CMAKE_SYSTEM_PROCESSOR arm) #设置目标处理器架构
# 指定编译器的根目录
set(TOOLCHAIN_DIR /opt/fsl-imx-x11/4.1.15-2.1.0/sysroots)
set(CMAKE_SYSROOT ${TOOLCHAIN_DIR}/cortexa7hf-neon-poky-linux-gnueabi)
# 指定交叉编译器 arm-gcc 和 arm-g++
set(CMAKE_C_COMPILER ${TOOLCHAIN_DIR}/x86_64-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/armpoky-linux-gnueabi-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_DIR}/x86_64-pokysdk-linux/usr/bin/arm-poky-linuxgnueabi/arm-poky-linux-gnueabi-g++)
举例,使用多个三方库opencv进行cmake
# CMake需要的最低版本号是3.4.1
cmake_minimum_required(VERSION 3.4.1)
# 指定了项目的名称为resnet18
project(example)
# 不使用任何C编译器标志,使用C++11标准进行编译
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
# rknn api
# CMAKE_SOURCE_DIR当前cmakelist的目录
set(RKNN_API_PATH ${CMAKE_SOURCE_DIR}/../3rdparty/librknn_api) #该变量定义了RKNN API库的路径
set(LIB_ARCH aarch64)
set(RKNN_RT_LIB ${RKNN_API_PATH}/${LIB_ARCH}/librknnrt.so) # 该变量定义了RKNN运行时库的路径。
include_directories(${RKNN_API_PATH}/include) # 添加RKNN API的头文件
# opencv
set(OpenCV_DIR ${CMAKE_SOURCE_DIR}/../3rdparty/opencv/share/OpenCV) # 指定了OpenCV库的路径。
find_package(OpenCV REQUIRED) # 自动查找OpenCV库,并将相关信息保存在CMake内置变量中
# 指定了程序运行时查找动态链接库的路径
set(CMAKE_INSTALL_RPATH "lib")
# 创建一个可执行文件
add_executable(${PROJECT_NAME}
src/main.cc
)
# 指定工程需要链接的库文件
target_link_libraries(${PROJECT_NAME}
${RKNN_RT_LIB}
${OpenCV_LIBS}
)
# 指定了程序安装的路径
set(CMAKE_INSTALL_PREFIX ${CMAKE_SOURCE_DIR}/install/${PROJECT_NAME}_${CMAKE_SYSTEM_NAME})
# 拷贝可执行程序和需要用的库以及后面测试要用到的model测试文件
install(TARGETS ${PROJECT_NAME} DESTINATION ./)
install(DIRECTORY model DESTINATION ./)
install(PROGRAMS ${RKNN_RT_LIB} DESTINATION lib)
所以目录结构如下
my_rknn_resnet/
├── 00_example/
│ ├── build.sh # 构建脚本
│ ├── CMakeLists.txt # CMake 配置文件
│ ├── src/
│ │ └── main.cc # 主程序源代码
│ ├── model/ # 模型文件夹(用于测试)
│ └── build/ # 构建输出目录
│ └── build_linux_aarch64/ # 具体构建输出目录
├── 3rdparty/
│ ├── librknn_api/
│ │ ├── include/ # RKNN API 头文件
│ │ └── aarch64/ # RKNN 运行时库(aarch64架构)
│ │ └── librknnrt.so # RKNN 运行时库文件
│ └── opencv/
│ ├── share/
│ │ └── OpenCV/ # OpenCV CMake 配置文件
│ └── lib/ # OpenCV 库文件
└── install/ # 安装输出目录
└── example_Linux/ # 示例安装目录
Cmake的编译方式
1.使用cmake工具链配置文件,通常建议将工具链配置放在一个单独的文件中,以便更好地管理和重用,指定工具链配置文件进行编译
cmake -DCMAKE_TOOLCHAIN_FILE=../Toolchain-rk3588.cmake ..
2.直接编译,将配置内容直接放在Cmakelist.txt 文件中,直接cmake ..