web-dev-qa-db-fra.com

Comment configurer CMake pour une compilation croisée avec clang pour ARM incorporé sous Windows?

J'essaie de générer des makefiles Ninja pour compiler un projet C++ avec Clang pour un CPU ARM Cortex A5. J'ai créé un fichier de chaîne d'outils pour CMake mais il semble qu'il y ait une erreur ou quelque chose qui manque que je ne trouve pas. Lorsque j'appelle CMake avec le fichier de la chaîne d'outils ci-dessous, j'obtiens l'erreur suivante.

Commande CMake:

cmake -DCMAKE_TOOLCHAIN_FILE = "..\Src\Build\Toolchain-clang-arm.cmake" -GNinja ..\Src \

Sortie:

- L'identification du compilateur C est Clang 7.0.0 CMake Error à C: /Users/user/scoop/apps/cmake/3.13.4/share/cmake-3.13/Modules/CMakeDetermineCompilerId.cmake: 802 (message): The Clang outil de compilation

"C:/Program Files/LLVM/bin/clang.exe"

cible le MSVC ABI mais possède une interface de ligne de commande de type GNU. Ce n'est pas pris en charge. Utilisez plutôt `` clang-cl '', par ex. en définissant "CC = clang-cl" dans l'environnement. En outre, utilisez l'environnement de ligne de commande MSVC. Pile d'appels (appel le plus récent en premier):
C: /Users/user/scoop/apps/cmake/3.13.4/share/cmake-3.13/Modules/CMakeDetermineCCompiler.cmake: 113 (CMAKE_DIAGNOSE_UNSUPPORTED_CLANG) CMakeLists.txt: 2 (PROJET)

- Configuration incomplète, des erreurs se sont produites!

Fichier de chaîne d'outils CMake (Toolchain-clang-arm.cmake):

set(CMAKE_CROSSCOMPILING TRUE)
SET(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR arm)

# Clang target triple
SET(TARGET armv7-none-eabi)

# specify the cross compiler
SET(CMAKE_C_COMPILER_TARGET ${TARGET})
SET(CMAKE_C_COMPILER clang)
SET(CMAKE_CXX_COMPILER_TARGET ${TARGET})
SET(CMAKE_CXX_COMPILER clang++)
SET(CMAKE_ASM_COMPILER_TARGET ${TARGET})
SET(CMAKE_ASM_COMPILER clang)

# C/C++ toolchain
SET(TOOLCHAIN "C:/Program Files (x86)/GNU Tools ARM Embedded/7 2018-q2-update")
SET(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN ${TOOLCHAIN})
SET(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN ${TOOLCHAIN})

# specify compiler flags
SET(Arch_FLAGS "-target armv7-none-eabi -mcpu=cortex-a5")
SET(CMAKE_C_FLAGS "-Wall -Wextra ${Arch_FLAGS}" CACHE STRING "Common flags for C compiler")
SET(CMAKE_CXX_FLAGS "-Wall -Wextra -std=c++11 -fno-exceptions -fno-threadsafe-statics ${Arch_FLAGS}" CACHE STRING "Common flags for C++ compiler")

J'ai utilisé la documentation CMake et Clang et certains lien aléatoire sur le net pour créer le fichier de la chaîne d'outils. L'ensemble du projet se compile très bien avec ARM GCC pour Windows, donc le fichier de la chaîne d'outils semble être la seule pièce manquante du puzzle.

[~ # ~] modifier [~ # ~]

J'ai essayé de contourner les vérifications du compilateur CMake en forçant le compilateur. Je remplace les lignes par SET (CMAKE_C_COMPILER clang), SET (CMAKE_CXX_COMPILER clang ++) etc. avec:

CMAKE_FORCE_C_COMPILER(clang Clang)
CMAKE_FORCE_CXX_COMPILER(clang++ Clang)

L'erreur reste la même.

[~ # ~] modifier [~ # ~]

Je peux compiler avec succès un exemple de bonjour avec clang -target arm-none-eabi. Le problème semble donc être dans CMake. J'ai créé un bug dans le tracker de problème CMake.

Versions de l'outil:

  • clang version 7.0.0 (tags/RELEASE_700/final)
  • cmake version 3.13.4
7
S. Marti

Ma question a été répondue par le réponse à mon rapport de bug, mais j'ajoute la réponse ici pour avoir toutes les informations en un seul endroit pour référence future.

En bref: CMake ne prend actuellement pas en charge l'utilisation de l'interface de ligne de commande clang/clang ++ si vous installez Clang à partir de llvm.org . Si vous souhaitez utiliser l'interface clang/clang ++ (qui est nécessaire pour la compilation croisée pour ARM), vous devez installer Clang via msys2 .

En détail

Clang sous Windows possède deux interfaces de ligne de commande différentes:

  • clang/clang ++ l'interface par défaut qui tente d'être compatible avec les GCC gcc/g ++ et cible le GNU ABI
  • clang-cl qui tente d'être compatible avec le compilateur Visual C++ de Microsofts cl.exe et cible le MSVC ABI

Pour effectuer une compilation croisée pour ARM vous avez besoin de l'interface clang/clang ++. Le problème est que CMake prend en charge différentes interfaces en fonction de la façon dont vous avez installé Clang (voir bug dans le suivi des problèmes CMake pour plus de détails):

  • Si vous installez Clang à partir de llvm.org CMake ne prend en charge que l'interface clang-cl.
  • Si vous installez Clang via msys2 CMake prend en charge l'interface clang/clang ++.

Voici donc ce que j'ai fait:

  1. Installer msys2
  2. Installez Clang et CMake avec pacman . Il existe deux packages clang dans msys2, une version mingw32 et une version mingw64. J'ai utilisé le package mingw64 (mingw-w64-x86_64-clang).
  3. Lancez le shell mingw64 et exécutez CMake et créez à partir de là.

Fichier de chaîne d'outils

Il y avait deux problèmes avec mon fichier de chaîne d'outils d'origine qui m'ont pris beaucoup de temps à résoudre. J'espère donc que cela fera gagner du temps aux autres:

  1. Le cible triple (par exemple arm-none-eabi) doit correspondre au préfixe des binutils GCC exactement. Le préfixe de mes binutils était arm-none-eabi (par exemple arm-none-eabi-ar), j'ai donc dû changer le triple cible en conséquence.
  2. CMAKE_TRY_COMPILE_TARGET_TYPE doit être changé en STATIC_LIBRARY afin d'empêcher CMake d'exécuter l'éditeur de liens pendant la vérification de la compilation.

Voici le fichier de chaîne d'outils final que j'ai utilisé (vous pouvez également trouver un bon exemple de fichier de chaîne d'outils dans ce dépôt GitHub ):

cmake_minimum_required(VERSION 3.13)

set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR ARM)

if(DEFINED ENV{GCC_ARM_TOOLCHAIN})
    set(GCC_ARM_TOOLCHAIN $ENV{GCC_ARM_TOOLCHAIN})
else()
    set(GCC_ARM_TOOLCHAIN "C:/Users/user/tools/gcc-arm-none-eabi-7-2018-q2-update-win32")
endif()

LIST(APPEND CMAKE_PROGRAM_PATH ${GCC_ARM_TOOLCHAIN})

# Specify the cross compiler
# The target triple needs to match the prefix of the binutils exactly
# (e.g. CMake looks for arm-none-eabi-ar)
set(CLANG_TARGET_TRIPLE arm-none-eabi)
set(GCC_ARM_TOOLCHAIN_PREFIX ${CLANG_CLANG_TARGET_TRIPLE})
set(CMAKE_C_COMPILER clang)
set(CMAKE_C_COMPILER_TARGET ${CLANG_TARGET_TRIPLE})
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_CXX_COMPILER_TARGET ${CLANG_TARGET_TRIPLE})
set(CMAKE_ASM_COMPILER clang)
set(CMAKE_ASM_COMPILER_TARGET ${CLANG_TARGET_TRIPLE})

# Don't run the linker on compiler check
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

# Specify compiler flags
set(Arch_FLAGS "-mcpu=cortex-a5 -mthumb -mfpu=neon-vfpv4 -mfloat-abi=hard -mno-unaligned-access")
set(CMAKE_C_FLAGS "-Wall ${Arch_FLAGS}" CACHE STRING "Common flags for C compiler")
set(CMAKE_CXX_FLAGS "-Wall -std=c++17 -fno-exceptions -fno-rtti -fno-threadsafe-statics ${Arch_FLAGS}" CACHE STRING "Common flags for C++ compiler")
set(CMAKE_ASM_FLAGS "-Wall ${Arch_FLAGS} -x assembler-with-cpp" CACHE STRING "Common flags for assembler")
set(CMAKE_EXE_LINKER_FLAGS "-nostartfiles -Wl,-Map,kernel.map,--gc-sections -Fuse-linker-plugin -Wl,--use-blx --specs=nano.specs --specs=nosys.specs" CACHE STRING "")

# C/C++ toolchain
set(GCC_ARM_SYSROOT "${GCC_ARM_TOOLCHAIN}/${GCC_ARM_TOOLCHAIN_PREFIX}")
# set(CMAKE_SYSROOT ${GCC_ARM_SYSROOT})
set(CMAKE_FIND_ROOT_PATH ${GCC_ARM_SYSROOT})

# Search for programs in the build Host directories
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# For libraries and headers in the target directories
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
2
S. Marti

Voici une réponse alternative qui utilise CMake pour effectuer une compilation croisée pour ARM en utilisant la chaîne d'outils GCC, plutôt que clang, et utilise également une ancienne marque plutôt que Ninja. Je sais que cela ne répond pas directement à la question, mais c'est une alternative très raisonnable pour ARM intégré, et la plupart des chaînes d'outils de fournisseurs basées sur Eclipse que nous utilisons maintenant sont basées sur GCC plutôt que sur LLVM/clang.

Installez d'abord la dernière chaîne d'outils "GNU MCU Eclipse ARM Embedded GCC" de https://github.com/gnu-mcu-Eclipse/arm-none-eabi-gcc/releases (REMARQUE: pas d'installation, décompressez simplement où vous le voulez).

Ensuite, installez la dernière version de MSYS2/MinGW à l'aide du programme d'installation disponible sur https://www.msys2.org/ .

Pour une raison quelconque, l'installation par défaut de MSYS2 n'inclut pas make. Ainsi, après avoir utilisé pacman pour mettre à jour les packages par défaut conformément aux instructions d'installation, exécutez 'pacman -S make' pour installer make.

Il existe une version cmake disponible dans MSYS2. Cependant, il n'inclut pas les générateurs pour MSYS ou MinGW (aucune idée pourquoi), et aussi (ou à cause de) semble avoir des problèmes pour trouver la chaîne d'outils GCC externe, même lorsque les chemins d'accès complets sont explicitement fournis sur la ligne de commande ou dans un fichier de chaîne d'outils . Ainsi, cette solution utilise la version Windows native de CMake, disponible sur https://cmake.org/download/ , et NON la version MSYS2 de cmake.

Par défaut, le shell MSYS n'hérite pas de l'environnement Windows, donc le CMake Windows natif ne sera pas sur le chemin du shell MSYS. La solution simple consiste à spécifier le chemin d'accès complet à cmake sur la ligne de commande. Dans mon cas, j'ai la chaîne d'outils du compilateur croisé GCC sur C:/GNU MCU Eclipse/ARM Embedded GCC/8.2.1-1.4-20190214-0604. Ainsi, une commande complète pour cmake ressemble à ceci.

/c/Program\ Files/CMake/bin/cmake.exe -DCMAKE_BUILD_TYPE=Debug -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm-none-eabi.cmake "-DTOOLCHAIN_PREFIX=C:/GNU MCU Eclipse/ARM Embedded GCC/8.2.1-1.4-20190214-0604" -G "MSYS Makefiles" ../

Ici, la commande est exécutée à partir d'un répertoire de construction situé un niveau plus bas que la racine du projet, et un répertoire frère cmake contient le fichier de chaîne d'outils spécifié. Remarque, les barres obliques inverses sont nécessaires pour échapper à tous les espaces dans le chemin d'accès à cmake.exe, mais ne sont PAS utilisées dans les chemins d'accès cités passés en argument à cmake.

Vous pouvez également exécuter cmake et faire directement à partir d'une ancienne ligne de commande Windows (cmd.exe) tant que les répertoires bin cmake et msys sur le chemin Windows. Dans ce cas, il n'est pas nécessaire de spécifier le chemin complet vers cmake. Aucun succès de PowerShell, cependant.

1
AngCaruso