cmake之CMakelist.txt的使用

常用命令

1. 指定 cmake 的最小版本

cmake_minimum_required(VERSION 3.22.1)

2. 打印信息

2.1. 打印普通信息
message(${PROJECT_SOURCE_DIR})
message("some message")
2.2. 打印告警
message(WARNING "warnning message")
2.3. 打印错误

FATAL_ERROR 会导致编译失败,可配合条件判断使用

message(FATAL_ERROR "error message")

3. 项目名称

project(demo)

可选项,它会引入两个变量 demo_BINARY_DIRdemo_SOURCE_DIR
同时cmake自动定义两个变量 PROJECT_BINARY_DIRPROJECT_SOURCE_DIR

4. 设置变量

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wall -fPIC")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -O3 -Wall -fPIC")
set(CMAKE_BUILD_TYPE Release)
set(TARGET test)
set(CMAKE_INSTALL_PREFIX "../install")

5. 查找指定的库文件

同类型的命令有:

find_file()
find_path()
find_program()
find_package()
find_library()

用法:
find_library(VAR name path)查找到指定的预编译库,并将它的路径存储在变量中。
默认的搜索路径为 cmake 包含的系统库,因此如果是 NDK 的公共库只需要指定库的 name 即可。

find_library(log-lib log )
set(CMAKE_PREFIX_PATH "/home/libtorch_170/share/cmake/Torch")
find_package(Torch REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${TORCH_CXX_FLAGS}")

set(OpenCV_DIR "/home/opencv450/install/lib/cmake/opencv4")
find_package(OpenCV 4 REQUIRED)

6. 设置包含的目录

include_directories(
    ${PROJECT_SOURCE_DIR}/include
    ${CMAKE_CURRENT_SOURCE_DIR}
    ${CMAKE_CURRENT_BINARY_DIR}
    ${CMAKE_CURRENT_SOURCE_DIR}/include
)

Linux 下还可以通过如下方式设置包含的目录

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}")

7. 设置链接库搜索目录

link_directories(
     ${CMAKE_CURRENT_SOURCE_DIR}/libs
 )

Linux 下还可以通过如下方式设置包含的目录

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_CURRENT_SOURCE_DIR}/libs")

8. 指定编译包含的源文件

8.1 明确指定包含哪些源文件
add_library(demo demo.cpp test.cpp util.cpp)
8.2 搜索所有的 cpp 文件

aux_source_directory(dir VAR) 发现一个目录下所有的源代码文件并将列表存储在一个变量中。

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})
# 或者
aux_source_directory(. SRC_LIST)
aux_source_directory(protocol SRC_PROTOCOL_LIST)
add_library(demo ${SRC_LIST} ${SRC_PROTOCOL_LIST})

9. 设置编译类型

add_executable(demo demo.cpp)       # 生成可执行文件
add_library(common STATIC util.cpp) # 生成静态库
add_library(common SHARED util.cpp) # 生成动态库或共享库

add_library 默认生成是静态库,通过以上命令生成文件名字,

在 Linux 下是:
demo
libcommon.a
libcommon.so

在 Windows 下是:
demo.exe
common.lib
common.dll

10. 设置 target 需要链接的库

库的路径可以通过设置链接库搜索目录添加

target_link_libraries( ${TARGET} #这是生成的目标
	# 然后下面是生成目标所需要链接的库,如:
	${TORCH_LIBRARIES}
	${OpenCV_LIBS} 
	dl 
	m 
	pthread 
	rt 
)

11. 包含其它 cmake 文件

include(./common.cmake) # 指定包含文件的全路径
include(def) 			# 在搜索路径中搜索def.cmake文件
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # 设置include的搜索路径

12. 重命名

此处的TARGET为生成的名字,以name为例

set(TARGET name)
12.1. 添加后缀

生成类似这样的动态库libname_message.so

set(CMAKE_RELEASE_POSTFIX "_message")  	#这条命令需要放在add_library之前
add_library(${TARGET} SHARED ${SRC_LIST})

生成类似这样的可执行文件name_message

add_executable(${TARGET}  ${SRC_LIST}) 
set_target_properties(${TARGET} PROPERTIES RELEASE_POSTFIX "_message")
12.2. 添加版本号

生成类似这样的动态库libname.so.x.y.z
最前面使用前缀lib,中间为库的名字,后缀为.so,后面跟着 3 个数字组成的版本号。"x"表示**主版本号,"y"表示次版本号,"z"表示发布版本号。

VERSION:完整版本号 SOVERSION:SONAME

set_target_properties(${TARGET} PROPERTIES VERSION 1.0.0 SOVERSION 1) 
12.3. 重命名

如果不想用name,想换个名字;将“name”换成“hello”

set_target_properties (${TARGET} PROPERTIES OUTPUT_NAME "hello")

13. install安装

安装的方式有两种,一种是执行cmake的时候指定安装目录:

cmake -DCMAKE_INSTALL_PREFIX=../install  ..

另一种是在CMakelist.txt 中设置安装的根路径:

set(CMAKE_INSTALL_PREFIX ../PATH)
INSTALL指令用于定义安装规则,安装的内容可以包括目标二进制、动态库、静态库以及
文件、目录、脚本等。
13.1 目标文件的安装
INSTALL(TARGETS targets...
	[[ARCHIVE|LIBRARY|RUNTIME]
	[DESTINATION <dir>]
	[PERMISSIONS permissions...]
	[CONFIGURATIONS
	[Debug|Release|...]]
	[COMPONENT <component>]
	[OPTIONAL]
	] [...]
)

参数中的TARGETS后面跟的就是我们通过ADD_EXECUTABLE或者ADD_LIBRARY定义的
目标文件,可能是可执行二进制、动态库、静态库。

目标类型也就相对应的有三种,ARCHIVE特指静态库,LIBRARY特指动态库,RUNTIME
特指可执行目标二进制。

DESTINATION定义了安装的路径,如果路径以/开头,那么指的是绝对路径,这时候
CMAKE_INSTALL_PREFIX其实就无效了。如果你希望使用CMAKE_INSTALL_PREFIX来
定义安装路径,就要写成相对路径,即不要以/开头,那么安装后的路径就是
${CMAKE_INSTALL_PREFIX}/<DESTINATION定义的路径>

简单的例子:

#如果 demo 是可执行文件则会安装到${CMAKE_INSTALL_PREFIX}/bin目录  
#如果是动态库则会安装到${CMAKE_INSTALL_PREFIX}/lib目录  
#如果是静态库则会安装到${CMAKE_INSTALL_PREFIX}/libstatic目录

install(TARGETS ${TARGET}
       RUNTIME DESTINATION bin          #可执行文件安装路径(追加)
       LIBRARY DESTINATION lib          #动态库文件安装路径(追加)
       ARCHIVE DESTINATION libstatic    #静态库文件安装路径(追加)
)
13.2 普通文件的安装
INSTALL(FILES files... DESTINATION <dir>
         [PERMISSIONS permissions...]
         [CONFIGURATIONS [Debug|Release|...]]
         [COMPONENT <component>]
         [RENAME <name>] [OPTIONAL])
可用于安装一般文件,并可以指定访问权限,文件名是此指令所在路径下的相对路径。
如果默认不定义权限PERMISSIONS,安装后的权限为,OWNER_WRITE,OWNER_READ,
GROUP_READ,和WORLD_READ,即644权限。

简单的例子:

install (FILES ${PROJECT_SOURCE_DIR}/include/mpt_study.h ${PROJECT_SOURCE_DIR}/include/mpt_public.h                 #安装文件
    DESTINATION include                                                     #普通文件安装路径(追加)
    PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ                #权限
)
13.3 非目标文件的可执行程序安装(比如脚本之类)
INSTALL(PROGRAMS files... DESTINATION <dir>
     [PERMISSIONS permissions...]
     [CONFIGURATIONS [Debug|Release|...]]
     [COMPONENT <component>]
     [RENAME <name>] [OPTIONAL])
跟上面的FILES指令使用方法一样,唯一的不同是安装后权限为:
OWNER_EXECUTE, GROUP_EXECUTE, 和WORLD_EXECUTE,即755权限

简单的例子:

install (PROGRAMS ${PROJECT_SOURCE_DIR}/compile.sh                          #安装文件
    DESTINATION SHPATH                                                      #普通文件安装路径(追加)
    PERMISSIONS OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE                   #权限
)
13.4 目录的安装
INSTALL(DIRECTORY dirs... DESTINATION <dir>
    [FILE_PERMISSIONS permissions...]
    [DIRECTORY_PERMISSIONS permissions...]
    [USE_SOURCE_PERMISSIONS]
    [CONFIGURATIONS [Debug|Release|...]]
    [COMPONENT <component>]
    [[PATTERN <pattern> | REGEX <regex>]
    [EXCLUDE] [PERMISSIONS permissions...]] [...])
这里主要介绍其中的DIRECTORY、PATTERN以及PERMISSIONS参数。
DIRECTORY后面连接的是所在Source目录的相对路径,但务必注意:
abc和abc/有很大的区别。
abc意味着abc这个目录会安装在目标路径下;
abc/意味着abc这个目录的内容会被安装在目标路径下;
如果目录名不以/结尾,那么这个目录将被安装为目标路径下的abc,如果目录名以/结尾,
代表将这个目录中的内容安装到目标路径,但不包括这个目录本身。
PATTERN用于使用正则表达式进行过滤,
PERMISSIONS用于指定PATTERN过滤后的文件权限。

简单的例子:

#install 目录安装
INSTALL(DIRECTORY icons scripts/                                                #安装目录文件    icons整个文件夹  scripts文件夹下的文件(不包含文件夹) 
    DESTINATION cpdir                                                           #目录安装路径
    PATTERN "CVS" EXCLUDE                                                       #过滤掉 CVS
    PATTERN "scripts/*"                                                         #选中所有文件
    PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ   #权限
)

这条指令的执行结果是:
将icons目录安装到 <prefix>/share/myproj,将scripts/中的内容安装到
<prefix>/share/myproj
不包含目录名为CVS的目录,对于scripts/*文件指定权限为 OWNER_EXECUTE
OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ.

条件控制

1. if…elseif…else…endif

逻辑判断和比较:
if (expression):expression 不为空(0,N,NO,OFF,FALSE,NOTFOUND)时为真
if (not exp):与上面相反
if (var1 AND var2)
if (var1 OR var2)
if (COMMAND cmd):如果 cmd 确实是命令并可调用为真
if (EXISTS dir) if (EXISTS file):如果目录或文件存在为真
if (file1 IS_NEWER_THAN file2):当 file1 比 file2 新,或 file1/file2 中有一个不存在时为真,文件名需使用全路径
if (IS_DIRECTORY dir):当 dir 是目录时为真
if (DEFINED var):如果变量被定义为真
if (var MATCHES regex):给定的变量或者字符串能够匹配正则表达式 regex 时为真,此处 var 可以用 var 名,也可以用 ${var}
if (string MATCHES regex)

数字比较:
if (variable LESS number):LESS 小于
if (string LESS number)
if (variable GREATER number):GREATER 大于
if (string GREATER number)
if (variable EQUAL number):EQUAL 等于
if (string EQUAL number)

字母表顺序比较:
if (variable STRLESS string)
if (string STRLESS string)
if (variable STRGREATER string)
if (string STRGREATER string)
if (variable STREQUAL string)
if (string STREQUAL string)

示例:

    if(MSVC)
        set(LINK_LIBS common)
    else()
        set(boost_thread boost_log.a boost_system.a)
    endif()
    target_link_libraries(demo ${LINK_LIBS})
    # 或者
    if(UNIX)
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fpermissive -g")
    else()
        add_definitions(-D_SCL_SECURE_NO_WARNINGS
        D_CRT_SECURE_NO_WARNINGS
        -D_WIN32_WINNT=0x601
        -D_WINSOCK_DEPRECATED_NO_WARNINGS)
    endif()
     
    if(${CMAKE_BUILD_TYPE} MATCHES "debug")
        ...
    else()
        ...
    endif()

2. while…endwhile

    while(condition)
        ...
    endwhile()

3. foreach…endforeach

    foreach(loop_var RANGE start stop [step])
        ...
    endforeach(loop_var)

start 表示起始数,stop 表示终止数,step 表示步长,示例:

    foreach(i RANGE 1 9 2)
        message(${i})
    endforeach(i)
    # 输出:13579

常用变量

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. 环境变量

使用环境变量

 $ENV{Name}

写入环境变量

 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() 添加
add_definitions(-DENABLE_DEBUG -DABC) # 参数之间用空格分隔

cmake指定特定版本gcc、g++

cmake -D CMAKE_C_COMPILER=/path/to/gcc/bin/gcc -D CMAKE_CXX_COMPILER=/path/to/gcc/bin/g++ 
  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值