ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
# 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系统库是否可以被链接。这可以通过以下一系列步骤来实现: 1. 声明一个混合的C和C++11程序。这是必要的,因为我们要编译和运行的测试代码片段是使用C语言完成: ```cmake 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) ``` 2. 我们需要在系统上找到UUID库。这通过使用`pkg-config`实现的。要求搜索返回一个CMake导入目标使用`IMPORTED_TARGET`参数: ```cmake find_package(PkgConfig REQUIRED QUIET) pkg_search_module(UUID REQUIRED uuid IMPORTED_TARGET) if(TARGET PkgConfig::UUID) message(STATUS "Found libuuid") endif() ``` 3. 接下来,需要使用`CheckCSourceRuns.cmake`模块。C++的是`CheckCXXSourceRuns.cmake`模块。但到CMake 3.11为止,Fortran语言还没有这样的模块: ```cmake include(CheckCSourceRuns) ``` 4. 我们声明一个`_test_uuid`变量,其中包含要编译和运行的C代码段: ```cmake set(_test_uuid " #include <uuid/uuid.h> int main(int argc, char * argv[]) { uuid_t uuid; uuid_generate(uuid); return 0; } ") ``` 5. 我们声明`CMAKE_REQUIRED_LIBRARIES`变量后,对`check_c_source_runs`函数的调用。接下来,调用`check_c_source_runs`,其中测试代码作为第一个参数,`_runs`变量作为第二个参数,以保存执行的检查结果。之后,取消`CMAKE_REQUIRED_LIBRARIES`变量的设置: ```cmake set(CMAKE_REQUIRED_LIBRARIES PkgConfig::UUID) check_c_source_runs("${_test_uuid}" _runs) unset(CMAKE_REQUIRED_LIBRARIES) ``` 6. 如果检查没有成功,要么是代码段没有编译,要么是没有运行,我们会用致命的错误停止配置: ```cmake if(NOT _runs) message(FATAL_ERROR "Cannot run a simple C executable using libuuid!") endif() ``` 7. 若成功,我们继续添加C++可执行文件作为目标,并链接到UUID: ```cmake 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})`。*