2010-11-09 15 views
25

+1 für jede Information, die hilft, das ganze Bild zu vervollständigen. Sie müssen die ganze Antwort nicht kennen. Ich werde einzelne Teile des Puzzles genauso schätzen. Vielen Dank.Wie kompilieren Sie für Linux x86 mit Linux amd64, cmake und g ++ kompilieren?

Ich bin dabei, meine erste Cross-Compilation zu versuchen. Ich habe sowohl SO als auch das Internet durchsucht und viele Informationen gefunden, aber ich weiß nicht immer, wie ich diese Teile zusammenfügen soll, weil es noch einige fehlende Teile gibt.

Mein Gastgeber: Linux Kubuntu AMD64.
Ziel: Linux Kubuntu x86 (32bit) (sollte einfach sein, nicht?)
Tools: g ++ und cmake.

Hier ist die Information, die ich gefunden:

How to compile a 32-bit binary on a 64-bit linux machine with gcc/cmake
Export erwähnt CFLAGS = -m32. Das ist ein Stück.

Cross-platform: selecting data types to use 32/64 bit
erwähnt Datentypen. Ich muss darauf in meinem Code achten.

#ifdef for 32-bit platform
#ifdef für 32-Bit-Plattform
Links auf die folgenden, obwohl ich noch nicht sicher bin, wie es zu benutzen:
http://predef.sourceforge.net/prearch.html

http://ww.ubuntuforums.org/showthread.php?t=1377396
Ich habe ein: sudo apt-get installieren g ++ - multilib

fehlende Teile:

Idealfall, wenn ich 'make' (mit c make), sollte es sowohl eine amd64-Binärdatei als auch eine x86-Nachricht ausgeben.

Teil meiner CMakeLists.txt sieht wie folgt aus:

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) 

Wie kann ich die Flagge -m32 führen eine zweite ausführbare Datei zu erstellen?

Soll ich nur eine ausführbare Datei erstellen (z. B. zum Testen und Debuggen), wie sage ich cmake, ob es eine oder beide Binärdateien erstellen soll?

Auch können Sie sehen, dass ich einige Drittanbieter-Bibliotheken verwenden, von denen ich einige selbst kompilieren musste. Bedeutet das, dass ich auch jede dieser Binärdateien für den Ziel-Host kompilieren muss? Einige verwenden cmake und einige verwenden: ./configure; machen;
Wie würde ich diese Bibliotheken für den Ziel-Host kompilieren (zu verwendende Flags usw.)?

Hinweis: Die dynamisch verknüpften Bibliotheken sind bereits kompiliert und auf dem Zielcomputer installiert, also muss ich mich vielleicht nicht um diesen Schritt kümmern ... Ich bin mir nicht sicher: Das ist eines meiner fehlenden Teile ...

Was ich brauche ist eine Art Tutorial, oder zumindest einige der fehlenden Teile. Ich werde diesen Beitrag mit weiteren Details darüber, was ich erreicht habe, und wie.

Danke.

P.S.

Ist es überhaupt möglich?

Suche mehr, fand ich diese:
http://www.mail-archive.com/[email protected]/msg26265.html
„Der ursprüngliche Entwurf nicht für etwas mehr als windows-Linux oder Linux-Fenster überqueren compiles entworfen zu sein scheint.“
cmake ist NICHT getestet für Linux Amd64 zu Linux x86.

http://www.cmake.org/Wiki/CMake_Cross_Compiling#FAQ.2FPotential_Problems
"Bei gemischten 32/64-Bit-Linux-Installationen kann die Kreuzkompilierung nicht nur für 32/64 Bit verwendet werden."

??

Antwort

5

dies ist eine vereinfachte Version von dem, was ich benutze, und es tut x86-Binärdateien erstellen:

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) 

außerdem werden Sie add_definitions verwenden Compiler-Flags wie -W Ox -Dxxx usw.

einstellen

Alle oben genannten Linien aufgeteilt sind tatsächlich in separaten cmake Dateien und eine Datei erhalten eine Reihe von ausführbaren Dateien zu erstellen, erstelle ich einen Master Cmake Datei, die alle unterschiedlichen Konfigurationen enthalten ich aufbauen wollen:

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 

Dann gibt es ein Treiber Shell-Skript, um alles zu bauen. Es werden Befehlszeilenoptionen verwendet, um einige zusätzliche Optionen festzulegen und um alles oder nur eine Konfiguration zu erstellen. Hier ist ein Stück davon:

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 

Während dies ist nicht genau das, was Sie verlangen, es funktioniert einwandfrei und macht das gleiche. (Nicht sicher, ob es in cmake möglich ist, eine beliebige Anzahl von Zielen in cmake selbst zu definieren und sie alle zusammen in einer Datei zu erzeugen.) Es dauert nur ein wenig Zeit, um den Generator für diese Dateien zu schreiben, aber sobald das erledigt ist Sie müssen den Generator auf ein Verzeichnis mit Quellen verweisen, lassen Sie ihn ausführen und rufen Sie dann das Build-Skript auf, um alles zu erstellen.

+0

+1 Danke für die ausführliche Zuschreibung. Ich werde das alles studieren und sehen, was ich tun kann. – augustin

6

Mit dieser Lösung können Sie Ihr cmake-Projekt auf einem Linux64-Host mit 32-Bit-Zielsystem auf Systemen mit Multi-Arch-Unterstützung kompilieren. Es verwendet eine "gefälschte" CMake-Toolchain, so dass CMAKE irgendwie glaubt, dass es auf einem 32-Bit-System ist, also keine zusätzlichen Modifikationen in Ihren cmake-Projektdateien benötigt werden, keine speziellen Konfigurationen, keine speziellen Einstellungen (naja).

  1. Installieren multilib Unterstützung:

    $sudo apt-get install gcc-multilib 
    
  2. erstellen "fake" linux32 Werkzeugkette

Zuerst erstellen wir ein "fake" i686-Compiler. Gehe dorthin, wo sich deine CMakeLists.txt befindet, und erstelle ein bin-Verzeichnis. Öffnen Sie Ihren bevorzugten Editor und erstellen Sie dieses einfache Bash-Skript für den gcc-Compiler.

Wie Sie sehen, rufen Sie einfach den Systemcompiler auf, indem Sie das Flag -m hinzufügen. Speichern Sie dies als i686-linux-gnu-gcc. Machen Sie dasselbe für den g ++ - Compiler

#!/bin/sh 
/usr/bin/g++ -m32 "[email protected]" 

Speichern Sie es als i686-linux-gnu-g ++.Denken Sie daran, die ausführbaren Flags setzen auf diesem SCRIPs

erstellen auch einen symbolischen Link auf das System ar binär in dieser Form

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

Endlich schafft die Toolchain-linux32.cmake Datei

# 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++) 

und Erstellen Sie das Build-Verzeichnis und rufen Sie cmake mit der Toolchain-Datei als Argument auf

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

und fertig !!!!!

Ich schreibe eine komplette Anleitung here, die einige Probleme, die ich mit Bibliotheken deckt nicht Multi-lib-konform

8

Wenn Sie eine Toolchain-Datei verwenden möchten, ist eine einfachere Lösung (IMHO) als das, was vorgeschlagen von @auledoom. Sie brauchen nicht auf alle Shell-Wrapper-Skripte zu schreiben, das einfach in der Toolchain-Datei setzen:

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

Das es sich um eine „Liste Variable“ in Cmake machen. Diese Lösung funktioniert für mich. Vorteil der Toolchain-Datei ist, dass Sie dort auch Pfade für 32bit-Bibliotheken definieren können, die sich normalerweise von Standardpfaden unterscheiden.

2

Hier ist das grundlegende Rezept, das ich die ganze Zeit für cmake Projekte verwenden ..

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

Dann automatisch jedes Ziel die .bin hat. $ {Arch} Erweiterung, und ich habe nie darüber für jede denken Ziele, die ich hinzufüge. Das $ {BIN_LIBROOT} ist nützlich, wenn Sie eine Reihe vorkompilierter Bibliotheken haben, da Sie diese verwenden können, um dynamisch nach libs in Ihren privaten lib-Verzeichnissen zu suchen, basierend auf der Zielplattform/dem Zielverzeichnis.

+0

Jetzt verwende ich das hauptsächlich nur während der Entwicklung auf meinem 64-Bit-Desktop. Wenn ich meine finalen Release Linux Binaries erstelle, baue ich sie in einer CentOS 6 Chroot (2 davon .. ein 32bit und ein 64bit) mit Mock. – Urkle

4

Alles, was Sie brauchen, ist -m32 zu CFLAGS und CXXFLAGS hinzuzufügen, wenn CMake ausgeführt wird. Dies kann über die Umgebungsvariablen durchgeführt werden:

$ CFLAGS=-m32 CXXFLAGS=-m32 cmake . 

oder durch entsprechende CMake Variablen einstellen:

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

Dies kann leicht mit einem einfachen CMake Projekt getestet:

$ 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 

wo CMakeLists.txt ein triviale CMake-Datei:

project(TEST) 
add_executable(foo foo.cc) 

und foo.cc ist wie folgt:

int main() {}