5.8 探究可执行命令
NOTE:此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-5/recipe-08 中找到,其中包含一个C/C++例子。该示例在CMake 3.5版(或更高版本)中是有效的,并且已经在GNU/Linux、macOS和Windows上进行过测试。
目前为止,我们已经展示了如何检查给定的源代码,是否可以由所选的编译器编译,以及如何确保所需的编译器和链接器标志可用。此示例中,将显示如何检查是否可以在当前系统上编译、链接和运行代码。
准备工作
本示例的代码示例是复用第3章第9节的配置,并进行微小的改动。之前,我们展示了如何在您的系统上找到ZeroMQ库并将其链接到一个C程序中。本示例中,在生成实际的C++程序之前,我们将检查一个使用GNU/Linux上的系统UUID库的小型C程序是否能够实际运行。
具体实施
开始构建C++项目之前,我们希望检查GNU/Linux上的UUID系统库是否可以被链接。这可以通过以下一系列步骤来实现:
声明一个混合的C和C++11程序。这是必要的,因为我们要编译和运行的测试代码片段是使用C语言完成:
cmake_minimum_required(VERSION 3.6 FATAL_ERROR)
project(recipe-08 LANGUAGES CXX C)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
我们需要在系统上找到UUID库。这通过使用
pkg-config
实现的。要求搜索返回一个CMake导入目标使用IMPORTED_TARGET
参数:find_package(PkgConfig REQUIRED QUIET)
pkg_search_module(UUID REQUIRED uuid IMPORTED_TARGET)
if(TARGET PkgConfig::UUID)
message(STATUS "Found libuuid")
endif()
接下来,需要使用
CheckCSourceRuns.cmake
模块。C++的是CheckCXXSourceRuns.cmake
模块。但到CMake 3.11为止,Fortran语言还没有这样的模块:include(CheckCSourceRuns)
我们声明一个
_test_uuid
变量,其中包含要编译和运行的C代码段:set(_test_uuid
"
#include <uuid/uuid.h>
int main(int argc, char * argv[]) {
uuid_t uuid;
uuid_generate(uuid);
return 0;
}
")
我们声明
CMAKE_REQUIRED_LIBRARIES
变量后,对check_c_source_runs
函数的调用。接下来,调用check_c_source_runs
,其中测试代码作为第一个参数,_runs
变量作为第二个参数,以保存执行的检查结果。之后,取消CMAKE_REQUIRED_LIBRARIES
变量的设置:set(CMAKE_REQUIRED_LIBRARIES PkgConfig::UUID)
check_c_source_runs("${_test_uuid}" _runs)
unset(CMAKE_REQUIRED_LIBRARIES)
如果检查没有成功,要么是代码段没有编译,要么是没有运行,我们会用致命的错误停止配置:
if(NOT _runs)
message(FATAL_ERROR "Cannot run a simple C executable using libuuid!")
endif()
若成功,我们继续添加C++可执行文件作为目标,并链接到UUID:
add_executable(use-uuid use-uuid.cpp)
target_link_libraries(use-uuid
PUBLIC
PkgConfig::UUID
)
工作原理
check_<lang>_source_runs
用于C和C++的函数,与check_<lang>_source_compile
相同,但在实际运行生成的可执行文件的地方需要添加一个步骤。对于check_<lang>_source_compiles
, check_<lang>_source_runs
的执行可以通过以下变量来进行:
- CMAKE_REQUIRED_FLAGS:设置编译器标志。
- CMAKE_REQUIRED_DEFINITIONS:设置预编译宏。
- CMAKE_REQUIRED_INCLUDES:设置包含目录列表。
- CMAKE_REQUIRED_LIBRARIES:设置可执行目标需要连接的库列表。
由于使用pkg_search_module
生成的为导入目标,所以只需要将CMAKE_REQUIRES_LIBRARIES
设置为PkgConfig::UUID
,就可以正确设置包含目录。
正如check_<lang>_source_compiles
是try_compile
的包装器,check_<lang>_source_runs
是CMake中另一个功能更强大的命令的包装器:try_run
。因此,可以编写一个CheckFortranSourceRuns.cmake
模块,通过适当包装try_run
, 提供与C和C++模块相同的功能。
NOTE:pkg_search_module
只能定义导入目标(CMake 3.6),但目前的示例可以使工作,3.6之前版本的CMake可以通过手动设置所需的包括目录和库check_c_source_runs
如下:set(CMAKE_REQUIRED_INCLUDES $ {UUID_INCLUDE_DIRS})
和set(CMAKE_REQUIRED_LIBRARIES $ {UUID_LIBRARIES})
。