CMake 完整入门教程(三)

9 在工程中查找并使用其他程序库的方法
在开发软件的时候我们会用到一些函数库,这些函数库在不同的系统中安装的位置可能不
同,编译的时候需要首先找到这些软件包的头文件以及链接库所在的目录以便生成编译选
项。例如一个需要使用博克利数据库项目,需要头文件 db_cxx.h 和链接库 libdb_cxx.so
现在该项目中有一个源代码文件 main.cpp ,放在项目的根目录中。
9.1 程序库说明文件
在项目的根目录中创建目录 cmake/modules/ ,在 cmake/modules/ 下创建文件
Findlibdb_cxx.cmake ,内容如下:
文件 Findlibdb_cxx.cmake
MESSAGE(STATUS "Using bundled FindLibdb.cmake...")  
  
# 查找头文件路径  
FIND_PATH(  
    LIBDB_CXX_INCLUDE_DIR  
    db_cxx.h  
    /usr/include/  
    /usr/local/include/  
)  
  
# 查找库文件路径  
FIND_LIBRARY(  
    LIBDB_CXX_LIBRARIES   
    NAMES db_cxx  
    PATHS /usr/lib/ /usr/local/lib/  
)  
  
# 检查是否找到了库和头文件  
IF (LIBDB_CXX_INCLUDE_DIR AND LIBDB_CXX_LIBRARIES)  
    SET(LIBDB_CXX_FOUND TRUE)  
ENDIF (LIBDB_CXX_INCLUDE_DIR AND LIBDB_CXX_LIBRARIES)

文件 Findlibdb_cxx.cmake 的命名要符合规范 : FindlibNAME.cmake ,其中 NAME 是函数库的
名称。 Findlibdb_cxx.cmake 的语法与 CMakeLists.txt 相同。这里使用了三个命令:
MESSAGE FIND_PATH FIND_LIBRARY
命令 MESSAGE 会将参数的内容输出到终端。
命令 FIND_PATH 指明头文件查找的路径,原型如下:
find_path( name1 [path1 path2 ...]) 该命令在参数 path* 指示的目录中查找文
name1 并将查找到的路径保存在变量 VAR 中。第 3 行到 8 行的意思是
/usr/include/ /usr/local/include/ 中查找文件 db_cxx.h ,并将 db_cxx.h 所在的路径保存
LIBDB_CXX_INCLUDE_DIR 中。
命令 FIND_LIBRARY FIND_PATH 类似,用于查找链接库并将结果保存在变量中。第 10
13 行的意思是在目录 /usr/lib/ /usr/local/lib/ 中寻找名称为 db_cxx 的链接库,并将结
果保存在 LIBDB_CXX_LIBRARIES
9.2 项目的根目录中的 CmakeList.txt
在项目的根目录中创建 CmakeList.txt
PROJECT(main)  
  
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)  
  
SET(CMAKE_SOURCE_DIR ".")  
  
# 设置 CMake 模块路径  
SET(CMAKE_MODULE_PATH  
    ${CMAKE_ROOT}/Modules  
    ${CMAKE_SOURCE_DIR}/cmake/modules)  
  
# 获取所有源文件  
AUX_SOURCE_DIRECTORY(. DIR_SRCS)  
  
# 添加可执行文件  
ADD_EXECUTABLE(main ${DIR_SRCS})  
  
# 查找 libdb_cxx 包  
FIND_PACKAGE(libdb_cxx REQUIRED)  
  
# 将 libdb_cxx 的路径标记为高级变量  
MARK_AS_ADVANCED(  
    LIBDB_CXX_INCLUDE_DIR  
    LIBDB_CXX_LIBRARIES)  
  
# 检查是否找到了 libdb_cxx 的库和头文件  
IF(LIBDB_CXX_INCLUDE_DIR AND LIBDB_CXX_LIBRARIES)  
    MESSAGE(STATUS "Found libdb libraries")  
    # 包含 libdb_cxx 的头文件目录  
    INCLUDE_DIRECTORIES(${LIBDB_CXX_INCLUDE_DIR})  
    # 打印 libdb_cxx 的库文件路径  
    MESSAGE(${LIBDB_CXX_LIBRARIES})  
    # 将 libdb_cxx 的库文件链接到 main 可执行文件  
    TARGET_LINK_LIBRARIES(main ${LIBDB_CXX_LIBRARIES})  
ENDIF(LIBDB_CXX_INCLUDE_DIR AND LIBDB_CXX_LIBRARIES)

下面是上述代码的详细解释:

  1. PROJECT(main): 声明了一个CMake项目,项目名称为"main"。

  2. CMAKE_MINIMUM_REQUIRED(VERSION 2.6): 指定CMake的最低版本要求为2.6。

  3. SET(CMAKE_SOURCE_DIR .): 设置CMAKE_SOURCE_DIR变量,其值为当前目录(.表示当前目录)。

  4. SET(CMAKE_MODULE_PATH ...): 设置CMAKE_MODULE_PATH变量,它决定了CMake查找模块的路径。在这里,它包括了${CMAKE_ROOT}/Modules${CMAKE_SOURCE_DIR}/cmake/modules两个路径。

  5. AUX_SOURCE_DIRECTORY(. DIR_SRCS): 获取当前目录下的所有源文件,并将它们存储在DIR_SRCS变量中。

  6. ADD_EXECUTABLE(main ${DIR_SRCS}): 添加一个名为"main"的可执行文件,该文件由DIR_SRCS变量中的源文件构建。

  7. FIND_PACKAGE(libdb_cxx REQUIRED): 使用CMake的FIND_PACKAGE命令查找libdb_cxx包。REQUIRED表示这个包是必需的,如果找不到,CMake将停止并给出错误。

  8. MARK_AS_ADVANCED(...): 将指定的变量标记为高级变量,这意味着它们不会在简单的cmake ..命令中自动设置或修改。

  9. IF(LIBDB_CXX_INCLUDE_DIR AND LIBDB_CXX_LIBRARIES): 检查是否找到了libdb_cxx的头文件目录和库文件。

    • MESSAGE(STATUS "Found libdb libraries"): 如果找到了libdb_cxx,打印一条状态消息表示已找到。
    • INCLUDE_DIRECTORIES(${LIBDB_CXX_INCLUDE_DIR}): 将libdb_cxx的头文件目录添加到编译器的搜索路径中。
    • MESSAGE(${LIBDB_CXX_LIBRARIES}): 打印找到的libdb_cxx库文件路径。
    • TARGET_LINK_LIBRARIES(main ${LIBDB_CXX_LIBRARIES}): 将找到的libdb_cxx库文件链接到"main"可执行文件中。
  10. ENDIF(LIBDB_CXX_INCLUDE_DIR AND LIBDB_CXX_LIBRARIES): 结束IF语句。

总的来说,这段代码定义了一个CMake项目,该项目构建一个名为"main"的可执行文件,并尝试找到并链接一个名为libdb_cxx的库。如果找到该库,它还会将其头文件目录添加到编译器的搜索路径中。

9.3 _FOUND
标准的 Find 模块应该定义下面几个变量:
_FOUND
_INCLUDE_DIR or _INCLUDES
_LIBRARY or _LIBRARIES
你可以通过 _FOUND 来判断模块是否被找到 , 如果没有找到 , 按照工程的需要关闭某
些特性、给出提醒或者中止编译。
我们再来看一个的例子 , 通过 _FOUND 来控制工程特性 :
FIND_PACKAGE(JPEG)  
  
IF(JPEG_FOUND)  
    SET(optionalSources ${optionalSources} jpegview.c)  
    INCLUDE_DIRECTORIES(${JPEG_INCLUDE_DIR})  
    SET(optionalLibs ${optionalLibs} ${JPEG_LIBRARIES})  
    ADD_DEFINITIONS(-DENABLE_JPEG_SUPPORT)  
ENDIF(JPEG_FOUND)

通过判断系统是否提供了 JPEG 库来决定程序是否支持 JPEG 功能。
10 常用命令
10.1 project 命令
命令语法: project( [languageName1 languageName2 ... ] )
命令简述:用于指定项目的名称
使用范例: project(Main)
10.2 cmake_minimum_required 命令
命令语法: cmake_minimum_required(VERSION major[.minor[.patch[.tweak]]]
[FATAL_ERROR])
命令简述:用于指定需要的 CMake 的最低版本
使用范例: cmake_minimum_required(VERSION 2.8)
10.3 aux_source_directory 命令
命令语法: aux_source_directory( )
命令简述:用于将 dir 目录下的所有源文件的名字保存在变量 variable
使用范例: aux_source_directory(. DIR_SRCS)
10.4 add_executable 命令
命令语法: add_executable( [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL]
source1 source2 … sourceN)
命令简述:用于指定从一组源文件 source1 source2 … sourceN 编译出一个可执行文件且命
名为 name
使用范例: add_executable(Main ${DIR_SRCS})
10.5 add_library 命令
命令语法: add_library([STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] source1
source2 … sourceN)
命令简述:用于指定从一组源文件 source1 source2 … sourceN 编译出一个库文件且命名为
name
使用范例: add_library(Lib ${DIR_SRCS})
10.6 add_dependencies 命令
命令语法: add_dependencies(target-name depend-target1 depend-target2 …)
命令简述:用于指定某个目标(可执行文件或者库文件)依赖于其他的目标。这里的目标
必须是 add_executable add_library add_custom_target 命令创建的目标
10.7 add_subdirectory 命令
命令语法: add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
命令简述:用于添加一个需要进行构建的子目录
使用范例: add_subdirectory(Lib)
10.8 target_link_libraries 命令
命令语法: target_link_libraries( [item1 [item2 [...]]] [[debug|optimized|general] ] …)
命令简述:用于指定 target 需要链接 item1 item2 … 。这里 target 必须已经被创建,链接的
item 可以是已经存在的 target (依赖关系会自动添加)
使用范例: target_link_libraries(Main Lib)
10.9 set 命令
命令语法: set( [[CACHE [FORCE]] | PARENT_SCOPE])
命令简述:用于设定变量 variable 的值为 value 。如果指定了 CACHE 变量将被放入 Cache
(缓存)中。
使用范例: set(ProjectName Main)
10.10
unset 命令
命令语法: unset( [CACHE])
命令简述:用于移除变量 variable 。如果指定了 CACHE 变量将被从 Cache 中移除。
使用范例: unset(VAR CACHE)
10.11
message 命令
命令语法: message([STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR]
“message to display” …)
命令简述:用于输出信息
使用范例: message(“Hello World”)
10.12
include 命令
用来载入 CMakeLists.txt 文件,也用于载入预定义的 cmake 模块 .
INCLUDE(file1 [OPTIONAL])
INCLUDE(module [OPTIONAL])
OPTIONAL 参数的作用是文件不存在也不会产生错误。
你可以指定载入一个文件,如果定义的是一个模块,那么将在 CMAKE_MODULE_PATH
搜索这个模块并载入。
载入的内容将在处理到 INCLUDE 语句时直接执行。
10.13
include_directories 命令
命令语法: include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 …)
命令简述:用于设定目录,这些设定的目录将被编译器用来查找 include 文件
使用范例: include_directories(${PROJECT_SOURCE_DIR}/lib)
10.14
find_file 命令
命令语法: find_file( name1 [path1 path2 ...])
VAR 变量代表找到的文件全路径,包含文件名
10.15
find_path 命令
命令语法: find_path( name1 [path1 path2 ...])
命令简述:用于查找包含文件 name1 的路径,如果找到则将路径保存在 VAR 中(此路径
为一个绝对路径),如果没有找到则结果为 -NOTFOUND 。默认的情况下, VAR 会被
保存在 Cache 中,这时候我们需要清除 VAR 才可以进行下一次查询(使用 unset 命令)。
使用范例:
find_path(LUA_INCLUDE_PATH lua.h ${LUA_INCLUDE_FIND_PATH})
if(NOT LUA_INCLUDE_PATH)
message(SEND_ERROR "Header file lua.h not found")
endif()
10.16
find_library 命令
命令语法: find_library( name1 [path1 path2 ...])
命令简述:用于查找库文件 name1 的路径,如果找到则将路径保存在 VAR 中(此路径为
一个绝对路径),如果没有找到则结果为 -NOTFOUND 。一个类似的命
link_directories 已经不太建议使用了
示例 :
FIND_LIBRARY(libX X11 /usr/lib)
IF(NOT libX)
MESSAGE(FATAL_ERROR “libX not found”)
ENDIF(NOT libX)
10.17
find_package 命令
命令语法: find_package( [major.minor] [QUIET] [NO_MODULE]
[[REQUIRED|COMPONENTS] [componets...]])
用来调用预定义在 CMAKE_MODULE_PATH 下的 Find.cmake 模块,你也可以自己定
Find 模块,通过 SET(CMAKE_MODULE_PATH dir) 将其放入工程的某个目录中供工
程使用。
10.18
add_definitions 命令
命令语法: add_definitions(-DFOO -DBAR …)
命令简述:用于添加编译器命令行标志(选项),通常的情况下我们使用其来添加预处理
器定义
使用范例: add_definitions(-D_UNICODE -DUNICODE)
如果要添加其他的编译器开关,可以通过 CMAKE_C_FLAGS 变量和 CMAKE_CXX_FLAGS 变量
设置。
10.19
execute_process 命令
命令语法:
execute_process(COMMAND [args1...]]
[COMMAND [args2...] [...]]
[WORKING_DIRECTORY ]
[TIMEOUT ]
[RESULT_VARIABLE ]
[OUTPUT_VARIABLE ]
[ERROR_VARIABLE ]
[INPUT_FILE ]
[OUTPUT_FILE ]
[ERROR_FILE ]
[OUTPUT_QUIET]
[ERROR_QUIET]
[OUTPUT_STRIP_TRAILING_WHITESPACE]
[ERROR_STRIP_TRAILING_WHITESPACE])
命令简述:用于执行一个或者多个外部命令。每一个命令的标准输出通过管道转为下一个
命令的标准输入。 WORKING_DIRECTORY 用于指定外部命令的工作目录, RESULT_VARIABLE
用于指定一个变量保存外部命令执行的结果,这个结果可能是最后一个执行的外部命令的
退出码或者是一个描述错误条件的字符串, OUTPUT_VARIABLE 或者 ERROR_VARIABLE 用于
指定一个变量保存标准输出或者标准错误, OUTPUT_QUIET 或者 ERROR_QUIET 用于忽略标
准输出和标准错误。
使用范例: execute_process(COMMAND ls)
10.20
file 命令
命令简述:此命令提供了丰富的文件和目录的相关操作(这里仅说一下比较常用的)
使用范例:
# 目录的遍历
# GLOB 用于产生一个文件(目录)路径列表并保存在 variable
# 文件路径列表中的每个文件的文件名都能匹配 globbing expressions (非正则表达式,
但是类似)
# 如果指定了 RELATIVE 路径,那么返回的文件路径列表中的路径为相对于 RELATIVE
路径
# file(GLOB variable [RELATIVE path] [globbing expressions]...)
# 获取当前目录下的所有的文件(目录)的路径并保存到 ALL_FILE_PATH 变量中
file(GLOB ALL_FILE_PATH ./*)
# 获取当前目录下的 .h 文件的文件名并保存到 ALL_H_FILE 变量中
# 这里的变量 CMAKE_CURRENT_LIST_DIR 表示正在处理的 CMakeLists.txt 文件的所在的目
录的绝对路径( 2.8.3 以及以后版本才支持)
file(GLOB ALL_H_FILE RELATIVE ${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/*.h)
  1. file(GLOB variable [RELATIVE path] [globbing expressions]...)

    • variable:这是一个变量名,用于保存找到的文件或目录的路径。
    • RELATIVE path:可选参数,指定一个相对路径,找到的文件或目录的路径将是相对于这个相对路径的。
    • globbing expressions:这些是用来匹配文件名的模式。例如,*.txt 会匹配所有 .txt 结尾的文件。
  2. 使用范例

    • 获取当前目录下的所有的文件(目录)的路径并保存到 ALL_FILE_PATH 变量中

    cmake`file(GLOB ALL_FILE_PATH ./*)`

    这会找到当前目录下的所有文件和目录,并将它们的路径保存到 ALL_FILE_PATH 变量中。

    • 获取当前目录下的 .h 文件的文件名并保存到 ALL_H_FILE 变量中

    cmake`file(GLOB ALL_H_FILE RELATIVE ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/*.h)`

    这会找到当前目录下的所有 .h 文件,并将它们的相对路径保存到 ALL_H_FILE 变量中。这里使用了 RELATIVE 关键字和 ${CMAKE_CURRENT_LIST_DIR} 变量来指定相对路径。

简单来说,file(GLOB ...) 是一个非常有用的命令,它可以帮助您自动地收集文件和目录的路径,特别是当您不知道文件的确切名称或只知道其模式时。

你可能感兴趣的:(C++项目开发基础,c++)