总结:更新20221227。
其中sample的工程例子,地址:https://gitee.com/yangdashi/test_cmake-lists
A、其中CMakeLists.txts是跨平台的编译软件。而makefile是主要应用在linux系统环境下的配置文件。
B、如果使用了CMakeList.txts的时候,其在linux下,会产生makefile文件。如果在window环境下,则是产生sln工程环境,然后使用VS进行编译,产生相应的库,或者执行文件。
下面是sample,其顶层的CMakeLists.txt的内容如下:
#进行查找文件下的所有某个类型文件。
file(GLOB TEMP temp/*.jpg)
#这里也可以使用CMAKE_PREFIX_PATH参数代替opencv的库路径。
set(OpenCV_DIR H:\softwared\opencv440\opencv\opencv\build)
#只有上面的路径设置了,下面这句执行才不会报错。
find_package(OpenCV REQUIRED)
#这里设置工程代码的库安装路径
set (INSTALL_LIB_DIR C:\\opt\\lib)
#这里是库的头文件安装路径
set(INSTALL_INCLUDE_DIR C:\\opt\\lib)
#这里是一些测试用例的数据安装路径
set(INSTALL_TEMP_DIR C:\\opt\\lib)
#这里的变量宏是全局的,只作用于其cpp文件,而不会作用于CMakeLists.txt文件上。其中在win上
#这里会宏会被写到预处理器定义上。 其中CMakeLists.txt上的if变量的只能在边缘的时候控制,cmake -DCLASSIFY=OFF .. (ON开-TRUE OFF关-FALSE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNO_CLASSIFY")
cmake_minimum_required(VERSION 3.5)
#默认是静态库static,这里设置成SHARD动态库。
#对于add_library一般要有两个个函数target_include_directories、target_link_libraries。
#分别用来包含其依赖头文件、库文件等。
add_library(hello_library SHARED Hello.cpp)
target_include_directories(hello_library PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
add_executable(main main.cpp)
target_include_directories(main PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/image_process)
#reduce
target_link_libraries(main hello_library reduce ${OpenCV_LIBS})
install (TARGETS hello_library DESTINATION ${INSTALL_LIB_DIR})
install (FILES Hello.h DESTINATION ${INSTALL_INCLUDE_DIR})
#这个开关变量是需要通过在cmake的时候进通过ON、OFF参数进行设置。CLASSIFY
if(CLASSIFY)
install(FILES ${TEMP} DESTINATION ${INSTALL_TEMP_DIR}/temp)
endif()
add_subdirectory("image_process")
同目录下文件有:temp文件夹、CMakelists.txt、Hello.cpp、Hello.h、main.cpp、build。
子目录image_process里的CMakeLists.txt的内容如下:
cmake_minimum_required(VERSION 3.8)
add_library(reduce reduce.cpp)
target_include_directories(reduce PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(reduce ${OpenCV_LIBS})
install(FILES reduce.h DESTINATION ${INSTALL_INCLUDE_DIR})
install(TARGETS reduce DESTINATION ${INSTALL_LIB_DIR})
同目录下有文件:CMakeLists.txt、reduce.cpp、reduce.h。
1.在网上下载一些开源库时经常需要自己使用Cmake进行源代码的工程搭建此处给出曾经遇到的坑。
出现错误:CMake Error at CMakeLists.txt:11 (project): No CMAKE_C_COMPILER could be found.
这提示的是没有找到C编译器,原因有两种:
a.没装C编译器,一般电脑装有VS后都会有C编译器的;
b.装的VS路径带有中文。(坑)。
例如错误:
带有中文路径会报错。当把其安装到没有中午路径下就可以正常编译,其路径为:F:\win8\vs2013。生成工程,如下:
此处的红框中是自己选择的,如果选择勾则表示对此处下的源代码进行编译生产工程文件。
2、cmake使用CMakeLists减少工程环境变量配置的工作例如opencv、libtorch的工程配置:
参考博客:cmake--生成--动态库
cmaketutorial-使用source_group对源码分组
其中opencv官网下载的window安装包是在安装好后,在build\x64\vc14\lib目录下是会由几个后缀为cmake的文件,其主要是用来配置opencv的lib、头文件的的配置文件,其会把这些配置到工程上的。其中libtorch在官网下载好后,其是相当于opencv被当作一个应用库。其里面也包含了cmake文件,用来在需要的工程上自动配置libtorch相关的内容。这样子可以很简单的完成项目配置。下面主要cmake配置用到的语句,
A、以配置opencv为例子:
#用于指定camke的最低版本
cmake_minimum_required (VERSION 3.1)
#用于指定当前编写所产生的h头文件目录
include_directories("..//include")
#用于指定编译的工程名字,可以随意取
project(testopencv)
SET(SRC_DIR ${PROJECT_SOURCE_DIR})
include_directories(${SRC_DIR})
#CURRENT_HEADERS名字可以随意,其作用就是把对应目录下的所有文件添加到CURRENT_HEADERS等对象里
file(GLOB CURRENT_HEADERS ${SRC_DIR}/*.h ${SRC_DIR}/*.hpp)
file(GLOB CURRENT_SOURCES ${SRC_DIR}/*.cpp ${SRC_DIR}/*.C)
#对工程相应的代码进行分组
source_group("Include" FILES ${CURRENT_HEADERS})
source_group("Source2" FILES ${CURRENT_SOURCES})
#指定opencv配置自身库、头文件等信息的cmake文件路径。路径要指定到cmake文件对应的目录下
set(CMAKE_PREFIX_PATH "F:\\installed_soft\\Opencv\\346vc14\\opencv\\build\\x64\\vc14\\lib")
#指定查找cmake后缀的文件名,例如这里的会在上面的cmake_prefix_path路径下查找以<库名字的大写>Config.cma#ke或者 <库名字的小写>-config.cmake的文件,
#这里的库名Opencv是OpenCVConfig.cmake,
#这回导致查找不到库,所以写这里的名称时要先到包文件下看其带有cmake的文件名称。
find_package(OpenCV REQUIRED)
#指令add_executable(testopencv main.cpp)这里main是包含入口的代码文件,其不会主动取包含其它cpp、hpp文件,工程可以cmake成功,但是打开后的工程可能会出现无法解析的函数,后者无法包括的头文件。
#其要自己手动在后面添加如下的有关头文件、原文件的代码。
add_executable(testopencv main.cpp ${CURRENT_SOURCES} ${CURRENT_HEADERS})
#这里指的是OpenCV要跟上面的find_package里查找的包名一样
target_link_libraries(testopencv "${OpenCV_LIBS}")
set_property(TARGET testopencv PROPERTY CXX_STANDARD 11)
配置好后生成的工程结构如下:
如果想生成的是exe的未添加add_executable则会报如下错误:
Selecting Windows SDK version 10.0.17134.0 to target Windows 10.0.18362.
CMake Error at CMakeLists.txt:19 (target_link_libraries):
Cannot specify link libraries for target "testopencv" which is not built by
this project.
B、下面时配置带有cuda的动态连接库的常用cmake,比较通用的:
cmake_minimum_required(VERSION 2.8)
set(targetname render)
project(${targetname})
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -O3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -O3 -std=c++11" )
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
set(SRC_DIR ${PROJECT_SOURCE_DIR}/)
include_directories(${SRC_DIR})
file(GLOB CURRENT_HEADERS ${SRC_DIR}/*.h )
file(GLOB CURRENT_SOURCES ${SRC_DIR}/*.cpp ${SRC_DIR}/*.c )
find_package(CUDA)
ADD_DEFINITIONS(-DGPU -DNO_CUDNN)
include_directories(${SRC_DIR}/)
IF (WIN32)
set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -Xcompiler /wd4819")
ENDIF()
file(GLOB CU_CURRENT_HEADERS ${SRC_DIR}/*.h )
file(GLOB CU_CURRENT_SOURCES ${SRC_DIR}/*.cpp ${SRC_DIR}/*.c )
file(GLOB CURRENT_CUDA_SOURCES ${SRC_DIR}/*.cu )
source_group("Include" FILES ${CURRENT_HEADERS} ${CU_CURRENT_HEADERS})
source_group("Source" FILES ${CURRENT_SOURCES} ${CU_CURRENT_SOURCES})
source_group("CuSource" FILES ${CURRENT_CUDA_SOURCES})
CUDA_COMPILE(CU_OBJ ${CURRENT_CUDA_SOURCES})
#这里是用来配置工程生成的是动态连接库的工程,如果不带cuda的函数则是add_library()
cuda_add_library(${targetname} SHARED ${CU_CURRENT_SOURCES} ${CU_CURRENT_HEADERS} ${CU_OBJ} ${CURRENT_SOURCES} ${CURRENT_HEADERS})
target_link_libraries(${targetname} ${CUDA_curand_LIBRARY} ${CUDA_cublas_LIBRARY})
SET_TARGET_PROPERTIES(${targetname} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${LIBRARY_OUTPUT_PATH})
SET_TARGET_PROPERTIES(${targetname} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${LIBRARY_OUTPUT_PATH})
其中主要的cmake宏定义有:
PROJECT_SOURCE_DIR: 是指工程源码目录,就是包含有CMakeLists.txt最近的目录,因为源码目录必须要包含有这个文件才可以编译,不会报错.
find_package:寻找<库名字的大写>Config.cmake 或者 <库名字的小写>-config.cmake (比如库Opencv,它会查找/usr/local/share/OpenCV中的OpenCVConfig.cmake或opencv-config.cmake)。**这称为配置模式。不管使用哪一种模式,只要找到*.cmake,*.cmake里面都会定义下面这些变量
<NAME>_FOUND
<NAME>_INCLUDE_DIRS or <NAME>_INCLUDES
<NAME>_LIBRARIES or <NAME>_LIBRARIES or <NAME>_LIBS
<NAME>_DEFINITIONS
这也就是可以使用OpenCV_LIBRARIES或者OpenCV_LIBS来引入库文件
ENV:环境变量(environment variable)读写其中用于判断java环境变量:
读取环境变量则要使用 $ENV{JAVA_HOME}
这样的格式
if(NOT DEFINED ENV{JAVA_HOME})
# 没有找到JAVA_HOME环境变量
message(FATAL_ERROR "not defined environment variable:JAVA_HOME")
endif()
#不能用if(ENV{JAVA_HOME})形式来判断是否定义
#但可以用if($ENV{JAVA_HOME})
用于torch环境判断:
if (DEFINED ENV{TORCH_INSTALL_PREFIX})
set(TORCH_INSTALL_PREFIX $ENV{TORCH_INSTALL_PREFIX})
else()
# Assume we are in <install-prefix>/share/cmake/Torch/TorchConfig.cmake
get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(TORCH_INSTALL_PREFIX "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
endif()
# Include directories.
if (EXISTS "${TORCH_INSTALL_PREFIX}/lib/include")
set(TORCH_INCLUDE_DIRS
${TORCH_INSTALL_PREFIX}/lib/include
${TORCH_INSTALL_PREFIX}/lib/include/torch/csrc/api/include)
else()
set(TORCH_INCLUDE_DIRS
${TORCH_INSTALL_PREFIX}/include
${TORCH_INSTALL_PREFIX}/include/torch/csrc/api/include)
endif()
如果定义了环境变量的话,则会优先以环境变量的路径为准进行进行加载头文件等信息.
CMAKE_CURRENT_LIST_DIR:指的是当前后缀为cmake文件路径
get_filename_component:得到一个完整文件名中的特定部分。
get_filename_component(<VAR> FileName
PATH|ABSOLUTE|NAME|EXT|NAME_WE|REALPATH
[CACHE])
将变量<VAR>设置为路径(PATH),文件名(NAME),文件扩展名(EXT),去掉扩展名的文件名(NAME_WE),完整路径(ABSOLUTE),或者所有符号链接被解析出的完整路径(REALPATH)。注意,路径会被转换为Unix的反斜杠(/),并且没有结尾的反斜杠。该命令已经考虑了最长的文件扩展名。如果指定了CACHE选项,得到的变量会被加到cache中。
CMAKE_PREFIX_PATH:这个是用于指定第三方库的cmake文件的路径,这个要具体到对应的目录下,要么回报找不到.cmake文件的错误。
在linux下进行编译使用tensorrt进行工程构建的cmakelists编写:
# cmakelists: sencan_liddetection_xj_server
cmake_minimum_required (VERSION 3.8)
project(algorithm)
cmake_minimum_required (VERSION 3.8)
find_package (OpenCV REQUIRED)
include_directories (${OpenCV_INCLUDE_DIRS})
include_directories("/usr/local/include/OpenCV","/usr/local/include/OpenCV2")
find_package (CUDA REQUIRED)
include_directories (${CUDA_INCLUDE_DIRS})
file(GLOB_RECURSE SRCS ${PROJECT_SOURCE_DIR}/src/*.cpp ${PROJECT_SOURCE_DIR}/src/*.cu)
include_directories(${PROJECT_SOURCE_DIR}/include/)
#DL-libtorch
if(LIBTORCH)
if(UNIX)
link_directories("/usr/local/cuda/lib64")
set(Torch_DIR /usr/local/libtorch/share/cmake/Torch)
find_package(Torch REQUIRED)
include_directories(${TORCH_INCLUDE_DIRS})
link_directories(${TORCH_LIBRARIES})
endif()
endif()
#DL-tensorrt
if(TENSORRT)
if(UNIX)
include_directories(/usr/local/cuda/include)
link_directories(/usr/local/cuda/lib64)
include_directories(/usr/local/TensorRT-8.2.2.1/include)
link_directories(/usr/local/TensorRT-8.2.2.1/lib)
enable_language(CUDA)
option(CUDA_USE_STATIC_CUDA_RUNTIME OFF)
set(SRC_FILES ${SRC_FILES} ${SRCS})
endif()
endif()
add_executable(yolov5_det main.cpp ${SRCS})
target_link_libraries(yolov5_det ${OpenCV_LIBS})
#this is necessary.whether the error "undefined reference to `createInferRuntime_INTERNAL'" can occurs.
target_link_libraries(yolov5_det nvinfer)
target_link_libraries(yolov5_det cudart)
注意:这里的nvinfer、跟cudart是一定要的,否则不管在linux跟window下会导致如下报错:
因为整个编译文档无法是通过include_directories制定头文件路径,然后link_directories通过制定库文件路径接着还需要target_link_libraries来把对应库文件添加进来。