返回介绍

2.4 检测处理器体系结构

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

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

19 世纪 70 年代,出现的 64 位整数运算和本世纪初出现的用于个人计算机的 64 位寻址,扩大了内存寻址范围,开发商投入了大量资源来移植为 32 位体系结构硬编码,以支持 64 位寻址。许多博客文章,如 https://www.viva64.com/en/a/0004/ ,致力于讨论将 C++ 代码移植到 64 位平台中的典型问题和解决方案。虽然,避免显式硬编码的方式非常明智,但需要在使用 CMake 配置的代码中适应硬编码限制。本示例中,我们会来讨论检测主机处理器体系结构的选项。

准备工作

我们以下面的 arch-dependent.cpp 代码为例:

#include <cstdlib>
#include <iostream>
#include <string>
​
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
​
std::string say_hello()
{
  std::string arch_info(TOSTRING(ARCHITECTURE));
  arch_info += std::string(" architecture. ");
#ifdef IS_32_BIT_ARCH
  return arch_info + std::string("Compiled on a 32 bit host processor.");
#elif IS_64_BIT_ARCH
  return arch_info + std::string("Compiled on a 64 bit host processor.");
#else
  return arch_info + std::string("Neither 32 nor 64 bit, puzzling ...");
#endif
}
​
int main()
{
  std::cout << say_hello() << std::endl;
  return EXIT_SUCCESS;
}

具体实施

CMakeLists.txt 文件中,我们需要以下内容:

  1. 首先,定义可执行文件及其源文件依赖关系:
    cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
    project(recipe-04 LANGUAGES CXX)
    add_executable(arch-dependent arch-dependent.cpp)
  2. 检查空指针类型的大小。CMake 的 CMAKE_SIZEOF_VOID_P 变量会告诉我们 CPU 是 32 位还是 64 位。我们通过状态消息让用户知道检测到的大小,并设置预处理器定义:
    if(CMAKE_SIZEOF_VOID_P EQUAL 8)
      target_compile_definitions(arch-dependent PUBLIC "IS_64_BIT_ARCH")
      message(STATUS "Target is 64 bits")
    else()
      target_compile_definitions(arch-dependent PUBLIC "IS_32_BIT_ARCH")
      message(STATUS "Target is 32 bits")
    endif()
  3. 通过定义以下目标编译定义,让预处理器了解主机处理器架构,同时在配置过程中打印状态消息:
    if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "i386")
        message(STATUS "i386 architecture detected")
    elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "i686")
        message(STATUS "i686 architecture detected")
    elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "x86_64")
        message(STATUS "x86_64 architecture detected")
    else()
        message(STATUS "host processor architecture is unknown")
    endif()
    target_compile_definitions(arch-dependent
      PUBLIC "ARCHITECTURE=${CMAKE_HOST_SYSTEM_PROCESSOR}"
      )
  4. 配置项目,并注意状态消息(打印出的信息可能会发生变化):
    $ mkdir -p build
    $ cd build
    $ cmake ..
    ​
    ...
    -- Target is 64 bits
    -- x86_64 architecture detected
    ...
  5. 最后,构建并执行代码(实际输出将取决于处理器架构):
    $ cmake --build .
    $ ./arch-dependent
    ​
    x86_64 architecture. Compiled on a 64 bit host processor.

工作原理

CMake 定义了 CMAKE_HOST_SYSTEM_PROCESSOR 变量,以包含当前运行的处理器的名称。可以设置为“i386”、“i686”、“x86_64”、“AMD64”等等,当然,这取决于当前的 CPU。 CMAKE_SIZEOF_VOID_P 为 void 指针的大小。我们可以在 CMake 配置时进行查询,以便修改目标或目标编译定义。可以基于检测到的主机处理器体系结构,使用预处理器定义,确定需要编译的分支源代码。正如在前面的示例中所讨论的,编写新代码时应该避免这种依赖,但在处理遗留代码或交叉编译时,这种依赖是有用的,交叉编译会在第 13 章进行讨论。

NOTE : 使用 CMAKE_SIZEOF_VOID_P 是检查当前 CPU 是否具有 32 位或 64 位架构的唯一“真正”可移植的方法。

更多信息

除了 CMAKE_HOST_SYSTEM_PROCESSOR , CMake 还定义了 CMAKE_SYSTEM_PROCESSOR 变量。前者包含当前运行的 CPU 在 CMake 的名称,而后者将包含当前正在为其构建的 CPU 的名称。这是一个细微的差别,在交叉编译时起着非常重要的作用。我们将在第 13 章,看到更多关于交叉编译的内容。另一种让 CMake 检测主机处理器体系结构,是使用 CC++中 定义的符号,结合 CMake 的 try_run 函数,尝试构建执行的源代码(见第 5.8 节) 分支的预处理符号。这将返回已定义错误码,这些错误可以在 CMake 端捕获(此策略的灵感来自 https://github.com/axr/cmake/blob/master/targetarch.cmake ):

#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
    #error cmake_arch i386
#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
    #error cmake_arch x86_64
#endif

这种策略也是检测目标处理器体系结构的推荐策略,因为 CMake 似乎没有提供可移植的内在解决方案。另一种选择,将只使用 CMake,完全不使用预处理器,代价是为每种情况设置不同的源文件,然后使用 target_source 命令将其设置为可执行目标 arch-dependent 依赖的源文件:

add_executable(arch-dependent "")
​
if(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "i386")
    message(STATUS "i386 architecture detected")
    target_sources(arch-dependent
        PRIVATE
        arch-dependent-i386.cpp
    )
elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "i686")
    message(STATUS "i686 architecture detected")
    target_sources(arch-dependent
        PRIVATE
            arch-dependent-i686.cpp
    )
elseif(CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "x86_64")
    message(STATUS "x86_64 architecture detected")
    target_sources(arch-dependent
        PRIVATE
            arch-dependent-x86_64.cpp
    )
else()
    message(STATUS "host processor architecture is unknown")
endif()

这种方法,显然需要对现有项目进行更多的工作,因为源文件需要分离。此外,不同源文件之间的代码复制肯定也会成为问题。

发布评论

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