我做了很多研究并且无法找到答案...我怎样才能使用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?
答案 0 :(得分:33)
所以我为我的问题设计了一个相当有创意的解决方案......似乎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)。
我已经使用Visual Studio 9和10生成器(x86,x86_64,ia64),Xcode,NMake,MSYS Makefiles和Unix Makefiles在Windows,OS X和Linux上测试和验证了它的工作原理。每次都会返回正确的结果。
注意:如果您故意执行将-m32或-m64传递给编译器或其他可能影响目标体系结构的标志(有没有办法通过所有环境),此解决方案可能会失败设置到try_run?);这不是我测试过的东西。只要您使用生成器的默认设置并且所有目标都是针对相同的体系结构进行编译,您应该没问题。
我的解决方案的完整源代码可以在GitHub上找到:https://github.com/petroules/solar-cmake/blob/master/TargetArch.cmake
答案 1 :(得分:15)
我为主机和目标系统相同的情况提供了解决方案。
首先,您需要调用“uname -m”来获取“计算机硬件名称”。之后,您需要切断尾随的“回车”以将实际值恢复为提供的变量。
EXECUTE_PROCESS( COMMAND uname -m COMMAND tr -d '\n' OUTPUT_VARIABLE ARCHITECTURE )
现在你可以打印出变量$ {ARCHITECTURE}:
message( STATUS "Architecture: ${ARCHITECTURE}" )
或做一些Canonization来映射,例如“x86_64”,“amd64”,...例如“64位”。 32Bit也是如此。 有了这个,您可以执行archtecture dependend Compilation,如:
if( ${ARCHITECTURE} STREQUAL "64Bit" )
set( BLA_LIBRARY "/opt/lib/libBla.so" )
else()
set( BLA_LIBRARY "/opt/lib32/libBla.so" )
endif()
答案 2 :(得分:7)
Android ${ANDROID_ABI}
${ANDROID_ABI}
变量是在Android中使用的方式,它假设arm64-v8a
,x86_64
等值。
我在NDK: How to include Prebuilt Shared Library Regardless of Architecture
进一步评论了这个例子答案 3 :(得分:5)
我认为你的构建过程涉及多个目标,我最好让CMake 知道它正构建的ARCH /工具链。 您可以按照instructions进行CMake交叉编译,鼓励您创建工具链CMake文件,该文件允许您选择正在使用的工具链/编译器。
我创建了一个用于为arm处理器构建我的C ++ Linux应用程序,并将其命名为toolchain-arm.cmake
。
它包括set(CMAKE_SYSTEM_PROCESSOR arm)
。
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)
答案 4 :(得分:1)
这篇文章很老了,很抱歉如果在这里复活死者,但我只是觉得我分享了我所做的解决方案。
我不想使用任何外部应用程序,遗憾的是我们使用的toolchain.cmake文件并没有将arch设置在另一个变量中,所以我通过查看{{{ 1}}和CMAKE_C_FLAGS
变量查找GCC的CMAKE_CXX_FLAGS
参数。如果没有,则会回退到-march
。
快速浏览一下Clang文档似乎表明这不适用于那个,但它只需要第二个正则表达式步骤来匹配其预期的参数。
CMAKE_HOST_SYSTEM_PROCESSOR
答案 5 :(得分:0)
目前,您不需要任何黑客来确定目标架构:每个目标变量OSX_ARCHITECTURES已添加到cmake中,可用于您的目的: http://public.kitware.com/Bug/view.php?id=8725
答案 6 :(得分:-1)
我认为最简单,最可靠的解决方案是为您正在构建的平台手动指定架构(您可以使用cmake . -DMY_ARCHITECTURE=x86
或类似的东西)。至少那是我们在项目中所做的事情,因为你上面描述了同样的问题
答案 7 :(得分:-3)
这是一种经过充分测试的了解主机架构的方法:
# 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()