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

时间:2022-09-01 07:42:03

+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.

+1每条信息,帮助完成整个画面。你不需要知道整个答案。我也会非常欣赏这个拼图的各个部分。谢谢。

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.

我的主机:linux Kubuntu amd64。目标:linux kubuntu x86(32位)(应该很简单,不是吗?)工具:g++ 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.

如何在一个64位linux机器上编译一个32位的二进制文件,并使用gcc/cmake提到export CFLAGS=-m32。这是一块。

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

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

#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

对于32位平台#ifdef,对于32位平台的链接,我不太确定如何使用它:http://predef.sourceforge.net/prearch.html。

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

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

missing pieces:

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

理想情况下,当我做“make”(用cmake)时,它应该同时输出amd64和x86。

Part of my CMakeLists.txt looks like this:

我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 introduce the flag -m32 to create a second executable?

如何引入标志-m32来创建第二个可执行文件?

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?

我是否应该只做一个可执行文件(例如,用于测试和调试),我如何告诉cmake一个或两个二进制文件?

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.)?

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

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/cmake@cmake.org/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.mail-archive.com/cmake@cmake.org/msg26265.html“最初的设计似乎并不是为windows-linux或linux-windows交叉编译而设计的。”cmake并没有在linux x86平台上测试linux amd64。

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."

在32/64位的Linux安装中,不能只使用32/64位的编译器。

??

? ?

5 个解决方案

#1


8  

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:

如果您想使用工具链文件,那么有一个更简单的解决方案(IMHO),而不是@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)

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.

这将使它成为cmake中的“列表变量”。这个办法对我有效。工具链文件的好处是,您还可以为32位库定义路径,这些路径通常与标准路径不同。

#2


6  

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).

这个解决方案将允许您在一个linux64主机上交叉编译您的cmake项目,目标是32位,在具有多弓支持的系统上。它使用了一个“假”的cmake工具链,所以cmake“相信”它是在32位系统上的,所以在你的cmake项目文件中不需要额外的修改,没有特殊的配置,没有特殊的设置(几乎)。

  1. Install multilib support:

    安装multilib支持:

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

    创建一个“假”linux32工具链。

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.

首先,我们创建一个“伪”i686编译器。去你的CMakeLists的地方。txt驻留并创建一个bin目录。打开您的首选编辑器并为gcc编译器创建这个简单的bash脚本。

#!/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

正如您看到的,它只是对添加-m标志的系统编译器进行调用。保存这个i686-linux-gnu-gcc。对g++编译器也这样做吗?

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

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

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

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

在此表单中创建一个与系统ar二进制文件的符号链接。

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

At last create the toolchain-linux32.cmake file

最后创建工具链-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++)

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

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

$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

我将在这里写一个更完整的指南,它涵盖了一些与库不兼容的问题。

#3


5  

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

这是我使用的一个简化版本,它确实创建了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 )

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

此外,您还将使用add_definition来设置诸如-W -Ox -Dxxx之类的编译器标志。

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:

上面所有的行实际上都是分开的,在seperate 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

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:

然后,有一个驱动程序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

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.

虽然这不是你所要求的,但它是完美无缺的,而且是一样的。(不确定cmake中是否有可能定义cmake本身的任意数量的目标,并将它们由一个文件构建在一起。)为这些文件编写生成器只是需要一些时间,但是一旦完成,我所要做的就是将生成器指向一个有源的目录,让ir运行,然后调用构建脚本来完成所有工作。

#4


4  

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

您所需要的是在运行CMake时添加-m32到CFLAGS和CXXFLAGS。这可以通过环境变量来完成:

$ CFLAGS=-m32 CXXFLAGS=-m32 cmake .

or by setting corresponding CMake variables:

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

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

This can easily tested with a simple CMake project:

这很容易用一个简单的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

where CMakeLists.txt is a trivial CMake file:

CMakeLists的地方。txt是一个普通的CMake文件:

project(TEST)
add_executable(foo foo.cc)

and foo.cc is as follows:

和foo。cc如下:

int main () {}

#5


2  

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

这是我一直用在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()

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.

然后每个目标都会自动拥有。bin。${arch}扩展,我从来不必为我所添加的任何目标考虑这个问题。${BIN_LIBROOT}是有用的,如果您有一堆预编译的库,您可以使用它来根据目标平台/arch动态地搜索您的私有lib dirs中的libs。

#1


8  

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:

如果您想使用工具链文件,那么有一个更简单的解决方案(IMHO),而不是@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)

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.

这将使它成为cmake中的“列表变量”。这个办法对我有效。工具链文件的好处是,您还可以为32位库定义路径,这些路径通常与标准路径不同。

#2


6  

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).

这个解决方案将允许您在一个linux64主机上交叉编译您的cmake项目,目标是32位,在具有多弓支持的系统上。它使用了一个“假”的cmake工具链,所以cmake“相信”它是在32位系统上的,所以在你的cmake项目文件中不需要额外的修改,没有特殊的配置,没有特殊的设置(几乎)。

  1. Install multilib support:

    安装multilib支持:

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

    创建一个“假”linux32工具链。

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.

首先,我们创建一个“伪”i686编译器。去你的CMakeLists的地方。txt驻留并创建一个bin目录。打开您的首选编辑器并为gcc编译器创建这个简单的bash脚本。

#!/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

正如您看到的,它只是对添加-m标志的系统编译器进行调用。保存这个i686-linux-gnu-gcc。对g++编译器也这样做吗?

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

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

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

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

在此表单中创建一个与系统ar二进制文件的符号链接。

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

At last create the toolchain-linux32.cmake file

最后创建工具链-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++)

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

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

$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

我将在这里写一个更完整的指南,它涵盖了一些与库不兼容的问题。

#3


5  

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

这是我使用的一个简化版本,它确实创建了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 )

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

此外,您还将使用add_definition来设置诸如-W -Ox -Dxxx之类的编译器标志。

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:

上面所有的行实际上都是分开的,在seperate 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

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:

然后,有一个驱动程序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

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.

虽然这不是你所要求的,但它是完美无缺的,而且是一样的。(不确定cmake中是否有可能定义cmake本身的任意数量的目标,并将它们由一个文件构建在一起。)为这些文件编写生成器只是需要一些时间,但是一旦完成,我所要做的就是将生成器指向一个有源的目录,让ir运行,然后调用构建脚本来完成所有工作。

#4


4  

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

您所需要的是在运行CMake时添加-m32到CFLAGS和CXXFLAGS。这可以通过环境变量来完成:

$ CFLAGS=-m32 CXXFLAGS=-m32 cmake .

or by setting corresponding CMake variables:

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

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

This can easily tested with a simple CMake project:

这很容易用一个简单的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

where CMakeLists.txt is a trivial CMake file:

CMakeLists的地方。txt是一个普通的CMake文件:

project(TEST)
add_executable(foo foo.cc)

and foo.cc is as follows:

和foo。cc如下:

int main () {}

#5


2  

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

这是我一直用在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()

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.

然后每个目标都会自动拥有。bin。${arch}扩展,我从来不必为我所添加的任何目标考虑这个问题。${BIN_LIBROOT}是有用的,如果您有一堆预编译的库,您可以使用它来根据目标平台/arch动态地搜索您的私有lib dirs中的libs。