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
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
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.
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.
CC=gcc CXX=g++ cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release ../llvm/
--target=aarch64-linux-gnu
-Fuse-ld=lld
clang --target=aarch64-linux-gnu -v main.cpp -o main -Fuse-ld=lld
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
ld.lld: erreur: impossible d'ouvrir crt1.o: Aucun fichier ou répertoire de ce type
clang --target=aarch64-linux-gnu -v main.cpp -o main -Fuse-ld=lld -L./libs
ld.lld: erreur: symbole non défini: __libc_csu_fini
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.
-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.