Cmake 整理

cmake是什么

CMake是一个跨平台的编译(Build)工具,可以用简单的语句来描述所有平台的编译过程。

CMake和makefile

Cmake是用来makefile的一个工具:读入所有源文件之后,自动生成makefile。

在 linux 平台下使用 CMake 生成 Makefile 并编译的流程

  1. 编写 CMake 配置文件 CMakeLists.txt 。
  2. 执行命令 cmake PATH 生成 Makefile。其中, PATH 是 CMakeLists.txt 所在的目录。
  3. 使用 make 命令进行编译。

CmakeList

常用命令

1. 指定 cmake 的最小版本

cmake_minimum_required(VERSION 3.4.1)

2. 设置项目名称

project(demo)

3. 指定编译器

CMAKE_CXX_COMPILER | cxx编译器
CMAKE_C_COMPILER | c编译器

4. 设置编译类型

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

5. set

set用于给一般变量,缓存变量,环境变量赋值。

5.1 Set赋值给一般变量
set(FOO  “x”)。         #FOO作用域为当前作用域。
set(FOO "x" PARENT_SCOPE)   #FOO作用域跳上一级。
5.2 Set赋值给缓存变量

什么是缓存变量,缓存变量可以理解为当第一次运行cmake时,这些变量缓存到一份文件中(即编译目录下的CMakeCache.txt)。当再次运行cmake时,这些变量会直接使用缓存值。缓存变量在整个cmake运行过程中都可以起作用。相当于一个全局变量,我们在同一个 cmake 工程中都可以使用。

当使用CACHE时,且缓存(cache)中没有该变量时,变量被创建并存入缓存(cache)中,如果原缓存(cache)中有该变量,也不会改变原缓存中该变量的值,除非后面使用FORCE。

set(FOO, "x" CACHE <type>)  #原缓存中没有FOO则将FOO赋值为x且存入cache中。原缓存中有FOO则不做任何改变,即便原cache中FOO存的不是x。
set(FOO, "x" CACHE <type><docstring> FORCE)    #即便原cache中存在FOO也会创建另一个FOO

使用CACHE的同时,要设定和,可以理解为所存入变量类型,为变量的描述。

分为以下几种类型:

BOOL:有ON/OFF,两种取值
FILEPATH:文件的全路径
PATH:目录路径
STRING:字符串
INTERNAL:字符串
5.3 Set赋值给环境变量
set(ENV{<variable>} [<value>])
  • variable:只能有一个
  • value:一般来说,只有一个,为空时,将清除之前设置的变量值,多个时,取值最近的一个,之后的值将被忽略
message(WARNING $ENV{JAVA_HOME}) #JAVA_HOME是windows中设置的变量

# D:\SoftWare\Java\jdk1.8.0_191

set(ENV{JAVA_HOME} 1)
message(WARNING $ENV{JAVA_HOME})

# 1

set(ENV{DEFINE} DEFINE DEFINE2 DEFINE3) #自定义的变量
message(WARNING $ENV{DEFINE})

# DEFINE

set(a) #没有value值,a值清空
message(WARNING ${a})

# 空
5.4 set 追加值
set(SRC_LIST main.cpp)
set(SRC_LIST ${SRC_LIST} test.cpp)

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

6.1 明确指定包含哪些源文件
add_library(demo demo.cpp test.cpp util.cpp)
set(COMMON
        config.cpp
        util.cpp
        )

add_library(common ${COMMON})
6.2 搜索所有的 cpp 文件

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

aux_source_directory(. SRC_LIST) # 搜索当前目录下的所有.cpp文件
add_library(demo ${SRC_LIST})

7. 引入外部依赖包

find_package(name path)查找到指定的预编译库,并将它的路径存储在变量中。

每个以Find<LibaryName>.cmake命名的文件都可以帮我们找到一个包

每一个模块都会定义以下几个变量

<LibaryName>_FOUND
<LibaryName>_INCLUDE_DIR or <LibaryName>_INCLUDES
<LibaryName>_LIBRARY or <LibaryName>_LIBRARIES
find_package(CURL)
add_executable(curltest curltest.cc)
if(CURL_FOUND)
    target_include_directories(clib PRIVATE ${CURL_INCLUDE_DIR})
    target_link_libraries(curltest ${CURL_LIBRARY})
else(CURL_FOUND)
    message(FATAL_ERROR ”CURL library not found”)
endif(CURL_FOUND)

8. 指定头文件路径

8.1 target_include_directories

指定编译给定目标时要使用的包含目录。名称<target>必须是由命令创建的,例如add_executable()或add_library()生成的target

target_include_directories(t x/y) 具有目标范围——它将 x/y 添加到目标 t 的包含路径中。

关键字

public: 头文件可以提供给依赖的库和自己使用

interface: 头文件提供给依赖的库使用,但自己不使用,场景:封装一个sdk,供外部使用的头文件和内部使用的头文件,这时候就很有用了

private:头文件自己使用,不提供给外部使用

target_include_directories(kylin-mobile-assistant PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}
        ${KYSDKBASE_PKG_INCLUDE_DIRS}
        )
8.2 include_directories

include_directories(x/y) 影响目录范围。 此 CMakeList 中的所有目标,以及在其调用点之后添加的所有子目录中的目标,都会将路径 x/y 添加到它们的包含路径中。

9. 设置链接库搜索目录

target_link_directories(classificationlist PUBLIC
        ${CMAKE_CURRENT_SOURCE_DIR}/libs
        )
link_directories(
    ${CMAKE_CURRENT_SOURCE_DIR}/libs
)

10. 设置 target 需要链接的库

target_link_libraries(kylin-mobile-assistant PUBLIC
        Qt${QT_VERSION_MAJOR}::Widgets
        Qt${QT_VERSION_MAJOR}::Network
        ${KYSDKBASE_PKG_LIBRARIES}
        common
        connectmanage
        projection
        filetransfer
        ui
        )
10.1 指定链接动态库或静态库
target_link_libraries(demo libface.a) # 链接libface.a
target_link_libraries(demo libface.so) # 链接libface.so
10.2 指定全路径
target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.a)
target_link_libraries(demo ${CMAKE_CURRENT_SOURCE_DIR}/libs/libface.so)

11. 打印日志

message(STATUS ...) 
message(${PROJECT_SOURCE_DIR}) # 打印变量
message("build with debug mode")
message(WARNING "this is warnning message")
message(FATAL_ERROR "this build has many error") # FATAL_ERROR 会导致编译失败

# eg: message(STATUS "HELLO WORLD")

12. 逻辑控制

# 条件控制
if(XXX)
else(XXX)
endif(XXX)

# for
foreach(item ${TEST})
    //${item}
endforeach(item)

13. add_executable

使用指定的源文件来生成目标可执行文件。

add_executable(kylin-mobile-assistant
        main.cpp
        )

14. add_subdirectory

添加一个子目录并构建该子目录。

set(SUBDIRECTORIES_MAIN
        common
        connectmanage
        filetransfer
        projection
        ui
        )
foreach (SUBDIRECTORY_MAIN ${SUBDIRECTORIES_MAIN})
    add_subdirectory(${SUBDIRECTORY_MAIN})
endforeach ()

15. install

cmake的时候,最常见的几个步骤就是:

mkdir build && cd build
cmake ..
make
make install

install用于指定在安装时运行的规则。它可以用来安装很多内容,可以包括目标二进制、动态库、静态库以及文件、目录、脚本等

install(TARGETS <target>... [...])
install({FILES | PROGRAMS} <file>... [...])
install(DIRECTORY <dir>... [...])
install(SCRIPT <file> [...])
install(CODE <code> [...])
install(EXPORT <export-name> [...])

该命令的一些参数的含义:

DESTINATION:指定磁盘上要安装文件的目录;
PERMISSIONS:指定安装文件的权限。有效权限是OWNER_READ,OWNER_WRITE,OWNER_EXECUTE,GROUP_READ,GROUP_WRITE,GROUP_EXECUTE,WORLD_READ,WORLD_WRITE,WORLD_EXECUTE,SETUID和SETGID;
CONFIGURATIONS:指定安装规则适用的构建配置列表(DEBUG或RELEASE等);
EXCLUDE_FROM_ALL:指定该文件从完整安装中排除,仅作为特定于组件的安装的一部分进行安装;
OPTIONAL:如果要安装的文件不存在,则指定不是错误。

install(FILES kylin-mobile-assistant DESTINATION /usr/bin/kylin-mobile-assistant/ PERMISSIONS
        OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/mobile-assistant.desktop DESTINATION /usr/share/applications/ PERMISSIONS
        OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/third_party/scrcpy-server DESTINATION /usr/bin/kylin-mobile-assistant)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/config DESTINATION /usr/bin/kylin-mobile-assistant/)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/keymap DESTINATION /usr/bin/kylin-mobile-assistant/)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/third_party/sndcpy DESTINATION /usr/bin/kylin-mobile-assistant/ PERMISSIONS
        OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)

16. pkg_conf

什么是pkg-config

简单理解,pkg-config根据.pc结尾的文件做依赖配置。

pkg-config的基本使用

pkg-config默认会在以下路径中查找指定的包(库)对应的.pc文件:

/usr/lib/pkgconfig目录

/usr/share/pkgconfig目录

/usr/local/lib/pkgconfig目录

/usr/local/share/pkgconfig目录

PKG_CONFIG_PATH环境变量里的目录(可通过export PKG_CONFIG_PATH=XXX来修改)

给pkg-config传入的.pc文件绝对路径

CMake中使用pkg-config
1. 安装pkg-config

安装pkg-config,并确保在CMake中能找到它的可执行文件。

sudo apt install pkg-config

2. CMakeLists.txt中使用pkg-config

在CMakeLists.txt中:

find_package(PkgConfig)
pkg_check_module(MyDepName REQUIRED xxx) # 当给出REQUIRED参数时,如果找不到模块,命令将失败并报错。

其中MyDepName是自行起的名字,可以和原始包的名字不一样

找到pkg-config可执行文件并添加pkg_get_variable()、pkg_check_modules()和pkg_search_module()命令。以下变量也将被设置:

  • PKG_CONFIG_FOUND:如果找到pkg-config可执行文件
  • PKG_CONFIG_EXECUTABLE:pkg-config程序的路径
  • PKG_CONFIG_VERSION_STRING:pkg-config版本
3. pkg_check_module

执行时返回以下变量,常用

< XXX > _FOUND:如果模块存在,则设置为1
< XXX > _LIBRARIES:库
< XXX > _LINK_LIBRARIES:库及其绝对路径
< XXX > _LIBRARY_DIRS:库的路径
< XXX > _INCLUDE_DIRS:头文件路径
< XXX > _VERSION:模块版本

find_package(PkgConfig REQUIRED)
pkg_check_modules(KYSDKQTWIDGETS_PKG
        kysdk-qtwidgets
        )
        
target_include_directories(storagelist PUBLIC
        ${CMAKE_CURRENT_SOURCE_DIR}
        ${KYSDKQTWIDGETS_PKG_INCLUDE_DIRS}
        )
target_link_directories(classificationlist PUBLIC
        ${KYSDKQTWIDGETS_PKG_LIBRARY_DIRS}
        )
target_link_libraries(storagelist PUBLIC
        ${KYSDKQTWIDGETS_PKG_LIBRARIES}
        )

Cmake中重要的变量

关键字含义
CMAKE_CURRENT_SOURCE_DIRCMakeLists.txt所在的路径
CMAKE_CURRENT_BINARY_DIR编译的路径
PROJECT_NAME项目名称 设置了project之后就可以使用该值
CMAKE_CXX_FLAGS编译参数
CMAKE_C_FLAGS编译参数
CMAKE_STATIC_LINKER_FLAGS静态链接参数
CMAKE_SHARED_LINKER_FLAGS动态链接参数
CMAKE_CXX_COMPILERcxx编译器
CMAKE_C_COMPILERc编译器
CMAKE_AR汇编器
CMAKE_LINKER连接器
EXECUTABLE_OUTPUT_PATH可执行文件生成的路径
LIBRARY_OUTPUT_PATH库生成的路径
BUILD_SHARED_LIBS指定add_library() 的默认编译属性,动态库还是静态库【默认】
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值