从 CMake 在 Eigen 中设置最大静态对齐

Setting maximum static alignment in Eigen from CMake

我正在使用一个通用的 CMake 脚本,该脚本提供了一个关于在使用 Eigen 编译项目时激活矢量化功能的感谢回退策略。

使用符合 C++17 标准的 Eigen 3.4 并使用更新的编译器(例如 gcc > 7)进行编译,开发人员无需遵守静态对象对齐方面的代码要求。 STL 容器中不再有 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 宏和显式对齐(我们在实验室为此欢呼雀跃!)。

但是我们有各种各样的项目和不同的编译设置。我们希望在编写代码时不必担心对齐问题,而 CMake 脚本会检测架构+编译功能并停用 Eigen 的架构不安全矢量化功能(即使这意味着破坏双兼容性)。

有没有办法在 CMake 级别检索架构最大对齐大小,以正确设置 EIGEN_MAX_STATIC_ALIGN_BYTES 指令??

也许是 bash 检索 max_align_t 的脚本? https://en.cppreference.com/w/cpp/types/max_align_t

您可以使用 https://en.cppreference.com/w/cpp/types/max_align_t with try_run 中的源代码。请注意,交叉编译需要额外的考虑;有关详细信息,请参阅 try_run 的文档。

cmake_tests/alignment_check.cpp:

这是来自https://en.cppreference.com/w/cpp/types/max_align_t

的来源
#include <iostream>
#include <cstddef>
int main()
{
    std::cout << alignof(std::max_align_t) << '\n';
}

CMakeLists.txt

...

try_run(MY_MAXALIGN_RUN_RESULT MY_MAXALIGN_COMPILE_SUCCESS
        ${CMAKE_CURRENT_BINARY_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/cmake_tests/alignment_check.cpp"
        COMPILE_OUTPUT_VARIABLE MY_MAXALIGN_COMPILE_OUTPUT
        RUN_OUTPUT_VARIABLE MY_MAXALIGN_RUN_OUTPUT)

if (NOT MY_MAXALIGN_COMPILE_SUCCESS)
    message(FATAL_ERROR "Error during compilation of ${CMAKE_CURRENT_SOURCE_DIR}/cmake_tests/alignment_check.cpp :\n\n${MY_MAXALIGN_COMPILE_OUTPUT}")
endif()

if (MY_MAXALIGN_RUN_RESULT)
    message(FATAL_ERROR "Error running logic in ${CMAKE_CURRENT_SOURCE_DIR}/cmake_tests/alignment_check.cpp :\n\n${MY_MAXALIGN_RUN_OUTPUT}")
endif()

string(STRIP ${MY_MAXALIGN_RUN_OUTPUT} MY_MAXALIGN)

message(STATUS "MY_MAXALIGN = \"${MY_MAXALIGN}\"")

...

MY_MAXALIGN cmake 变量的内容可用于例如指定编译定义。

CMake 输出

...
MY_MAXALIGN = "8"
...

虽然 fabian 的想法很棒,但它有一个 巨大的 缺点 - 您必须 运行 可执行文件。 。目标是在没有 运行ning 的情况下获得 alignof(std::max_align_t) 的值,仅通过编译。我们可以做到。

一如既往,向最好的人学习。来自 CMake modules 检查文件:CMakeCompilerABI.h CMakeCCompilerABI.c CMakeDetermineCompilerABI.cmake。请注意 CMakeCompilerABI.h 如何将信息嵌入到可执行文件中,而不实际打印它。采取同样的方法。您的源文件如下所示:

// determineAlingofMax.cpp
#include <cstddef>
#define VAL  alignof(std::max_align_t)
const char info_alingof_max_align_t[] = {
    'I', 'N', 'F', 'O', ':', 'a', 'l', 'i', 'n', 'g', 'o', 'f', 'm', 'a', 'x'
    '[', '0' + ((VAL / 10) % 10), '0' + (VAL % 10), ']', '[=10=]',
};
int main(int argc, char *argv[]) {
   return  info_alingof_max_align_t[argc];
}

请注意我们如何计算 alignof 并将其转换为字符串在编译时

现在我们必须将它编译成目标文件 - 我们不需要 运行 任何可执行文件。所以我们看一下CMakeDetermineCompilerABI.cmake写类似:

set(BIN "${CMAKE_BINARY_DIR}/determineAlingofMax.bin"
try_compile(ALIGNMAX_COMPILED
  ${CMAKE_BINARY_DIR}
  SOURCES /path/to/the/determineAlingofMax.cpp
  CMAKE_FLAGS ${CMAKE_FLAGS}
              # Ignore unused flags
              "--no-warn-unused-cli"
  COMPILE_DEFINITIONS ${COMPILE_DEFINITIONS}
  COPY_FILE "${BIN}"
  COPY_FILE_ERROR copy_error
  OUTPUT_VARIABLE OUTPUT
)
if (ALIGNMAX_COMPILED AND not copy_error)
   file(STRINGS "${BIN}" data REGEX "INFO:alingofmax\[[^]]*\]")
   if (data MATCHES "INFO:alingofmax\[0*([^]]*)\]")
       set(ALINGOFMAX "${CMAKE_MATCH_1}" CACHE INTERNAL "")
   endif()
endif()
if (NOT ALINGOFMAX) 
   message(FATAL_ERROR some error here)
endif()
# and finally, maybe option()
set(EIGEN_MAX_STATIC_ALIGN_BYTES ${ALINGOFMAX})

请注意二进制文件是如何不执行的——只编译了。字符串 INFO:alignofmax 必须足够唯一,所以它不会出现在可执行文件中的任何地方 - 我最近更喜欢使用 UUID。