Architecture 如何使用CMake检测目标体系结构?

Architecture 如何使用CMake检测目标体系结构?,architecture,cmake,build-process,qmake,Architecture,Cmake,Build Process,Qmake,我已经做了很多研究,但找不到答案。。。如何使用CMake可靠地找到我编译的目标体系结构?基本上相当于QMAKE中的QMAKE_TARGET.arch 大多数资料似乎都建议使用CMAKE_SYSTEM_处理器,但这是一个糟糕的解决方案,因为在OS X上,无论您是为i386、x86_64、ppc还是ppc64编译,它都会返回i386 类似地,CMAKE_SIZEOF_VOID_p给出的是系统的指针大小,而不是目标 我知道有CMAKE_OSX_体系结构,但如果没有设置,它可能是空的,在这种情况下,它似

我已经做了很多研究,但找不到答案。。。如何使用CMake可靠地找到我编译的目标体系结构?基本上相当于QMAKE中的QMAKE_TARGET.arch

大多数资料似乎都建议使用CMAKE_SYSTEM_处理器,但这是一个糟糕的解决方案,因为在OS X上,无论您是为i386、x86_64、ppc还是ppc64编译,它都会返回i386

类似地,CMAKE_SIZEOF_VOID_p给出的是系统的指针大小,而不是目标

我知道有CMAKE_OSX_体系结构,但如果没有设置,它可能是空的,在这种情况下,它似乎默认为系统能够实现的任何功能。那么我如何才能找到目标体系结构信息呢


特别是对于OS X,我如何区分32、64和Intel Universal?

我认为最简单、最可靠的解决方案是手动为您构建的平台指定架构(您可以使用
cmake.-DMY_architecture=x86
或类似的东西)。至少这是我们在项目中所做的,因为与您上面描述的问题相同,所以我设计了一个相当有创意的解决方案来解决我的问题。。。CMake似乎没有检测目标体系结构的功能

现在,我们知道我们可以很容易地在C中实现这一点,因为像
\uuui386\uuuuu
\uuuuuux86\u64\uuuuu
等符号将根据您的环境定义。幸运的是,CMake有一个try_run函数,它将在配置阶段编译并运行任意C源代码文件

然后我们可以编写一个小程序,它使用一组ifdef并将架构名称作为字符串写入控制台。唯一的问题是,只有在主机和目标系统相同的情况下,这才有效。。。它在交叉编译期间无法工作,因为虽然可以编译二进制文件,但无法运行它以查看其输出

这就是事情变得有趣的地方。我们可以利用C预处理器通过故意编写一个坏的C程序来获取必要的信息。。。我们使用了基于ifdef将架构名称写入控制台的原始概念,但我们不这样做,而是简单地用#error预处理器指令代替printf调用

当CMake的try_run函数编译C文件时,编译总是会失败,但是我们在#error指令中放置的任何消息都会显示在编译器的错误输出中,try_run返回给我们

因此,我们所要做的就是使用一些CMake字符串命令从编译器的错误输出中解析体系结构名称,然后我们可以检索目标体系结构。。。即使在交叉编译时

代码中特定于OS X的部分主要使用CMAKE_OSX_体系结构来确定目标体系结构,但在未指定的情况下,它将使用与其他系统相同的代码,并正确返回x86_64(对于编译器默认使用的现代系统)或i386(对于Leopard等较旧的OS X系统)

我已经使用Visual Studio 9和10生成器(x86、x86_64、ia64)、Xcode、NMake、MSYS Makefiles和Unix Makefiles在Windows、OS X和Linux上测试并验证了这一点。每次都返回正确的结果

注意:如果您故意将-m32或-m64传递给编译器,或其他可能影响目标体系结构的标志传递给编译器,则此解决方案可能会失败(是否有方法将所有环境设置传递给try\u run?);这不是我测试过的东西。只要您使用生成器的默认设置,并且所有目标都是为相同的体系结构编译的,您就应该可以了


我的解决方案的完整源代码可以在GitHub上找到:

对于主机和目标系统相同的情况,我有一个解决方案

首先,您需要调用“uname-m”以获取“机器硬件名称”。之后,您需要切断尾随的“回车”以将实际值返回到提供的变量中

EXECUTE_PROCESS( COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE ARCHITECTURE )
现在可以打印变量${ARCHITECTURE}:

message( STATUS "Architecture: ${ARCHITECTURE}" )
或者对映射进行一些规范化,例如“x86_64”、“amd64”。。。例如“64位”。32位也是如此。 使用此选项,您可以执行与体系结构相关的编译,如:

if( ${ARCHITECTURE} STREQUAL "64Bit" )
    set( BLA_LIBRARY "/opt/lib/libBla.so" )
else()
    set( BLA_LIBRARY "/opt/lib32/libBla.so" )
endif()

如果您的构建过程涉及多个目标,我认为最好让CMake知道它构建的目标是什么。 您可以遵循for CMake交叉编译,这鼓励您创建工具链CMake文件,该文件允许您选择正在使用的工具链/编译器

我为ARM处理器构建了一个C++ Linux应用程序,并命名为“代码>工具链ARM.cFux.< 它包括

设置(CMAKE\u系统\u处理器臂)

然后我像这样执行了CMake:

cmake-DCMAKE\u BUILD\u TYPE=Release-DCMAKE\u TOOLCHAIN\u FILE={my TOOLCHAIN cmake path}/TOOLCHAIN-arm.cmake{my source path}

在我的项目的CMakeList.txt中,我可以以任何方式引用CMAKE_SYSTEM_处理器

在为X86构建时,我没有包含对-DCMAKE_TOOLCHAIN_文件的引用,这使得CMAKE_SYSTEM_处理器没有定义,或者至少没有定义为
arm

这是我的工具链臂

SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_SYSTEM_VERSION 1)
set(CMAKE_SYSTEM_PROCESSOR arm)

# specify the cross compiler
SET(ENV{TOOLCHAIN_ROOT} /home/user/toolchain/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin )
SET(CMAKE_C_COMPILER   $ENV{TOOLCHAIN_ROOT}/arm-linux-gnueabihf-gcc)
SET(CMAKE_CXX_COMPILER $ENV{TOOLCHAIN_ROOT}/arm-linux-gnueabihf-gcc)

# search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

目前,确定目标体系结构不需要任何技巧:每个目标变量OSX_体系结构已添加到cmake中,可用于您的目的:

这是一种经过充分测试的了解主机体系结构的方法:

# Store in CMAKE_DEB_HOST_ARCH var the current build architecture
execute_process(COMMAND
  dpkg-architecture
    -qDEB_HOST_ARCH
  OUTPUT_VARIABLE
    CMAKE_DEB_HOST_ARCH
  OUTPUT_STRIP_TRAILING_WHITESPACE
)
然后根据需要在CMakeLists中使用这些信息

if(${CMAKE_DEB_HOST_ARCH} MATCHES "armhf")
  ...
elseif(${CMAKE_DEB_HOST_ARCH} MATCHES "i386")
  ...
else()
  ...
endif()

这篇帖子很旧,如果在这里复活死者,我很抱歉,但我想我会分享我提出的解决方案

我不想使用任何外部应用程序,不幸的是,我们正在使用的toolchain.cmake文件没有在另一个变量中设置arch,因此我通过查看
cmake_C_标志
cmake_CXX_标志
变量来检测它<
set(TARGET_ARCH_REGEX "^.*-march[= ]([^ ]+).*$")
string(REGEX MATCH "${TARGET_ARCH_REGEX}" TARGET_ARCH_MATCH ${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS})
if (TARGET_ARCH_MATCH)
    string(REGEX REPLACE "${TARGET_ARCH_REGEX}" "\\1" TARGET_ARCH ${CMAKE_C_FLAGS} ${CMAKE_CXX_FLAGS})
else()
    set(TARGET_ARCH ${CMAKE_HOST_SYSTEM_PROCESSOR})
endif()