web-dev-qa-db-fra.com

Comment compiler un programme C++ sous Windows pour ARM en utilisant LLVM?

Aim Compilez un programme C++ sous Windows pour ARM en utilisant uniquement LLVM.

Pourquoi LLVM à cause des licences permissives. 

Je commence à me demander si ma compréhension de LLVM est correcte.

Faire sur la machine hôte

  1. Utilisez clang (front end) pour générer une représentation intermédiaire. Cette représentation est indépendante de la cible.
  2. Utilisez llc (back-end) pour générer le code Assembly cible.
  3. Utilisez lld-link.exe pour produire un fichier exécutable.

Puis exécutez sur la machine cible.

Machine hôte Windows 10, 64 bits

Machine cible Drive PX avec un bras cortex-a57

Le programme

int main(int argc, char* argv[]) 
{
    int x=41;
    x++;
    return x;
}

J'ai extrait et compilé LLVM (à l'aide de Visual Studio 2015, version finale, CPU = x64)

Mes tentatives 

clang.exe -target arm -march=armv8-a -mcpu=cortex-a57 -mfloat-abi=hard  -emit-llvm -c -o main.bc  main.cpp
llc.exe -march=arm -mcpu=cortex-a57 -mattr=a57,armv8-a,v8 -meabi=gnu -o main.s main.bc
lld-link.exe /entry:main /machine:arm main.s

Erreur

lld-link.exe: error: main.s: unknown file type

Ensuite, j'ai essayé de faire les étapes front-end sous Windows et le back-end sur la machine à bras. 

clang.exe -target arm -march=armv8-a -mcpu=cortex-a57 -mfloat-abi=hard  -emit-llvm -c -o main.bc  main.cpp
llc.exe -march=arm -mcpu=cortex-a57 -mattr=a57,armv8-a,v8 -meabi=gnu -o main.s main.bc
SCP main.s to the arm machine. SSH and
gcc main.s (using gcc as a test. LLVM should do this.)

Erreur 

main.s: Assembler messages:
main.s:2: Error: unknown pseudo-op: `.syntax'
main.s:3: Error: unknown pseudo-op: `.eabi_attribute'
main.s:9: Error: unknown pseudo-op: `.fpu'
main.s:26: Error: junk at end of line, first unrecognized character is `@'
main.s:29: Error: unknown pseudo-op: `.code'
main.s:31: Error: unknown pseudo-op: `.fnstart'
main.s:32: Error: junk at end of line, first unrecognized character is `@'
main.s:34: Error: operand 1 should be an integer register -- `mov r2,#0'
main.s:41: Error: operand 1 should be an integer or stack pointer register -- `add r0,r0,#1'
main.s:45: Error: unknown mnemonic `bx' -- `bx lr'
main.s:48: Error: unknown pseudo-op: `.cantunwind'
main.s:49: Error: unknown pseudo-op: `.fnend'
main.s:50: Error: junk at end of line, first unrecognized character is `@'

J'ai donc essayé de cibler uniquement Windows

clang.exe  -emit-llvm -c -o main.bc  main.cpp
llc.exe -march=x86 -c -o main.s main.bc
ld.lld.exe main.s

Erreur

ld.lld.exe: error: main.s:1: unknown directive: .text

Ensuite, au lieu de ld.lld.exe, utilisez gcc (Utilisez à nouveau gcc comme test. LLVM devrait le faire.)

clang.exe  -emit-llvm -c -o main.bc  main.cpp
llc.exe -march=x86 -c -o main.s main.bc
gcc main.s -o main.exe

Ça marche. Pour tester je tape

main.exe
echo Exit Code is %errorlevel%

Qui retourne 42

Question générale

Quelles sont les étapes à suivre pour compiler un programme C++ sous Windows ciblant un processeur armé utilisant uniquement LLVM (pas de gcc, rien téléchargé depuis ARM)?

Questions spécifiques

  1. Les outils fournis avec LLVM auto-compilé (par exemple, clang.exe, llc.exe, lld.exe) peuvent-ils compiler un fichier exécutable sur le bras de ciblage Windows? E.g est-il encore en développement?
  2. Pourquoi ma tentative de compilation et de liaison sous Windows, ciblant Windows, échoue-t-elle? 
  3. D'où proviennent les fichiers d'en-tête et les bibliothèques (par exemple, libstdc ++) lors de la liaison sur l'hôte de la cible? Je suppose que je dois obtenir ceux de la machine à bras? Copiez-les dans l'hôte et dites à l'éditeur de liens où les trouver? Est-ce exact?

Mettre à jour

J'ai donc essayé à l'origine Compilation croisée avec Clang

clang.exe --target=arm --sysroot=c:\code\clang\FromCmdLine main.cpp  -v

Le résultat est 

clang.exe: error: linker (via gcc) command failed with exit code 1 (use -v to see invocation)

Et les détails de -v sont

 "C:\\llvm\\clang.exe" -cc1 -triple armv4t-- -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name main.cpp -mrelocation-model static -mthread-model posix -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -target-cpu arm7tdmi -target-feature +soft-float -target-feature +soft-float-abi -target-feature -fp-only-sp -target-feature -d16 -target-feature -vfp2 -target-feature -vfp3 -target-feature -fp16 -target-feature -vfp4 -target-feature -fp-armv8 -target-feature -neon -target-feature -crypto -target-feature +strict-align -target-abi aapcs -msoft-float -mfloat-abi soft -fallow-half-arguments-and-returns -dwarf-column-info -debugger-tuning=gdb -v -resource-dir "c:\\llvm\\clang\\7.0.0" -isysroot "c:\\code" -fdeprecated-macro -fdebug-compilation-dir "c:\\code" -ferror-limit 19 -fmessage-length 293 -fno-signed-char -fobjc-runtime=gcc -fcxx-exceptions -fexceptions -fdiagnostics-show-option -fcolor-diagnostics -o "C:\\Users\\AppData\\Local\\Temp\\main-b17d06.o" -x c++ main.cpp
clang -cc1 version 7.0.0 based upon LLVM 7.0.0svn default target x86_64-pc-win32
ignoring nonexistent directory "c:\code\usr/local/include"
ignoring nonexistent directory "c:\code\usr/include"
#include "..." search starts here:
#include <...> search starts here:
 C:\llvm\clang\7.0.0\include
End of search list.
 "C:\\MinGW\\bin\\gcc.exe" "--sysroot=c:\\code" -v -o a.out "C:\\Users\\AppData\\Local\\Temp\\main-b17d06.o"
Using built-in specs.
COLLECT_GCC=C:\MinGW\bin\gcc.exe
COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/6.3.0/lto-wrapper.exe
Target: mingw32
Configured with: ../src/gcc-6.3.0/configure --build=x86_64-pc-linux-gnu --Host=mingw32 --target=mingw32 --with-gmp=/mingw --with-mpfr --with-mpc=/mingw --with-isl=/mingw --prefix=/mingw --disable-win32-registry --with-Arch=i586 --with-tune=generic --enable-languages=c,c++,objc,obj-c++,fortran,ada --with-pkgversion='MinGW.org GCC-6.3.0-1' --enable-static --enable-shared --enable-threads --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime-libs --with-libiconv-prefix=/mingw --with-libintl-prefix=/mingw --enable-libstdcxx-debug --enable-libgomp --disable-libvtv --enable-nls
Thread model: win32
gcc version 6.3.0 (MinGW.org GCC-6.3.0-1)
COMPILER_PATH=c:/mingw/bin/../libexec/gcc/mingw32/6.3.0/;c:/mingw/bin/../libexec/gcc/;c:/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/bin/
LIBRARY_PATH=c:/mingw/bin/../lib/gcc/mingw32/6.3.0/;c:/mingw/bin/../lib/gcc/;c:/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/lib/;c:/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../;c:/code/clang/FromCmdLine/lib/
COLLECT_GCC_OPTIONS='-v' '-o' 'a.out' '-mtune=generic' '-march=i586'
 c:/mingw/bin/../libexec/gcc/mingw32/6.3.0/collect2.exe -plugin c:/mingw/bin/../libexec/gcc/mingw32/6.3.0/liblto_plugin-0.dll -plugin-opt=c:/mingw/bin/../libexec/gcc/mingw32/6.3.0/lto-wrapper.exe -plugin-opt=-fresolution=C:\Users\AppData\Local\Temp\ccufvVIA.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt --sysroot=c:\code\clang\FromCmdLine -Bdynamic -o a.out c:/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../crt2.o c:/mingw/bin/../lib/gcc/mingw32/6.3.0/crtbegin.o -Lc:/mingw/bin/../lib/gcc/mingw32/6.3.0 -Lc:/mingw/bin/../lib/gcc -Lc:/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/lib -Lc:/mingw/bin/../lib/gcc/mingw32/6.3.0/../../.. -Lc:/code/clang/FromCmdLine/lib C:\Users\AppData\Local\Temp\main-b17d06.o -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt -ladvapi32 -lshell32 -luser32 -lkernel32 -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt c:/mingw/bin/../lib/gcc/mingw32/6.3.0/crtend.o
c:/mingw/bin/../lib/gcc/mingw32/6.3.0/../../../../mingw32/bin/ld.exe: C:\Users\AppData\Local\Temp\main-b17d06.o: Relocations in generic ELF (EM: 40)
C:\Users\AppData\Local\Temp\main-b17d06.o: error adding symbols: File in wrong format

Mettre à jour

Cela ne répond pas complètement à ma question mais cela m'aide à progresser.

Pour une meilleure compréhension, j’ai trouvé crosstool-NG utile, en particulier leur documentation (chapitres 1 à 5).

Ensuite, j'ai lu la compilation croisée cmake documentation.

J'ai écrit un petit test Cake Cake.

Helloworld.cpp

#include <iostream>
int main(int argc, char *argv[])
{
   std::cout << "Hello World!" << std::endl;
   return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.8.9)
project (hello)
add_executable(hello helloworld.cpp)

Configuration spécifique à la cible pour cmake. Ceci est de 4 .

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)

set(CMAKE_SYSROOT /home/user/x-tools/aarch64-unknown-linux-gnueabi/aarch64-unknown-linux-gnueabi/sysroot/)
set(CMAKE_STAGING_PREFIX /home/user/crosscompile/stage)

set(tools /home/user/x-tools/aarch64-unknown-linux-gnueabi)
set(CMAKE_C_COMPILER ${tools}/bin/aarch64-unknown-linux-gnueabi-gcc)
set(CMAKE_CXX_COMPILER ${tools}/bin/aarch64-unknown-linux-gnueabi-g++)

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

Et la ligne de commande

cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain_file.txt ..

Cette croix est compilée sur ARM et le programme est exécuté sur la machine ARM.

Mais cela n'utilise pas LLVM/Clang. Pour utiliser LLVM, j’ai pensé changer la configuration de la chaîne d’outils à utiliser

set(tools /usr/bin)
set(CMAKE_C_COMPILER ${tools}/clang)
set(CMAKE_CXX_COMPILER ${tools}/clang++)

Cela a échoué car ce dossier bin est destiné à la machine hôte.

J'ai également essayé d'utiliser le téléchargement AArch64 à partir de http://releases.llvm.org/download.html . Oui cela aussi n'a pas fonctionné.

Donc, en résumé, ce qui est requis.

  1. Un dossier sysroot avec la lib et inclure des dossiers pour le système cible. D'accord, il doit y avoir plus dans ce dossier sysroot que lib et include.
  2. Une chaîne d’outils (compilateur, assembleur, éditeur de liens) pour le système cible.
6
robor78

C’est ce que j’avais à faire pour obtenir une validation de principe, pour effectuer une compilation croisée en utilisant seulement llvm, avec Host = linux x86_64 et target = DrivePX (arm aarch64). (Fonctionne également avec Host = Windows 10 x86_64.) 

Je recommande un outil tel que croostool-ng qui définit une chaîne d’outils de compilation croisée, mais les étapes ci-dessous montrent ce qui se passe dans les coulisses et n’utilise que llvm.

  1. Sur l'ordinateur hôte, extrayez et compilez LLVM, y compris Clang
    • voir http://llvm.org/docs/GettingStarted.html
    • Cela prend beaucoup de temps alors faites une version release. Assurez-vous également d'avoir suffisamment d'espace (Go). 
    • Dire à cmake de créer une version release, par exemple 
    • CC=gcc CXX=g++ cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release ../llvm/
    • Alors appelez make.
  2. Appelez en attente sur l'ordinateur hôte .
    • N'oubliez pas de définir la cible, par exemple --target=aarch64-linux-gnu
    • Dites à Clang d'utiliser l'éditeur de liens llvm, c'est-à-dire -Fuse-ld=lld
    • clang --target=aarch64-linux-gnu -v main.cpp -o main -Fuse-ld=lld
  3. Il y aura beaucoup d'erreurs de l'éditeur de liens

ld.lld: erreur: impossible de trouver la bibliothèque -lgcc 

ld.lld: erreur: impossible de trouver la bibliothèque -lgcc_s 

ld.lld: erreur: impossible de trouver la bibliothèque -lc

  1. Et quelques autres erreurs sur les fichiers crtX.o manquants, par exemple:.

ld.lld: erreur: impossible d'ouvrir crt1.o: Aucun fichier ou répertoire de ce type

  1. Sur la machine cible, recherchez tous les fichiers libgcc, libc, etc.
    • N'oubliez pas de copier les bibliothèques avec version complète, par exemple pour libgcc_s.so copier libgcc_s.so.1
    • Copiez ces fichiers sur l'ordinateur hôte.
    • Indiquez à Clang où trouver ces bibliothèques, par exemple. Copiez les fichiers dans un dossier appelé libs
    • clang --target=aarch64-linux-gnu -v main.cpp -o main -Fuse-ld=lld -L./libs
    • N'oubliez pas non plus que l'éditeur de liens recherche par exemple libgcc_s.so afin de créer des liens symboliques vers par exemple libgcc_s.so.1.
  2. Copiez les fichiers crtX.o de la cible vers l'hôte. Placez-les à côté du fichier main.cpp.
  3. Puis une autre erreur

ld.lld: erreur: symbole non défini: __libc_csu_fini

  • Ce symbole est situé dans libc_nonshared.a. Et cette réponse aidé. 

libc.so est un script de l'éditeur de liens qui demande à l'éditeur de liens d'extraire la bibliothèque partagée libc.so.6 et une partie non partagée, libc_nonshared.a.

  • Sur l'hôte, recherchez et ouvrez libc.so et voyez où se trouvent libc.so.6 et libc_nonshared.a. 
  • Copiez-les dans l'hôte.
  • Dire à l'éditeur de liens d'utiliser ces 2 bibliothèques, à savoir -lc -lc_nonshared
  • clang --target=aarch64-linux-gnu -v main.cpp -o main -Fuse-ld=lld -L./libs -lc -lc_nonshared

Mon code texte court ne dépend que de libc, libgcc et ne nécessite aucun fichier d'en-tête. Si votre code nécessite d'autres bibliothèques et fichiers d'en-tête, vous devez les copier de la cible vers l'hôte. 


Update Lisez cette question si vous vous interrogez sur libgcc.

2
robor78