如何使用 linux amd64、cmake 和 g++ 交叉编译 linux x86?

发布于 2024-10-01 19:15:23 字数 2421 浏览 0 评论 0原文

每条有助于完成整个图片的信息+1。您不需要知道全部答案。我也会同样欣赏拼图中的各个部分。谢谢。

我即将尝试我的第一次交叉编译。我搜索了SO和网络,发现了很多信息,但我并不总是知道如何将这些信息组合在一起,因为仍然有一些缺失的信息。

我的主机:linux Kubuntu amd64。
目标:linux kubuntu x86(32位)(应该很容易,不是吗?)
工具:g++ 和 cmake。

这是我找到的信息:

如何使用 gcc/cmake 在 64 位 Linux 机器上编译 32 位二进制文​​件
提到导出 CFLAGS=-m32。那是一件。

跨平台:选择要使用的数据类型 32/64一点
提到数据类型。我可能需要注意我的代码中的这一点。

#ifdef 适用于 32 位平台
#ifdef 适用于 32 位平台
链接到以下内容,尽管我不太确定如何使用它:
http://predef.sourceforge.net/prearch.html

http://ww.ubuntuforums.org/showthread.php?t=1377396
我做了: sudo apt-get install g++-multilib

缺少的部分:

理想情况下,当我执行“make”(使用 cmake)时,它应该吐出 amd64 二进制文件和 x86 二进制文件。

我的 CMakeLists.txt 的一部分如下所示:

add_definitions(-Wall -pthread)
add_executable (../run.amd64 user.cpp time.cpp init.cpp utils.cpp main.cpp)
target_link_libraries(../run.amd64 cppcms dbixx config++ ctemplate)

How do I不能引入标志 -m32 来创建第二个可执行文件?

如果我只想制作一个可执行文件(例如用于测试和调试),我如何告诉 cmake 制作一个或两个二进制文件?

另外,你可以看到我使用了一些第三方库,其中一些是我必须自己编译的。这是否意味着我还需要为目标主机编译每个二进制文件?有些使用 cmake,有些使用:./configure;制作;
我该如何为目标主机编译这些库(要使用的标志等)?

注意:动态链接库已经编译并安装在目标计算机上,所以也许我不需要担心这一步...我不确定:这是我缺少的部分之一...

我需要的是一种教程,或者至少是一些缺失的部分。我将更新这篇文章,提供有关我所取得的成就以及如何取得的更多详细信息。

谢谢。

PS

这有可能吗?

搜索更多,我发现了这个:
http://www.mail-archive.com/[电子邮件受保护]/msg26265.html
“最初的设计似乎只是为 windows-linux 或 linux-windows 交叉编译而设计的。”
cmake 未针对 linux amd64 到 linux x86 进行测试。

http://www.cmake.org/Wiki/CMake_Cross_Compiling#FAQ.2FPotential_Problems
“在混合 32/64 位 Linux 安装上,交叉编译不能仅用于构建 32/64 位。”

??

+1 for each piece of information that helps to complete the whole picture. You don't need to know the whole answer. I'll appreciate individual pieces of the puzzle just as much. Thanks.

I am about to attempt my first cross-compilation. I have searched both SO and the web and found many pieces of information, but I don't always know how to put those pieces together because there are still some missing pieces.

My host: linux Kubuntu amd64.
Target: linux kubuntu x86 (32bit) (should be easy, no?)
Tools: g++ and cmake.

Here is the information I found:

How to compile a 32-bit binary on a 64-bit linux machine with gcc/cmake
mentions export CFLAGS=-m32. That's one piece.

Cross-platform: selecting data types to use 32/64 bit
mentions data types. I may have to pay attention to that within my code.

#ifdef for 32-bit platform
#ifdef for 32-bit platform
links to the following, although I am not too sure yet how to use it:
http://predef.sourceforge.net/prearch.html

http://ww.ubuntuforums.org/showthread.php?t=1377396
I did: sudo apt-get install g++-multilib

missing pieces:

Ideally, when I do 'make' (with cmake), it should spit out both a amd64 binary and a x86 one.

Part of my CMakeLists.txt looks like this:

add_definitions(-Wall -pthread)
add_executable (../run.amd64 user.cpp time.cpp init.cpp utils.cpp main.cpp)
target_link_libraries(../run.amd64 cppcms dbixx config++ ctemplate)

How do I introduce the flag -m32 to create a second executable?

Should I want to make only one executable (e.g. for testing and debugging), how do I tell cmake to make either one or both binaries?

Also, you can see that I use some third party libraries, some of which I had to compile myself. Does this mean that I need to compile each of those binaries for the target host as well? Some use cmake and some use: ./configure; make;
How would I do about compiling those libraries for the target host (flags to use, etc.)?

Note: the dynamically linked libraries are already compiled and installed on the target computer, so maybe I don't need to worry about this step... I am not sure: this is one of my missing pieces...

What I need is a kind of tutorial, or at least some of the missing pieces. I'll update this post with more details on what I achieved and how.

Thanks.

P.S.

Is it possible at all?

Searching more, I found this:
http://www.mail-archive.com/[email protected]/msg26265.html
"The original design doesn't seem to be designed for anything more than windows-linux or linux-windows cross compiles."
cmake is NOT tested for linux amd64 to linux x86.

http://www.cmake.org/Wiki/CMake_Cross_Compiling#FAQ.2FPotential_Problems
"On mixed 32/64 bit Linux installations cross compilation cannot be used to build for 32/64 bit only."

??

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

夏日落 2024-10-08 19:15:23

如果您想使用工具链文件,有一个比 @auledoom 提出的解决方案更简单的解决方案(恕我直言)。您根本不需要编写 shell 包装器脚本,只需将其放入工具链文件中即可:

# 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 -m32)
set(CMAKE_CXX_COMPILER g++ -m32)

这将使其成为 cmake 中的“列表变量”。这个解决方案对我有用。工具链文件的好处是您还可以定义 32 位库等的路径,这通常与标准路径不同。

If you want to use a toolchain file there is an easier solution (IMHO) than what is proposed by @auledoom. You do not need to write the shell wrapper scripts at all, simply put this in the toolchain file:

# 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 -m32)
set(CMAKE_CXX_COMPILER g++ -m32)

This will make it a "list variable" in cmake. This solution works for me. Benefit of the toolchain file is that you can there also define paths for 32bit libraries etc, which is usually different from standard paths.

天邊彩虹 2024-10-08 19:15:23

该解决方案将允许您在面向 32 位的 linux64 主机上、在具有多架构支持的系统上交叉编译您的 cmake 项目。
它使用“假”cmake 工具链,因此 CMAKE 以某种方式“相信”它在 32 位系统上,因此不需要在 cmake 项目文件中进行任何额外修改,不需要特殊配置,不需要特殊设置(几乎)。

  1. 安装多库支持:

    $sudo apt-get install gcc-multilib
    
  2. 创建一个“假”linux32 工具链

首先,我们创建一个“假”i686 编译器。转到 CMakeLists.txt 所在的位置并创建一个 bin 目录。打开您喜欢的编辑器并为 gcc 编译器创建这个简单的 bash 脚本。

#!/bin/sh
/usr/bin/gcc -m32 "$@"

如您所见,它只是调用添加 -m 标志的系统编译器。将其保存为 i686-linux-gnu-gcc。对 g++ 编译器执行相同操作,

#!/bin/sh
/usr/bin/g++ -m32 "$@"

将其保存为 i686-linux-gnu-g++。请记住在此脚本上设置可执行标志

还以这种形式创建到系统 ar 二进制文件的符号链接

$ln /usr/bin/ar i686-linux-gnu-ar

最后创建 toolchain-linux32.cmake 文件

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

# Which compilers to use for C and C++
set(CMAKE_C_COMPILER ${CMAKE_SOURCE_DIR}/bin/i686-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER ${CMAKE_SOURCE_DIR}/bin/i686-linux-gnu-g++)

并创建构建目录并使用工具链文件作为参数调用 cmake

$mkdir build && cd build
$cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-linux32.cmake ..

,您就完成了! !!!

我将在此处编写更完整的指南,其中涵盖了我与不兼容多库的库遇到的一些问题

This solution will allow you cross-compile your cmake project on a linux64 host targeting 32bits, on systems with multi-arch support.
It's uses a "fake" cmake toolchain so CMAKE somehow "believes" it's on 32bit system, so no additional modifications are needed inside your cmake project files, no special configurations, no special settings (well almost).

  1. Install multilib support:

    $sudo apt-get install gcc-multilib
    
  2. Create a "fake" linux32 toolchain

First, we create a "fake" i686 compiler. Go where your CMakeLists.txt resides and create a bin directory. Open your preferred editor and create this simple bash script for gcc compiler.

#!/bin/sh
/usr/bin/gcc -m32 "$@"

As you see, it's just make a call to the system compiler adding the -m flag. Save this as i686-linux-gnu-gcc. Do the same for the g++ compiler

#!/bin/sh
/usr/bin/g++ -m32 "$@"

Save it as i686-linux-gnu-g++. Remember to set the executable flags on this scrips

Create also a symlink to the system ar binary in this form

$ln /usr/bin/ar i686-linux-gnu-ar

At last create the toolchain-linux32.cmake file

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

# Which compilers to use for C and C++
set(CMAKE_C_COMPILER ${CMAKE_SOURCE_DIR}/bin/i686-linux-gnu-gcc)
set(CMAKE_CXX_COMPILER ${CMAKE_SOURCE_DIR}/bin/i686-linux-gnu-g++)

and create the build directory and call cmake with the toolchain file as argument

$mkdir build && cd build
$cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain-linux32.cmake ..

and your done!!!!!

I'll write a more complete guide here, which covers some problems i have with libraries not multi-lib compliant

〆一缕阳光ご 2024-10-08 19:15:23

这是我使用的简化版本,它确实创建了 x86 二进制文件:

set( TargetName myExe )
set( SOURCES a.cpp b.cpp )
add_executable( ${TargetName} ${SOURCES} )
target_link_libraries( ${TargetName} m pthread stdc++ )
set_target_properties( ${TargetName} PROPERTIES COMPILE_FLAGS -m32 LINK_FLAGS -m32 )

此外,您将使用 add_definitions 来设置编译器标志,例如 -W -Ox -Dxxx 等。

上面的所有行实际上都分割在单独的 cmake 文件中,并且获取一个文件来构建多个可执行文件,我生成一个主 cmake 文件,其中包含我想要构建的所有不同配置:

project( myProject )
set( SOURCES a.cpp b.cpp )
if( ${ConfigurationType} strequal "Debugx86" )
  include( debugopts.cmake )
  include( x86.cmake )
  include( executable.cmake )
  ...
elseif( ${ConfigurationType} strequal "Releasex64" )
  include( debugopts.cmake )
  include( x86.cmake )
  include( executable.cmake )
  ...
etc

然后有一个驱动程序 shell 脚本来构建所有这些文件。它需要命令行选项来设置一些额外的选项,并选择构建所有内容或仅构建一种配置。这是其中的一部分:

if [ "$myConfig" = "all" -o "$myConfig" = "Debugx86" ]; then
  mkdir -p project_Debugx86
  cd project_Debugx86
  cmkake "$sourceDir" "$cmakeOpts" -DConfigurationType="Debugx86"
  make clean
  make "$makeopts"
fi
if [ "$myConfig" = "all" -o "$myConfig" = "Releasex64" ]; then
  mkdir -p project_Releasex64
  cd project_Releasex64
  cmkake "$sourceDir" "$cmakeOpts" -DConfigurationType="Releasex64
  make clean
  make "$makeopts"
fi

虽然这并不完全是您所要求的,但它可以完美地工作并且执行相同的操作。 (不确定 cmake 是否可以在 cmake 本身中定义任意数量的目标,并通过一个文件将它们全部构建在一起。)只需要一些时间来为该文件编写生成器,但是一旦完成,我就可以了要做的就是将生成器指向包含源代码的目录,让 ir 运行,然后调用构建脚本来生成所有内容。

this is a simplified version of what I use, and it does create x86 binaries:

set( TargetName myExe )
set( SOURCES a.cpp b.cpp )
add_executable( ${TargetName} ${SOURCES} )
target_link_libraries( ${TargetName} m pthread stdc++ )
set_target_properties( ${TargetName} PROPERTIES COMPILE_FLAGS -m32 LINK_FLAGS -m32 )

furthermore you'll use add_definitions to set compiler flags like -W -Ox -Dxxx etc.

All the lines above are actually split in seperate cmake files, and to get one file to build a number of executables, I generate a master cmake file containing all different configurations I want to build:

project( myProject )
set( SOURCES a.cpp b.cpp )
if( ${ConfigurationType} strequal "Debugx86" )
  include( debugopts.cmake )
  include( x86.cmake )
  include( executable.cmake )
  ...
elseif( ${ConfigurationType} strequal "Releasex64" )
  include( debugopts.cmake )
  include( x86.cmake )
  include( executable.cmake )
  ...
etc

Then there's a driver shell script to build it all. It takes commandline options to set some extra options and select to build everything or just one configuration. Here's a piece of it:

if [ "$myConfig" = "all" -o "$myConfig" = "Debugx86" ]; then
  mkdir -p project_Debugx86
  cd project_Debugx86
  cmkake "$sourceDir" "$cmakeOpts" -DConfigurationType="Debugx86"
  make clean
  make "$makeopts"
fi
if [ "$myConfig" = "all" -o "$myConfig" = "Releasex64" ]; then
  mkdir -p project_Releasex64
  cd project_Releasex64
  cmkake "$sourceDir" "$cmakeOpts" -DConfigurationType="Releasex64
  make clean
  make "$makeopts"
fi

While this is not exactly what you ask for, it works flawlessly and does the same. (Not sure if it is possible in cmake to define any number of targets in cmake itself, and have them built all together by one file.) It just takes some time to write the generator for this files, but once that is done all I have to do is point the generator to a directory with sources, let ir run, then invoke the build script to make everything.

听你说爱我 2024-10-08 19:15:23

您只需在运行 CMake 时将 -m32 添加到 CFLAGSCXXFLAGS 即可。这可以通过环境变量来完成:

$ CFLAGS=-m32 CXXFLAGS=-m32 cmake .

或通过设置相应的 CMake 变量:

$ cmake -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 .

这可以使用简单的 CMake 项目轻松测试:

$ uname -m
x86_64
$ CFLAGS=-m32 CXXFLAGS=-m32 cmake .
-- The C compiler identification is GNU 4.8.1
-- The CXX compiler identification is GNU 4.8.1
....
$ make 
Scanning dependencies of target foo
[100%] Building CXX object CMakeFiles/foo.dir/foo.cc.o
Linking CXX executable foo
[100%] Built target foo
$ file foo
foo: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x5b1871446c92cbdcbf905583e16189f68f3bf5f2, not stripped

其中 CMakeLists.txt 是一个简单的 CMake 文件:

project(TEST)
add_executable(foo foo.cc)

foo.cc< /代码>如下:

int main () {}

All you need is to add -m32 to CFLAGS and CXXFLAGS when running CMake. This can be done via environment variables:

$ CFLAGS=-m32 CXXFLAGS=-m32 cmake .

or by setting corresponding CMake variables:

$ cmake -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 .

This can easily tested with a simple CMake project:

$ uname -m
x86_64
$ CFLAGS=-m32 CXXFLAGS=-m32 cmake .
-- The C compiler identification is GNU 4.8.1
-- The CXX compiler identification is GNU 4.8.1
....
$ make 
Scanning dependencies of target foo
[100%] Building CXX object CMakeFiles/foo.dir/foo.cc.o
Linking CXX executable foo
[100%] Built target foo
$ file foo
foo: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=0x5b1871446c92cbdcbf905583e16189f68f3bf5f2, not stripped

where CMakeLists.txt is a trivial CMake file:

project(TEST)
add_executable(foo foo.cc)

and foo.cc is as follows:

int main () {}
2024-10-08 19:15:23

这是我在 cmake 项目中一直使用的基本配方。

OPTION(FORCE32 "Force a 32bit compile on 64bit" OFF)
IF(FORCE32)
    if(APPLE)
        SET(CMAKE_OSX_ARCHITECTURES "i386")
    else()
        SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32")
        SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
    endif()
ENDIF()

IF(APPLE)
    set(BIN_LIBROOT "macosx")
ELSE()
    if(CMAKE_SIZEOF_VOID_P MATCHES "8" AND NOT(FORCE32) )
        set(BIN_LIBROOT "linux64")
        set(CMAKE_EXECUTABLE_SUFFIX ".bin.x86_64")
        set(BIN_RPATH "\$ORIGIN/lib64")
    else()
        set(BIN_LIBROOT "linux")
        set(CMAKE_EXECUTABLE_SUFFIX ".bin.x86")
        set(BIN_RPATH "\$ORIGIN/lib")
    endif()

    set(CMAKE_SKIP_BUILD_RPATH TRUE)
    set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
    set(CMAKE_INSTALL_RPATH ${BIN_RPATH})
    set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
ENDIF()

然后每个目标都会自动具有 .bin.${arch} 扩展名,并且我永远不必为我添加的任何目标考虑这一点。如果您有一堆预编译库,则 ${BIN_LIBROOT} 非常有用,因为您可以使用它根据目标平台/架构动态搜索私有库目录中的库。

Here is the basic recipe I use all the time for cmake projects..

OPTION(FORCE32 "Force a 32bit compile on 64bit" OFF)
IF(FORCE32)
    if(APPLE)
        SET(CMAKE_OSX_ARCHITECTURES "i386")
    else()
        SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32")
        SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
    endif()
ENDIF()

IF(APPLE)
    set(BIN_LIBROOT "macosx")
ELSE()
    if(CMAKE_SIZEOF_VOID_P MATCHES "8" AND NOT(FORCE32) )
        set(BIN_LIBROOT "linux64")
        set(CMAKE_EXECUTABLE_SUFFIX ".bin.x86_64")
        set(BIN_RPATH "\$ORIGIN/lib64")
    else()
        set(BIN_LIBROOT "linux")
        set(CMAKE_EXECUTABLE_SUFFIX ".bin.x86")
        set(BIN_RPATH "\$ORIGIN/lib")
    endif()

    set(CMAKE_SKIP_BUILD_RPATH TRUE)
    set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
    set(CMAKE_INSTALL_RPATH ${BIN_RPATH})
    set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)
ENDIF()

Then every target automatically has the .bin.${arch} extension and I never have to think about this for any targets I add. the ${BIN_LIBROOT} is useful if you have a bunch of precompiled libraries as you as you can use that to dynamically search for libs in your private lib dirs based on the target platform/arch.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文