返回介绍

2.2 处理与平台相关的源代码

发布于 2025-05-06 21:45:54 字数 2999 浏览 0 评论 0 收藏 0

NOTE : 此示例代码可以在 https://github.com/dev-cafe/cmake-cookbook/tree/v1.0/chapter-02/recipe-02 中找到,包含一个 C++示例。该示例在 CMake 3.5 版(或更高版本) 中是有效的,并且已经在 GNU/Linux、macOS 和 Windows 上进行过测试。

理想情况下,应该避免依赖于平台的源代码,但是有时我们没有选择,特别是当要求配置和编译不是自己编写的代码时。本示例中,将演示如何使用 CMake 根据操作系统编译源代码。

准备工作

修改 hello-world.cpp 示例代码,将第 1 章第 1 节的例子进行修改:

#include <cstdlib>
#include <iostream>
#include <string>
​
std::string say_hello() {
#ifdef IS_WINDOWS
  return std::string("Hello from Windows!");
#elif IS_LINUX
  return std::string("Hello from Linux!");
#elif IS_MACOS
  return std::string("Hello from macOS!");
#else
  return std::string("Hello from an unknown system!");
#endif
}
​
int main() {
  std::cout << say_hello() << std::endl;
  return EXIT_SUCCESS;
}

具体实施

完成一个 CMakeLists.txt 实例,使我们能够基于目标操作系统有条件地编译源代码:

  1. 首先,设置了 CMake 最低版本、项目名称和支持的语言:
    cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
    project(recipe-02 LANGUAGES CXX)
  2. 然后,定义可执行文件及其对应的源文件:
    add_executable(hello-world hello-world.cpp)
  3. 通过定义以下目标编译定义,让预处理器知道系统名称:
    if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
      target_compile_definitions(hello-world PUBLIC "IS_LINUX")
    endif()
    if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
      target_compile_definitions(hello-world PUBLIC "IS_MACOS")
    endif()
    if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
      target_compile_definitions(hello-world PUBLIC "IS_WINDOWS")
    endif()

    继续之前,先检查前面的表达式,并考虑在不同系统上有哪些行为。

  4. 现在,准备测试它,并配置项目:
    $ mkdir -p build
    $ cd build
    $ cmake ..
    $ cmake --build .
    $ ./hello-world
    ​
    Hello from Linux!

Windows 系统上,将看到来自 Windows 的 Hello。其他操作系统将产生不同的输出。

工作原理

hello-world.cpp 示例中,有趣的部分是基于预处理器定义 IS_WINDOWSIS_LINUXIS_MACOS 的条件编译:

std::string say_hello() {
#ifdef IS_WINDOWS
  return std::string("Hello from Windows!");
#elif IS_LINUX
  return std::string("Hello from Linux!");
#elif IS_MACOS
  return std::string("Hello from macOS!");
#else
  return std::string("Hello from an unknown system!");
#endif
}

这些定义在 CMakeLists.txt 中配置时定义,通过使用 target_compile_definition 在预处理阶段使用。可以不重复 if-endif 语句,以更紧凑的表达式实现,我们将在下一个示例中演示这种重构方式。也可以把 if-endif 语句加入到一个 if-else-else-endif 语句中。这个阶段,可以使用 add_definitions(-DIS_LINUX) 来设置定义(当然,可以根据平台调整定义),而不是使用 target_compile_definition 。使用 add_definitions 的缺点是,会修改编译整个项目的定义,而 target_compile_definitions 给我们机会,将定义限制于一个特定的目标,以及通过 PRIVATE|PUBLIC|INTERFACE 限定符,限制这些定义可见性。第 1 章的第 8 节,对这些限定符有详细的说明:

  • PRIVATE ,编译定义将只应用于给定的目标,而不应用于相关的其他目标。
  • INTERFACE ,对给定目标的编译定义将只应用于使用它的目标。
  • PUBLIC ,编译定义将应用于给定的目标和使用它的所有其他目标。

NOTE : 将项目中的源代码与平台相关性最小化,可使移植更加容易。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。