使用 CMake 强制进行 32 位编译的正确方法

Posted

技术标签:

【中文标题】使用 CMake 强制进行 32 位编译的正确方法【英文标题】:The proper way of forcing a 32-bit compile using CMake 【发布时间】:2011-08-13 22:26:05 【问题描述】:

很抱歉,有很多类似的问题,但我确实发现谷歌搜索 CMake 查询总是会产生类似但不一样的场景、冲突的 CMake 命令等等!

我需要强制我的项目构建 32 位二进制文​​件,因为我必须链接一个仅作为 32 位可用的库。我根据以下错误消息进行了诊断:

/usr/bin/ld: i386 architecture of input file `*external-32bit-lib*' is incompatible with i386:x86-64 output

据我所知,我应该使用:

set (CMAKE_CXX_FLAGS "-m32")

这确实改变了一些事情 - 我现在遇到了几个错误,例如:

/usr/bin/ld: i386 architecture of input file `*project-output-lib*' is incompatible with i386:x86-64 output

并且外部库也仍然会出现相同的错误。我认为这是因为-m32 使 gcc 生成 32 位二进制文​​件,但 ld 仍在尝试 64 位输出?进一步谷歌搜索这个问题并没有成功,所以如果有人能验证我是正确的并给出正确的方法,我将非常感激!

非常感谢!

【问题讨论】:

【参考方案1】:

如果您想使用 cmake 编译和链接 32 位,请使用它来创建库和二进制文件:

创建库:

add_library(mylib SHARED my_source.c)
set_target_properties(mylib PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")

创建可执行文件:

add_executable(mybin sources.c)
set_target_properties(mybin PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")

【讨论】:

此方法在 3.12 中不再适用,因为 COMPILE_FLAGS 已弃用 COMPILE_FLAGS 替换为 COMPILE_OPTIONS 以不使用已弃用的属性。 如果这个项目包含许多库和可执行文件,是否有可能明智地强制这个项目? 我收到LINK : warning LNK4044: unrecognized option '/m32'; ignored【参考方案2】:

通过以下来源使用TRY_RUN 命令。

大小.cpp:

#include <cstdlib>

int main( int argc, char** argv )

  size_t size = sizeof(void*);
  if ( size == 4 )
    return 0;
  return 1;

CMakeLists.txt:

TRY_RUN(RUN_RESULT_VAR COMPILE_RESULT_VAR $your_temp_dir size.cpp RUN_OUTPUT_VARIABLE IS_64_SYSTEM)
IF(IS_64_SYSTEM)
  MESSAGE(FATAL_ERROR "64 compiling not allowed!")
ENDIF(IS_64_SYSTEM)

它适用于所有标准编译器。

【讨论】:

【参考方案3】:

我使用了malat的方法,做了一个Toolchain文件。

我有一个可以在一些 Linux 发行版上运行的工具链文件,也许它会给你灵感。它可能按原样为您工作,或者您可能需要其他丑陋的黑客来获得您依赖的其他 cmake 脚本或 w/e:

https://github.com/visualboyadvance-m/visualboyadvance-m/blob/master/cmake/Toolchain-cross-m32.cmake

【讨论】:

【参考方案4】:

即使这看起来像是额外的工作,我相信在这种情况下,一个合适的解决方案是使用工具链文件。比如:

# the name of the target operating system
set(CMAKE_SYSTEM_NAME Linux)

# which compilers to use for C and C++
set(CMAKE_C_COMPILER gcc)
set(CMAKE_C_FLAGS -m32)
set(CMAKE_CXX_COMPILER g++)
set(CMAKE_CXX_FLAGS -m32)

# here is the target environment located
set(CMAKE_FIND_ROOT_PATH   /usr/i486-linux-gnu )

# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

那么用法很简单:

$ cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake /path/to/source

这里的重要部分是现在可以指定一个根目录路径 (CMAKE_FIND_ROOT_PATH),它应该用于搜索第三方库。实际上,您的编译器可能不够聪明,无法知道在 x86_64 系统上的何处搜索 x86 Qt 库。

拥有一个工具链文件允许在标准编译器的基础上指定一个不同的工具链文件,并且您应该能够在从 Windows 环境中以 32 位编译时调整该选项。

现在这是额外的工作,因为从 x86_64 Linux 操作系统编译 32 位非常简单,但此解决方案适用于其他更奇特的设置。

有关工具链文件的更多信息,可以查看例如:

http://www.cmake.org/Wiki/CmakeMingw

【讨论】:

工具链文件可能有点多,而cmake /path/to/source -DCMAKE_CXX_FLAGS=-m32 -DCMAKE_C_FLAGS=-m32 可能会这样做,但这两种是处理这种情况的唯一正确方法。 CMakeLists.txt 不应包含此类“信息”。除非 OP 想要阻止 64 位编译发生。 @rubenvb 如我的帖子中所述,您仍然需要CMAKE_FIND_ROOT_PATH 来帮助cmake 处理find_package(Qt) 之类的事情 使用此技术和 cmake 3.9.3 ,在我第一次创建构建目录时,工具链中定义的 CMAKE_CXX_FLAGS 不会在子项目中传播。但是,如果您第二次运行命令来创建构建目录而不删除现有的构建目录,行为会发生变化!!!我不完全知道这是否是一个正常功能......为了解决这个问题,我在工具链文件中定义了 CMAKE_CXX_FLAGS 如下:set(CMAKE_CXX_FLAGS "$CMAKE_CXX_FLAGS -m32" CACHE STRING "c++ flags") 您有什么建议可以轻松切换编译 32 / 64 ? (我的意思是没有文件版本)【参考方案5】:

CMAKE_CXX_FLAGS 仅影响 C++ 编译器。您可能还必须为 C 编译器设置标志:

set (CMAKE_C_FLAGS "-m32")

【讨论】:

【参考方案6】:

听起来你也没有将 m32 传递给 LFLAGS,或者有旧的 obj 文件在偷偷摸摸。请务必先清洁。

这个问题和你的类似:cmake, gcc, cuda and -m32

【讨论】:

谢谢 - 很可能是这样 - 但我将如何通过 CMake 做到这一点?这是最明智或“正确”的方式吗?顺便说一句,我确实很干净 :) 更新了答案。见链接。我的意思是清洁你的手,你很脏:) 干杯,但不幸的是该链接似乎没有帮助。设置 LDFLAGS 好像没有效果...

以上是关于使用 CMake 强制进行 32 位编译的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

cmake跨平台编译之判断操作系统平台32位64位系统

解决Android Studio使用CMake无法编译出32位armeabi平台so库

强制 gcc 在 64 位平台上编译 32 位程序

使用 mingw-w64 和 cmake 构建 32 位和 64 位应用程序

cmake编译win下64位obs

android studio 2.2.2 32位怎么配置ndk cmake环境