实战出发,Cmake语法及CMakeLists文档编写规则总结(opencv为例)

一、自定义一个opencv环境项目。

CMakeLists简易写法:

# cmakelists: opencv_test 

cmake_minimum_required (VERSION 3.8)
project(opencv_test VERSION 1.0.0)

find_package (OpenCV REQUIRED)

include_directories (${
    
    OpenCV_INCLUDE_DIRS}
add_executable (opencv_test main.cpp)

target_link_libraries (opencv_test ${
    
    OpenCV_LIBS})

1. cmake_minimum_required()

规定cmake软件最低版本。

2. project()

规定项目的名称,此处项目名称为opencv_test,项目名称(工程文件夹名)命名规范可为:baidu(客户)_traffic(交通项目)_pz(开发公司)_server。

可以同步规定项目版本:project(opencv_test VERSION 1.0.0),这里规定版本为1.0.0。

3. find_package ()

find_package (OpenCV REQUIRED):需要先编译安装好opencv。

调用find_package寻找opencv的.cmake文件。.cmake文件在第三方包编译安装时自动安装到$CMAKE_PREFIX_PATH/lib/cmake/等文件夹中,比如/usr/lib/cmake/等

调用之后成功找到 CMAKE 会定义以下变量:

< NAME>_FOUND
< NAME>_INCLUDE_DIRS or < NAME>_INCLUDES
< NAME>_LIBRARIES or < NAME>_LIBRARIES or < NAME>_LIBS
< NAME>_DEFINTIONS

4. include_directories ()

提供一个搜索头文件暂时的根目录。

find_package(OpenCV REQUIRED)成功后即可使用变量OpenCV_INCLUDE_DIRS。

($为取出变量中的值。)

5. add_executable()

创建可执行文件。命名为< name> or < name>.exe。编译的源文件为[source1][source2]…
输出路径:CmakeLists在根目录下,build中编译生成在build中。

6. target_link_libraries()

target_link_libraries (app_test ${OpenCV_LIBS})

将找到的库连接 {OpenCV_LIBS} 到可执行文件上。
OpenCV_LIBS 为代表库可执行文件的变量,$为取出变量中的值。

写法:
TARGET_LINK_LIBRARIES(myProject hello)
TARGET_LINK_LIBRARIES(myProject libhello.a)
TARGET_LINK_LIBRARIES(myProject libhello.so)

以上通过CMAKE编译即可使用opencv。

Linux命令:(CMakeLists.txt路径下)
mkdir build 
cd build 
cmake ..
make -j12

二、项目中使用自己或他人封装的框架/库。

注:框架拷贝至对应路径下即可。

include_directories(/opt/include)

link_directories("/opt/lib")

指定要链接库的路径。
添加链接头文件和库的路径。
以上通过CMAKE编译即可使用自定义框架。

三、项目同步生成test的可执行文件。

CMakeLists.txt相同目录下应创建文件夹test,其中包含cpp源文件以及对应CMakeLists.txt

首先编写根目录下的CMakeLists.txt

# cmakelists: opencvProject
cmake_minimum_required (VERSION 3.8)
project (opencvProject VERSION 1.0.0)

enable_testing()

find_package (OpenCV REQUIRED)
include_directories (${
    
    OpenCV_INCLUDE_DIRS})
include_directories(/opt/include)
link_directories("/opt/lib")
add_executable (Trackbars-hsv main.cpp)
target_link_libraries (Trackbars-hsv ${
    
    OpenCV_LIBS})

add_subdirectory (test)

add_test(
	NAME app_test 
	COMMAND app_test)

有以下改动:

7. enable_testing()

该指令控制Makefile是否构建test目标,涉及工程所有目录。
一定要在根目录下的CMakeLists.txt中开启,不然执行make test的时候会报错。

8. add_subdirectory()

以add_subdirectory(test)为例:

必选参数source_dir:指定一个子目录,该子目录下包含(test的)CMakeLists.txt文件和代码文件。

需要在CMakeLists.txt相同的路径下创建一个test文件夹,文件夹中有test用的CMakeLists.txt以及源文件main等。

此时参数test表示相对路径。

9. add_test()

以add_test(NAME app_test COMMAND app_test)为例:

NAME指定本测试的名称,可以随意命名。

COMMAND表示可执行程序。

再编写test目录下的CMakeLists.txt(opencv环境)

cmake_minimum_required (VERSION 3.8)
project (test)
find_package (OpenCV REQUIRED)
include_directories (${
    
    OpenCV_INCLUDE_DIRS})
add_executable (app_test test.cpp)
target_link_libraries (app_test ${
    
    OpenCV_LIBS})

编译命令不变,build中make一次会在build中生成Trackbars-hsv.exe以及在build/test/中生成app_test.exe

四、完整项目规范化编写。

cmake_minimum_required (VERSION 3.8)
project (penenz VERSION 1.0.0)

enable_testing()

# version
configure_file (version.h.in version.h @ONLY)

#添加头文件路径:CMAKE_CURRENT_BINARY_DIR:build目录完全路径。
include_directories(${
    
    CMAKE_CURRENT_BINARY_DIR}

find_package (OpenCV REQUIRED)
include_directories (${
    
    OpenCV_INCLUDE_DIRS})

if(UNIX)
    include_directories ("/usr/local/include/opencv" "/usr/local/include/opencv2")
    link_directories("/usr/local/lib")
    link_directories("/usr/local/cuda/lib64")
endif()

if(UNIX)
    set(BOOST_LIBRARYDIR "/usr/local/lib")
    find_package(Boost REQUIRED COMPONENTS system filesystem thread)
    include_directories(${
    
    Boost_INCLUDE_DIRS})
    link_directories(${
    
    Boost_LIBRARY_DIRS})
else()
    set(Boost_USE_STATIC_LIBS ON)
    find_package(Boost 1.68.0 REQUIRED COMPONENTS system filesystem thread)
    include_directories ("$ENV{BOOST_ROOT}")
    link_directories ("$ENV{BOOST_ROOT}/lib64-msvc-14.1")
endif()

if(UNIX)
#增加c++版本。-pthread: 多线程使用,需要在此处设置编译。
    set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pthread")
    set (INSTALL_CONFIG_DIR /opt/config)
	set (PZ_SERVER_LIBS product_line board)#定义执行文件需要的链接库,可多个
else()
    set (INSTALL_CONFIG_DIR C:\\opt\\config)
    set (PZ_SERVER_LIBS product_line board)
endif()

#此处使用第三方相机库
if(UNIX)
	set (HAIKANG_LIBS_DIR "/opt/MVS/lib/64/")
	set (HAIKANG_INCLUDE "/opt/MVS/include/")
else()
	set (HAIKANG_LIBS_DIR "$ENV{HAIKANG_ROOT}/Development/Libraries/win64")
	set (HAIKANG_INCLUDE "$ENV{HAIKANG_ROOT}/Development/Includes")
endif()

set (HAIKANG_LIBS MvCameraControl)

include_directories (${
    
    HAIKANG_INCLUDE})
link_directories (${
    
    HAIKANG_LIBS_DIR})

set (PZ_SERVER_LIBS ${
    
    PZ_SERVER_LIBS} camera_haikang config_haikang)

#此处使用第三方IO卡库
if(UNIX)
	set(BIODAQ_LIBS biodaq biodaqutil)

	set(IOCARD_LIBS_DIR "/opt/advantech/libs")
	set(IOCARD_INCLUDE "/opt/advantech/inc")

	include_directories(${
    
    IOCARD_INCLUDE})
    link_directories(${
    
    IOCARD_LIBS_DIR})
endif()

#打印,更改变量CMAKE_CXX_FLAGS
if(UNIX)
	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNO_CLASSIFY")
	message(STATUS "===============" ${
    
    CMAKE_CXX_FLAGS} "===============")
endif()

#使用自定义库
if(UNIX)
	include_directories ("/opt/include")
	link_directories ("/opt/lib")
else()
	include_directories ("C:\\opt\\include")
	link_directories ("C:\\opt\\lib")
endif()

#把源文件定义
set(SRC_FILES main.cpp pz_app_server.cpp pz_app_workflow)

#添加执行文件
add_executable (server ${
    
    SRC_FILES})

#链接库
target_link_libraries (server ${
    
    PZ_SERVER_LIBS} ${
    
    Boost_LIBRARIES} ${
    
    OpenCV_LIBS})

if(UNIX)
    target_link_libraries (server -ldl -lstdc++fs)
endif()

target_link_libraries (server ${
    
    HAIKANG_LIBS})
target_include_directories (server PRIVATE ${
    
    HAIKANG_INCLUDE_DIR})

if(UNIX)
	target_link_libraries (server ${
    
    BIODAQ_LIBS})
	target_include_directories (server PRIVATE ${
    
    IOCARD_INCLUDE})
endif()

target_include_directories (server PRIVATE ${
    
    Boost_INCLUDE_DIR})

add_subdirectory (test)
add_test (NAME app_test COMMAND app_test)

install (FILES config.json configuration.json DESTINATION ${
    
    INSTALL_CONFIG_DIR})

10. configure_file()

configure_file (version.h.in version.h @ONLY)

复制一份输入文件到输出文件,替换输入文件中被@VAR@或者${VAR}引用的变量值。也就是说,让普通文件,也能使用CMake中的变量。
cmake读取配置文件version.h.in获取版本号。

version.h.in(输入,CMakeLists.txt根目录下)

#ifndef VERSION_H
#define VERSION_H

#define PROJECT_NAME "@PROJECT_NAME@"
#define PROJECT_VERSION  "@PROJECT_VERSION@"
#define PROJECT_MAJOR_VERSION "@PROJECT_VERSION_MAJOR@"
#define PROJECT_MINOR_VERSION "@PROJECT_VERSION_MINOR@"
#define PROJECT_PATCH_VERSION "@PROJECT_VERSION_PATCH@"

#endif // VERSION_H

version.h(输出,Build目录下)

#ifndef VERSION_H
#define VERSION_H

#define PROJECT_NAME "penenz"
#define PROJECT_VERSION  "1.0.0"
#define PROJECT_MAJOR_VERSION "1"
#define PROJECT_MINOR_VERSION "0"
#define PROJECT_PATCH_VERSION "0"

#endif // VERSION_H

11. CMAKE_CURRENT_BINARY_DIR(CMAKE变量)

include_directories(${CMAKE_CURRENT_BINARY_DIR})
添加头文件路径:CMAKE_CURRENT_BINARY_DIR:build目录完全路径。

12. set()

变量赋值,可设多个。set (normal_var a)

13. [3.]find_packag()拓展一

find_package(Boost REQUIRED COMPONENTS system filesystem thread)

find_package这里有更多细节:

REQUIRED:可选字段,表示一定要找到包,找不到的话立即停掉整个cmake。
COMPONENTS:可选字段,表示查找包中的必须要找到的组件,有任何一个找不到就算失败。

find_package先在CMAKE_MODULE_PATH变量对应的路径中查找,如果路径为空,或者路径中查找失败,则在cmake module directory(cmake安装时的Modules目录,比如/usr/local/share/cmake/Modules)查找。

比如此处会加载框架常用组件system,thread等,system(“reboot”)输出终端命令,运行shell脚本用。thread用于多线程。

14. set (CMAKE_CXX_FLAGS “${CMAKE_CXX_FLAGS} -std=c++14 -pthread”)

增加c++版本。 CMAKE_CXX_FLAGS是C++编译器的编译选项。
-pthread: 多线程使用,需要在此处设置编译。

15. target_link_libraries (server -ldl -lstdc++fs)

如果你的程序中使用dlopen、dlsym、dlclose、dlerror 显示加载动态库,需要设置链接选项 -ldl。

加-lstdc++表示编译c++文件,即链接c++库,加-lc表示链接c库,默认情况下就是链接c库,所以如果编译c文件可以不加-lc。

16. target_include_directories (server PRIVATE ${HAIKANG_INCLUDE_DIR})

private 用法:将该头文件目录只链接到server

17. install()

install (FILES config.json configuration.json DESTINATION ${INSTALL_CONFIG_DIR})

FILES指普通的文本文件

DESTINATION:指定磁盘上要安装文件的目录INSTALL_CONFIG_DIR;

五、onnx模型推理的环境部署。

简易版CMakeLists编写:

# cmakelists: test_onnx
cmake_minimum_required (VERSION 3.8)
project (test_onnx VERSION 1.0.0)

find_package (OpenCV REQUIRED)
include_directories (${OpenCV_INCLUDE_DIRS})

include_directories(/opt/include)
link_directories("/opt/lib")

add_executable (test main.cpp)
target_link_libraries (test ${OpenCV_LIBS} onnxruntime)

只有一步改变,连接上onnxruntime。
target_link_libraries (test ${OpenCV_LIBS} onnxruntime)

将使用到的头文件和链接库放在/opt/include与opt/lib下
模型推理所需头文件为:
onnxruntime_cxx_api.h
库为:
libonnxruntime.so.1.10.0 和 libonnxruntime.so

CMakeLists比较罗嗦的版本:
这里的核心操作就是添加include和lib的路径,其他命令删掉也是可以运行的。
此处探讨这段罗嗦版本的作用。

if (WIN32)
 string(APPEND CMAKE_CXX_FLAGS " /W4")
else()
 string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra")
 string(APPEND CMAKE_C_FLAGS " -Wall -Wextra")
endif()

#onnxruntime providers
option(onnxruntime_USE_CUDA "Build with CUDA support" OFF)
option(onnxruntime_USE_OPENVINO "Build with OpenVINO support" OFF)
option(onnxruntime_USE_NNAPI_BUILTIN "Build with builtin NNAPI lib for Android NNAPI support" OFF)
option(onnxruntime_USE_DNNL "Build with DNNL support" OFF)
option(onnxruntime_USE_NUPHAR "Build with Nuphar" OFF)
option(onnxruntime_USE_TENSORRT "Build with TensorRT support" OFF)
option(LIBPNG_ROOTDIR "libpng root dir")
option(ONNXRUNTIME_ROOTDIR "onnxruntime root dir")

if(NOT ONNXRUNTIME_ROOTDIR)
  if(WIN32)
    set(ONNXRUNTIME_ROOTDIR "C:/Program Files (x86)/onnxruntime")
  else()
    include_directories("/opt/include")
  endif()
endif()

include_directories(/opt/lib/onnxruntime-linux-x64-1.10.0/include /opt/lib/onnxruntime-linux-x64-1.10.0/include/onnxruntime/core/session)
link_directories("/opt/lib/onnxruntime-linux-x64-1.10.0/lib")

if(onnxruntime_USE_CUDA)
  add_definitions(-DUSE_CUDA)
endif()
if(onnxruntime_USE_OPENVINO)
  add_definitions(-DUSE_OPENVINO)
endif()
if(onnxruntime_USE_NNAPI_BUILTIN)
  add_definitions(-DUSE_NNAPI)
endif()
if(onnxruntime_USE_DNNL)
  add_definitions(-DUSE_DNNL)
endif()
if(onnxruntime_USE_NUPHAR)
  add_definitions(-DUSE_NUPHAR)
endif()
if(onnxruntime_USE_TENSORRT)
  add_definitions(-DUSE_TENSORRT)
endif()
if(onnxruntime_USE_DML)
  message("Enabling DML")
  add_definitions(-DUSE_DML)
endif()

18. string()

string(APPEND <string_variable> […])
尾部追加,set()可达到相同效果。

19. string(APPEND CMAKE_CXX_FLAGS " -Wall -Wextra")

gcc 编译器的 -Wall选项涵盖了绝大多数警告标记,但依然有一些警告不能生成。为了生成它们,使用 -Wextra选项。

两个一起用警告更多。

20. options()

option( “<help_text>” [value])

variable:定义选项名称 help_text:说明选项的含义
help_text:说明选项的含义
value:定义选项默认状态,一般是OFF或者ON,除去ON之外,其他所有值都为认为是OFF。

定义了选项名、值。

21. add_definitions()

为当前路径以及下层路径的目标加入编译器命令行定义。这个命令可以用来添加任何标志,但是它的原意是用来增加预处理器的定义(查看 add_compile_options() 命令增加其它的定义)。那些以 -D 或 /D 开头的变量,像预处理器定义的flag,会被自动加到当前路径的 COMPILE_DEFINITIONS 属性中。

在工程CMakeLists.txt 中,使用add_definitions()函数控制代码的开启和关闭:
添加一个宏定义ifdef (-D) TEST_DEBUG

option(TEST_DEBUG "option for debug" OFF)
if (TEST_DEBUG) 
    add_definitions(-DTEST_DEBUG)
endif(TEST_DEBUG)

运行构建项目的时候可以添加参数控制宏的开启和关闭.

 cmake -DTEST_DEBUG=1 .. #打开
 cmake -DTEST_DEBUG=0 .. #关闭

在源码中就可以使用:

#ifdef TEST_DEBUG
....

猜你喜欢

转载自blog.csdn.net/weixin_48846514/article/details/126785256
今日推荐