CmakeList使用
序言:参考文章1 参考文章2 参考文章3
cmake 是一个跨平台、开源的构建系统。它是一个集软件构建、测试、打包于一身的软件。它使用与平台和编译器独立的配置文件来对软件编译过程进行控制。
一个c++程序编译需要包含:源文件、引用库以及相关头文件、第三方库以及相关路径,cmakelist.txt文件主要任务就是对这些文件进行查找、链接。
一、常用变量
1、预定义变量
PROJECT_SOURCE_DIR:工程的根目录 PROJECT_BINARY_DIR:运行 cmake 命令的目录,通常是 ${PROJECT_SOURCE_DIR}/build PROJECT_NAME:返回通过 project 命令定义的项目名称 CMAKE_CURRENT_SOURCE_DIR:当前处理的 CMakeLists.txt 所在的路径 CMAKE_CURRENT_BINARY_DIR:target 编译目录 CMAKE_CURRENT_LIST_DIR:CMakeLists.txt 的完整路径 CMAKE_CURRENT_LIST_LINE:当前所在的行 CMAKE_MODULE_PATH:定义自己的 cmake 模块所在的路径,SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),然后可以用INCLUDE命令来调用自己的模块 EXECUTABLE_OUTPUT_PATH:重新定义目标二进制可执行文件的存放位置 LIBRARY_OUTPUT_PATH:重新定义目标链接库文件的存放位置
2、环境变量
1、使用环境变量
$ENV{Name}
2、写入环境变量
set(ENV{Name} value) # 这里没有“$”符号
3、系统信息
CMAKE_MAJOR_VERSION:cmake 主版本号,比如 3.4.1 中的 3 -CMAKE_MINOR_VERSION:cmake 次版本号,比如 3.4.1 中的 4 CMAKE_PATCH_VERSION:cmake 补丁等级,比如 3.4.1 中的 1 -CMAKE_SYSTEM:系统名称,比如 Linux--2.6.22 -CMAKE_SYSTEM_NAME:不包含版本的系统名,比如 Linux -CMAKE_SYSTEM_VERSION:系统版本,比如 2.6.22 -CMAKE_SYSTEM_PROCESSOR:处理器名称,比如 i686 UNIX:在所有的类 UNIX 平台下该值为 TRUE,包括 OS X 和 cygwin WIN32:在所有的 win32 平台下该值为 TRUE,包括 cygwin
4、主要开关选项
BUILD_SHARED_LIBS:这个开关用来控制默认的库编译方式,如果不进行设置,使用 add_library 又没有指定库类型的情况下,默认编译生成的库都是静态库。如果 set(BUILD_SHARED_LIBS ON) 后,默认生成的为动态库 CMAKE_C_FLAGS:设置 C 编译选项,也可以通过指令 add_definitions() 添加 CMAKE_CXX_FLAGS:设置 C++ 编译选项,也可以通过指令 add_definitions() 添加
二、常用命令(使用示例进行说明)
1、指定 cmake 的最小版本
#这行命令是可选的,我们可以不写这句话,但在有些情况下,
#如果 CMakeLists.txt 文件中使用了一些高版本 cmake 特有的一些命令的时候,就需要加上这样一行,提醒用户升级到该版本之后再执行 cmake。
cmake_minimum_required(VERSION 3.1)
2、设置项目名称
#这个命令不是强制性的,但最好都加上。它会引入两个变量 demo_BINARY_DIR 和 demo_SOURCE_DIR,
#同时,cmake 自动定义了两个等价的变量 PROJECT_BINARY_DIR 和 PROJECT_SOURCE_DIR。
project(DEMO)
#-------------------------------------- 编译器设置 --------------------------------------#
3、set命令
语法: SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
指令功能: 用来显式的定义变量
例子: SET (SRC_LST main.c other.c)
说明: 用变量代替值,例子中定义SRC_LST代替后面的字符串
#set命令可以看成定义变量,可以将长路径用变量代替,并且可进行拼接
#3.1 set 直接设置变量的值
set(SRC_LIST main.cpp test.cpp)
add_executable(demo ${SRC_LIST})
#3.2 set 追加设置变量的值
set(SRC_LIST main.cpp)
set(SRC_LIST ${SRC_LIST} test.cpp)
add_executable(demo ${SRC_LIST})
#3.3 list 追加或者删除变量的值
set(SRC_LIST main.cpp)
list(APPEND SRC_LIST test.cpp)
list(REMOVE_ITEM SRC_LIST main.cpp)
add_executable(demo ${SRC_LIST})
#以下是程序中对编译器进行设置
set(CMAKE_BUILD_TYPE Debug) #设置编译类型为debug
set(CMAKE_CXX_STANDARD 11) #设置C++版本为C11
set(CMAKE_INCLUDE_CURRENT_DIR ON) #设置当前包含的头文件开启
#设置opencv路径
set(OpenCV_DIR /usr/local/lib/cmake/opencv4)
set(OpenCV_INCLUDE_DIRS /usr/local/include/opencv4)
#-------------------------------------- 搜索软件包 --------------------------------------#
4、find_package
#使用背景:当编译一个需要使用第三方库的软件时,我们需要知道:
去哪儿找头文件 .h 对比GCC的 -I 参数 ——INCLUDE_DIRECTORIES——
去哪儿找库文件 (.so/.dll/.lib/.dylib/…) 对比GCC的 -L 参数 ——LINK_DIRECTORIES——
需要链接的库文件的名字 对比GCC的 -l 参数 ——LINK_LIBRARIES——
#比如说,我们需要一个第三方库 curl,那么我们的 CMakeLists.txt 需要指定头文件目录,和库文件,类似:
include_directiories(/usr/include/curl)
target_link_libraries(myprogram path/curl.so)
#如果借助于cmake提供的finder会怎么样呢?使用cmake的Modules目录下的FindCURL.cmake,相应的CMakeList.txt 文件:
find_package(CURL REQUIRED) #REQUIRED参数,没找到的话cmake执行失败
include_directories(${CURL_INCLUDE_DIR})
target_link_libraries(curltest ${CURL_LIBRARY})
#具体实例如下:
# Find the QtWidgets library
find_package(Qt5 COMPONENTS Widgets REQUIRED)
find_package(OpenCV REQUIRED)
find_package(CUDA REQUIRED)
#追加 LIBRARIES 路径
list(APPEND LIBRARIES ${CUDA_LIBRARIES})
list(APPEND LIBRARIES ${CUDA_CUBLAS_LIBRARIES})
5、message
#打印信息,可以进行路径验证,方便查错
message(STATUS "CUDA library status:")
message(STATUS "version: ${CUDA_VERSION}")
message(STATUS "*****libraries: ${CUDA_LIBRARIES}")
message(STATUS "\n include path*****: ${CUDA_INCLUDE_DIRS}")
message(STATUS "\n OpenCV include path*****: ${OpenCV_INCLUDE_DIRS}")
message(STATUS "*****CUDACUBLAS libraries: ${CUDA_CUBLAS_LIBRARIES}")
#-------------------------------------- 包含头文件 --------------------------------------#
#CMake支持大写、小写、混合大小写的命令
#引用第三方库需要
#1、在哪找头文件 include_directories
#2、在哪找库文件 link_directories
#3、库文件名称 target_link_libraries
6、include_directories
#添加第三方库包含的目录(即找头文件)
include_directories(${Caffe_INCLUDE_DIRS}) #设置包含caffe组件头文件的路径
7、link_directories
# 添加需要链接的库文件目录(即找 .so库文件)
link_directories(${Caffe_LIB_DIRS})
#添加常见包含路径
include_directories(include
${Qt5Widgets_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
${CUDA_INCLUDE_DIRS}
${EIGEN3_INCLUDE_DIR}
${FFmpeg_include_path}
)
include_directories(${CMAKE_CURRENT_BINARY_DIR}) #target 编译目录
#-------------------------------------- -添加项目- --------------------------------------#
#添加所有的源文件
SET(DEMO_SOURCES main.cpp xxx.cpp) #.cpp
SET(DEMO_HEADERS xxx.h) #.h
SET(DEMO_FORMS Display.ui) #.ui
SET(DEMO_QRC_FILE Resource.qrc) #.qrc
qt5_add_resources(QRC ${DEMO_QRC_FILE})
#调用预编译器moc,需要使用 QT5_WRAP_CPP宏
QT5_WRAP_CPP(DEMO_HEADERS_MOC ${DEMO_HEADERS})
#使用uic处理.ui文件
QT5_WRAP_UI(DEMO_FORMS_HEADERS ${DEMO_FORMS})
8、 指定编译包含的源文件
#8.1 明确指定包含哪些源文件
add_library(demo demo.cpp test.cpp util.cpp)
#8.2 搜索所有的 cpp 文件
aux_source_directory(. SRC_LIST) # 搜索当前目录下的所有.cpp文件
add_library(demo ${SRC_LIST})
#8.3 自定义搜索规则
file(GLOB SRC_LIST "*.cpp" "protocol/*.cpp")
add_library(demo ${SRC_LIST})
# 或者
file(GLOB SRC_LIST "*.cpp")
file(GLOB SRC_PROTOCOL_LIST "protocol/*.cpp")
add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})
# 或者
file(GLOB_RECURSE SRC_LIST "*.cpp") #递归搜索
FILE(GLOB SRC_PROTOCOL RELATIVE "protocol" "*.cpp") # 相对protocol目录下搜索
add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})
# 或者
aux_source_directory(. SRC_LIST)
aux_source_directory(protocol SRC_PROTOCOL_LIST)
add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})
#具体实例如下:
LINK_DIRECTORIES(${PROJECT_SOURCE_DIR})#工程的根目录
file(GLOB_RECURSE HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h*)#当前处理的 CMakeLists.txt 所在的路径/include
9、find_library
#查找到指定的预编译库,并将它的路径存储在变量中
#默认的搜索路径为 cmake 包含的系统库,因此如果是 NDK 的公共库只需要指定库的 name 即可
find_library(streamhk NAMES libstreamhk.so REQUIRED)
find_library(rqueue NAMES librqueue.so REQUIRED)
message(STATUS "streamhk:" ${streamhk})
message(STATUS "rqueue:" ${rqueue})
#-------------------------------------- -添加所有的源文件- --------------------------------------#
SET(DEMO_SOURCES main.cpp xxx.cpp) #.cpp
SET(DEMO_HEADERS xxx.h) #.h
SET(DEMO_FORMS Display.ui) #.ui
SET(DEMO_QRC_FILE Resource.qrc) #.qrc
qt5_add_resources(QRC ${DEMO_QRC_FILE}
QT5_WRAP_CPP(DEMO_HEADERS_MOC ${DEMO_HEADERS})
QT5_WRAP_UI(DEMO_FORMS_HEADERS ${DEMO_FORMS})
#-------------------------------------- -生成可以执行的文件- --------------------------------------#
add_executable(DEMO
${DEMO_SOURCES}
${DEMO_HEADERS_MOC}
${DEMO_FORMS_HEADERS}
${HEADER_FILES}
${QRC}
)
#===================================================#
#TARGET_LINK_LIBRARIES (设置要链接的库文件的名称)
#语法:TARGET_LINK_LIBRARIES(targetlibrary1 <debug | optimized> library2 ..)
比如(以下写法(包括备注中的)都可以):
TARGET_LINK_LIBRARIES(myProject hello),连接libhello.so库
TARGET_LINK_LIBRARIES(myProject libhello.a)
TARGET_LINK_LIBRARIES(myProject libhello.so)
再如:
TARGET_LINK_LIBRARIES(myProject libeng.so) #这些库名写法都可以。
TARGET_LINK_LIBRARIES(myProject eng)
TARGET_LINK_LIBRARIES(myProject -leng)
#===================================================#
#-------------------------------------- -链接第三方库- --------------------------------------#
target_link_libraries(DEMO
${Qt5Widgets_LIBRARIES}
${streamhk}
${rqueue}
/usr/lib/x86_64-linux-gnu/libgflags.so
/usr/lib/x86_64-linux-gnu/libglog.so
${OpenCV_LIBRARIES}
${caffe}
${nvcuvid}
/usr/local/cuda-10.0/lib64/libcudart.so
/usr/local/cuda-10.0/lib64/stubs/libcuda.so
-lpthread
libavformat.so
libavcodec.so
libswscale.so
libavutil.so
)
#-------------------------------------- -生成可执行文件(二进制文件)- --------------------------------------#
install(TARGETS DEMO RUNTIME DESTINATION ${CMAKE_SOURCE_DIR})
#===================================================#
#INSTALL 命令用于定义安装规则,安装内容包括可执行文件,静态库,动态库以及文件,目录,脚本等
#命令格式:
INSTALL(TARGETS target...
[ [ARCHIVE|LIBRARY|RUNTIME]
[DESTINATION <dir>]
] [...])
命令解释:
TARGETS 后面跟的可能是二进制,动态库,静态库中的某一种或者全是
目标类型也相对的有三种: ARCHIVE特指静态库,LIBRARY特指动态库,RUNTIME特质可执行目标二进制
DESTINATION 定义安装路径,如果以" /" 开头,则说明指定的是绝对路径,此时的CMAKE_INSTALL_PREFIX就无效了
#===================================================#
|