从 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。
我正在使用一个通用的 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 的想法很棒,但它有一个 巨大的 缺点 - 您必须 运行 可执行文件。 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。