CMakeLists入门

目录

    • 基础
    • 增加依赖库
    • 将 .cpp文件 编译成一个库,供其他文件调用
    • 变量名
    • list
    • 自动检测编译器是否支持C++11
    • add_definitions
    • include_directories
    • target_include_directories
    • 调用外部shell命令
    • 参考

基础

首先构建一个CMake目录。ubuntu下的CMake项目通常有几个文件夹组成。
一般

  • bin文件夹用来存放编译好的可执行二进制文件
  • src用来放源代码
  • lib用来放编译好的库文件
  • include用来放头文件

基本的CMakeLists.txt:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8) # 设定版本
PROJECT(git_test) # 设定工程名
set(CMAKE_CXX_COMPILER "g++") # 设定编译器

#设定可执行二进制文件的目录
SET( EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)

#设定存放编译出来的库文件的目录
SET( LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

#并且把该目录设为连接目录
LINK_DIRECTORIES( ${PROJECT_SOURCE_DIR}/lib)
#link_directories()

#设定头文件目录
INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}/include)
#include_directories()

#增加子文件夹,也就是进入源代码文件夹继续构建
ADD_SUBDIRECTORY( ${PROJECT_SOURCE_DIR}/src)

增加依赖库

# 增加PCL库的依赖
FIND_PACKAGE( PCL REQUIRED COMPONENTS common io )

# 增加opencv的依赖
FIND_PACKAGE( OpenCV REQUIRED )

# 将 -D 定义标志添加到源文件的编译中。
# 例如在编译某些项目源码的时候,有提示可以使用相关cmake设置,指令使用方式为 cmake -DTHIRD_PARTY_MIRROR=aliyun .. 
ADD_DEFINITIONS( ${PCL_DEFINITIONS} )
#设定头文件目录
INCLUDE_DIRECTORIES( ${PCL_INCLUDE_DIRS}  )
# link_libraries用来链接静态库,target_link_libraries用来链接导入库
LINK_LIBRARIES( ${PCL_LIBRARY_DIRS} )

# 增加一个可执行的二进制
ADD_EXECUTABLE( generate_pointcloud generatePointCloud.cpp )

TARGET_LINK_LIBRARIES( generate_pointcloud ${OpenCV_LIBS} 
    ${PCL_LIBRARIES} )
# 可以在find_package()前设定_DIR,指向包含Config.cmake或-config.cmake的目录。
# _ROOT先设定,再设定_DIR,最后find_package();并且两个都能找到包,则_DIR起作用
set(OpenCV_ROOT "/home/nio/3rdparty/opencv-4.4.0/build")
set(OpenCV_DIR "/home/nio/3rdparty/opencv-4.4.0/build")

# 查找PCL库(查找依赖包)
# find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
# version和EXACT: 都是可选的,version指定的是版本,如果指定就必须检查找到的包的版本是否和version兼容。如果指定EXACT则表示必须完全匹配的版本而不是兼容版本就可以。
# QUIET 可选字段,表示如果查找失败,不会在屏幕进行输出(但是如果指定了REQUIRED字段,则QUIET无效,仍然会输出查找失败提示语)
# MODULE 可选字段。前面提到说“如果Module模式查找失败则回退到Config模式进行查找”,但是假如设定了MODULE选项,那么就只在Module模式查找,如果Module模式下查找失败并不回落到Config模式查找。
# REQUIRED可选字段。表示一定要找到包,找不到的话就立即停掉整个cmake。而如果不指定REQUIRED则cmake会继续执行。
FIND_PACKAGE( PCL REQUIRED COMPONENTS common io )

# find_package()会把一整个依赖包的头文件包含路径、库路径、库名字、版本号等情况都获取到
# message 输出信息
message(STATUS "OpenCV library status:")
message(STATUS "    version: ${OpenCV_VERSION}")
message(STATUS "    libraries: ${OpenCV_LIBS}")
message(STATUS "    include path: ${OpenCV_INCLUDE_DIRS}")

# 增加opencv的依赖
FIND_PACKAGE( OpenCV REQUIRED )

# 添加头文件和库文件
# add_definitions()
ADD_DEFINITIONS( ${PCL_DEFINITIONS} )
INCLUDE_DIRECTORIES( ${PCL_INCLUDE_DIRS}  )
LINK_LIBRARIES( ${PCL_LIBRARY_DIRS} )

ADD_EXECUTABLE( test2 test2.cpp )
TARGET_LINK_LIBRARIES( test2
        ${OpenCV_LIBS}
        ${PCL_LIBRARIES} )


将 .cpp文件 编译成一个库,供其他文件调用

ADD_LIBRARY( slambase slamBase.cpp )
TARGET_LINK_LIBRARIES( slambase
    ${OpenCV_LIBS} 
    ${PCL_LIBRARIES} )
add_library( [STATIC | SHARED | MODULE]   [EXCLUDE_FROM_ALL] source1 [source2 ...])
  • :库的名字,直接写名字即可,不要写lib,会自动加上前缀的哈。

  • [STATIC | SHARED | MODULE] :
    SHARED: 动态库
    STATIC: 静态库
    MODULE: 在使用 dyld 的系统有效,如果不支持 dyld,则被当作 SHARED 对待。

  • EXCLUDE_FROM_ALL:这个库不会被默认构建,除非有其他的组件依赖或者手
    工构建。

变量名

PROJECT_SOURCE_DIR : 使用cmake命令后紧跟的目标,一般是工程的根目录
PROJECT_BINARY_DIR : 执行cmake命令的目录,通常是${PROJECT_SOURCE_DIR}/build
CMAKE_INCLUDE_PATH : 系统环境变量,非cmake变量
CMAKE_LIBRARY_PATH:系统环境变量,非cmake变量
CMAKE_CURRENT_SOURCE_DIR:当前处理的CMakeLists.txt所在的路径
CMAKE_CURRENT_BINARY_DIR:target编译目录(使用ADD_SURDIRECTORY(src bin)可以更改此变量的值 ,SET(EXECUTABLE_OUTPUT_PATH <新路径>)并不会对此变量有影响,只是改变了最终目标文件的存储路径)
CMAKE_CURRENT_LIST_FILE:输出调用这个变量的CMakeLists.txt的完整路径
CMAKE_CURRENT_LIST_LINE:输出这个变量所在的行
CMAKE_MODULE_PATH:定义自己的cmake模块所在的路径(这个变量用于定义自己的cmake模块所在的路径,如果你的工程比较复杂,有可能自己编写一些cmake模块,比如SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),然后可以用INCLUDE命令来调用自己的模块)
EXECUTABLE_OUTPUT_PATH:重新定义目标二进制可执行文件的存放位置
LIBRARY_OUTPUT_PATH:重新定义目标链接库文件的存放位置
PROJECT_NAME:返回通过PROJECT指令定义的项目名称CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS:用来控制IF ELSE语句的书写方式
CMAKE_MAJOR_VERSION:make主版本号,如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
CAMKE_SYSTEM_NAME:操作系统名称,不包括版本名,如Linux
CMAKE_SYSTEM_VERSION:操作系统版本号,如2.6.22
CMAKE_SYSTEM_PROCESSOR:电脑处理器名称,如i686
UNIX:在所有的类UNIX平台为TRUE,包括OS X和cygwin,Linux/Unix操作系统
WIN32:在所有的win32平台为TRUE,包括cygwin,Windows操作系统
APPLE:苹果操作系统;

list

list (subcommand  [args...])
  • subcommand为具体的列表操作子命令,例如读取、查找、修改、排序等。
  • 为待操作的列表变量
  • [args…]为对列表变量操作需要使用的参数表,不同的子命令对应的参数也不一致。

自动检测编译器是否支持C++11

include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
    message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()

add_definitions

add_definitions的功能和C/C++中的#define是一样的
比如我有如下两个文件,一个源文件main.cpp,一个CMakeLists.txt
源文件main.cpp

#include <iostream>
int main()
{
#ifdef TEST_IT_CMAKE
	std::cout<<"in ifdef"<<std::endl;
#endif
	std::cout<<"not in ifdef"<<std::endl;
}

cmake文件CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(optiontest)

add_executable(optiontest main.cpp)
option(TEST_IT_CMAKE "test" ON)
message(${TEST_IT_CMAKE})
if(TEST_IT_CMAKE)
	message("itis" ${TEST_IT_CMAKE})
	add_definitions(-DTEST_IT_CMAKE)
endif()

通过option设置一个变量,并通过add_definitions将其转换为#define TEST_IT_CMAKE

  • 当变量为ON时 option(TEST_IT_CMAKE "test" ON)

该程序的输出是

in ifdef
not in ifdef
  • 当变量为OFF时 option(TEST_IT_CMAKE "test" OFF)

该程序的输出为

not in ifdef

include_directories

将指定目录添加到编译器的头文件搜索路径之下,指定的目录被解释成当前源码路径的相对路径。
语法格式:

include_directories ([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])

默认情况下,include_directories命令会将目录添加到列表最后(AFTER选项)。不过,可以通过命令设置CMAKE_INCLUDE_DIRECTORIES_BEFORE 变量为ON来改变它的默认行为,将目录添加到列表前面。也可以在每次调用include_directories命令时使用AFTER或BEFORE选项来指定是添加到列表的前面或者后面。如果使用SYSTEM选项,会把指定目录当成系统的搜索目录。该命令作用范围只在当前的CMakeLists.txt。

例如,在Linux下,C编译器默认搜索路径:

/usr/include
/usr/local/include

如果我们项目根目录下,有个公共头文件目录include1、include2需要添加到C编译器的默认搜索路径,可以在CMakeLists.txt中添加:

include_directories(include1) # 注意当前CMakeLists.txt和include1相对路径关系, 此时必须是在同一个目录下
include_directories(${PROJECT_SOURCE_DIR}/include2) # 通过源码根目录来定位include2

target_include_directories

为指定目标(target)添加搜索路径,指定目标是指通过如add_executable(),add_library()这样的命令生成的,并且决不能是alias target(引用目标,别名目标)。
语法格式:

target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]  <INTERFACE|PUBLIC|PRIVATE> [items1...]  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])

调用外部shell命令

EXECUTE_PROCESS(COMMAND git describe --tags
			TIMEOUT 5
			OUTPUT_VARIABLE VERSION
			OUTPUT_STRIP_TRAILING_WHITESPACE
			)
MESSAGE(STATUS "BUILD FROM GIT TAG ${VERSION}")

这段CMake代码使用EXECUTE_PROCESS命令调用外部命令git describe --tags,以获取当前Git仓库的最近标签(tag)。让我们逐个解释这段代码的含义:

EXECUTE_PROCESS: 这是CMake中的命令,用于在构建过程中执行外部命令。它可以调用系统的shell,并执行指定的命令。

COMMAND git describe --tags: 这是EXECUTE_PROCESS命令中的COMMAND选项,它指定要执行的外部命令。在这里,我们要执行的命令是git describe --tags

git describe --tags: 这个Git命令用于获取最近的标签(tag)。它会找到最近的标签,并根据当前的提交信息生成一个描述信息,通常是由标签名和一些提交信息组成的字符串。例如,类似于v1.2.3-5-gabcdef,其中v1.2.3是最近的标签名,5表示当前提交与标签之间有5个提交,abcdef是当前提交的哈希值。

TIMEOUT 5: 这是EXECUTE_PROCESS命令中的TIMEOUT选项,它设置了执行外部命令的最大超时时间,单位为秒。在这里,设置为5秒,意味着如果执行git describe --tags命令超过5秒,将会被终止。

OUTPUT_VARIABLE VERSION: 这是EXECUTE_PROCESS命令中的OUTPUT_VARIABLE选项,它指定一个变量名VERSION,用于存储外部命令的输出结果。

OUTPUT_STRIP_TRAILING_WHITESPACE: 这是EXECUTE_PROCESS命令中的另一个选项,它告诉CMake将输出结果中的末尾空格(包括换行符)去掉。这样可以确保获取的标签信息没有额外的空格。

参考

https://blog.csdn.net/qq_35699473/article/details/115837708
https://www.cnblogs.com/fortunely/p/16297077.html

你可能感兴趣的:(ubuntu,cmake)