如何使用CMake检测目标架构?

Jak*_*les 41 architecture build-process qmake cmake

我已经做了很多研究并且无法找到答案...我怎样才能可靠地找到我正在编译的目标架构,使用CMake?基本上,相当于qmake中的QMAKE_TARGET.arch.

大多数消息来源似乎建议使用CMAKE_SYSTEM_PROCESSOR,但这是一个糟糕的解决方案,因为无论你是在编译i386,x86_64,ppc还是ppc64,它都会在OS X上返回i386.

同样,CMAKE_SIZEOF_VOID_P给出的指针大小的系统,而不是目标.

我知道有CMAKE_OSX_ARCHITECTURES,但如果没有设置,这可能是空的,在这种情况下,它似乎默认为系统能够做的任何事情.那么如何找到目标架构信息呢?

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

Jak*_*les 36

所以我为我的问题设计了一个相当有创意的解决方案......看来CMake没有任何功能来检测目标架构.

现在,我们知道我们可以很容易地做到这一点在C,因为相同的符号__i386__,__x86_64__这取决于你的环境等,将被定义.幸运的是,CMake有一个try_run函数,可以在配置阶段编译和运行任意C源代码文件.

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

事情变得有趣.我们可以通过故意编写一个破碎的C程序来利用C预处理器来获取必要的信息...我们使用基于ifdef将体系结构名称写入控制台的原始概念,但是我们只需要放置一个#错误预处理程序指令代替printf调用.

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

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

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

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

注意:如果您故意执行诸如将-m32或-m64传递给编译器或其他可能影响目标体系结构的标志(有没有办法将所有环境设置传递给try_run?),此解决方案可能会失败; 这不是我测试过的东西.只要您使用生成器的默认设置并且所有目标都是针对相同的体系结构进行编译,您应该没问题.

我的解决方案的完整源代码可以在GitHub上找到:https://github.com/petroules/solar-cmake/blob/master/TargetArch.cmake

  • 这是HOST系统的处理器类型,即您用于构建的系统.这可能并不总是与您正在构建软件的系统TARGET相同.例如,当您编写iPhone应用程序时,您的HOST系统是OS X,而您的TARGET是iOS.如果您正在编写Mac应用程序,则主机和目标都将是OS X.CMAKE_HOST_SYSTEM_PROCESSOR通常完全无用 - 例如,它在64位OS X系统上返回"i386",而在其他系统上可能返回其他不太有用的值同样. (3认同)
  • 很棒的帖子,感谢分享。我正在调整您的方法,但使用 CMake 的execute_process 函数直接使用预处理器。`${CMAKE_C_COMPILER} -E -P platformtest.c` 与我的交叉编译器 ${CMAKE_C_COMPILER}。它的输出噪音较小,使用 STDOUT,可以区分成功和失败,不需要任何解析,不依赖于编译器如何显示错误。请参阅https://gist.github.com/webmaster128/e08067641df1dd784eb195282fd0912f (3认同)
  • CMAKE_SYSTEM_PROCESSOR 为此目的不起作用吗? (2认同)
  • 原谅我的无知......为什么Cmake不做你描述的事情并为我们提供一个变量?没有配置的生成有什么好处?你有没有“设置(CMAKE_VERBOSE_MAKEFILE on)”并查看他们的标志在*每个*平台上有多糟糕,从i686和x86_64到AMR和MIPS?难怪他们默认隐藏输出...... (2认同)

小智 17

我为主机和目标系统相同的情况提供了解决方案.

首先,您需要调用"uname -m"来获取" 机器硬件名称 ".之后,您需要切断尾随的" 回车符 "以将实际值恢复为提供的变量.

EXECUTE_PROCESS( COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE ARCHITECTURE )
Run Code Online (Sandbox Code Playgroud)

现在你可以打印出变量$ {ARCHITECTURE}:

message( STATUS "Architecture: ${ARCHITECTURE}" )
Run Code Online (Sandbox Code Playgroud)

或做一些Canonization来映射,例如"x86_64","amd64",...到例如"64Bit".32Bit也是如此.有了这个,您可以执行archtecture dependend Compilation,如:

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

  • CMAKE_SYSTEM_PROCESSOR 包含 uname -s 的输出,或者在 Windows 上,包含环境变量 PROCESSOR_ARCHITECTURE。 (2认同)

Cir*_*四事件 10

Android的 ${ANDROID_ABI}

${ANDROID_ABI}变量是在Android中,它假定像值要走的路arm64-v8a,x86_64等等.

它用于官方NDK库示例:https://github.com/googlesamples/android-ndk/blob/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs/app/src/main/cpp/CMakeLists.txt#L25

我进一步评论了这个例子:NDK:如何包含预建的共享库,无论架构如何


Par*_*rse 5

如果您的构建过程涉及多个目标,那么最好让CMake 知道要针对哪个ARCH /工具链。您可以按照说明进行操作 CMake交叉编译进行,鼓励您创建工具链CMake文件,该文件可让您选择使用的工具链/编译器。

我已经创建了一个用于为手臂处理器构建我的C ++ Linux应用程序,并将其命名为 toolchain-arm.cmake

它包括set(CMAKE_SYSTEM_PROCESSOR arm)

然后我像这样执行CMake:

cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE={my toolchain cmake path}/toolchain-arm.cmake {my source path}

在我项目的CMakeList.txt中,我可以使用任何方式引用CMAKE_SYSTEM_PROCESSOR。

在为X86构建时,我不包含对-DCMAKE_TOOLCHAIN_FILE的引用,因此未定义CMAKE_SYSTEM_PROCESSOR,或者至少未将其定义为arm

这是我的toolchain-arm.cmake

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)
Run Code Online (Sandbox Code Playgroud)

  • *“...最好让 CMake 知道它正在构建的 ARCH/工具链。...”* - CMake 是构建系统。它应该检测平台并告诉我们它是什么;反之则不然。 (4认同)