Trucs et astuces Windows

ROS 2 prend en charge Windows 10 en tant que plate-forme de niveau 1, ce qui signifie que tout le code qui entre dans le noyau ROS 2 doit prendre en charge Windows. Pour ceux qui sont habitués au développement traditionnel sur Linux ou d’autres systèmes de type Unix, le développement sur Windows peut être un peu difficile. Ce document vise à présenter certaines de ces différences.

Longueur maximale du chemin

Par défaut, Windows a une longueur de chemin maximale de 260 caractères. En pratique, 4 de ces caractères sont toujours utilisés par la lettre de lecteur, les deux-points, la barre oblique inverse initiale et le caractère NULL final. Cela signifie que seuls 256 caractères sont disponibles pour la somme de toutes les parties du chemin. Cela a deux conséquences pratiques pour ROS 2 :

  • Certains des noms de chemin interne de ROS 2 sont assez longs. Pour cette raison, nous recommandons toujours d’utiliser un nom de chemin court pour la racine de votre répertoire ROS 2, comme C:\dev.

  • Lors de la construction de ROS 2 à partir de la source, le mode de construction isolé par défaut de colcon peut générer des noms de chemin très longs. Pour éviter ces noms de chemin très longs, utilisez --merge-install lors de la construction sous Windows.

Remarque : Il est possible de modifier Windows pour avoir des longueurs de chemin maximales beaucoup plus longues. Voir cet article pour plus d’informations.

Visibilité des symboles

Le compilateur Microsoft Visual C++ (MSVC) expose les symboles d’une bibliothèque de liens dynamiques (DLL) uniquement s’ils sont explicitement exportés. Les compilateurs clang et gcc ont une option pour faire la même chose, mais elle est désactivée par défaut. Par conséquent, lorsqu’une bibliothèque précédemment construite sur Linux est construite sur Windows, d’autres bibliothèques peuvent être incapables de résoudre les symboles externes. Vous trouverez ci-dessous des exemples de messages d’erreur courants qui peuvent être provoqués par des symboles non exposés :

error C2448: '__attribute__': function-style initializer appears to be a function definition
'visibility': identifier not found
CMake Error at C:/ws_ros2/install/random_numbers/share/random_numbers/cmake/ament_cmake_export_libraries-extras.cmake:48 (message):
   Package 'random_numbers' exports the library 'random_numbers' which
   couldn't be found

Symbol Visibility also impacts binary loading. If you are finding that a composible node does not run or a Qt Visualizer isn’t working, it may be that the hosting process can not find an expected symbol export from the binary. To diagnose this on Windows, the Windows developer tools includes a program called Gflags to enable various options. One of those options is called Loader Snaps which enables you to detect load failures while debugging. Please visit the Microsoft Documentation for more information on Gflags and Loaders snaps.

Deux solutions pour exporter des symboles sur Windows sont les en-têtes de contrôle de visibilité et la propriété WINDOWS_EXPORT_ALL_SYMBOLS. Microsoft recommande aux développeurs ROS d’utiliser les en-têtes de contrôle de visibilité pour contrôler l’exportation des symboles à partir d’un binaire. Les en-têtes de contrôle de visibilité offrent plus de contrôle sur la macro d’exportation de symboles et offrent d’autres avantages, notamment une taille binaire plus petite et des temps de liaison réduits.

En-têtes de contrôle de visibilité

Le but des en-têtes Visibility Control Headers est de définir une macro pour chaque bibliothèque partagée qui déclare correctement les symboles comme dllimport ou dllexport. Ceci est décidé selon que la bibliothèque est consommée ou construite elle-même. La logique de la macro prend également en compte le compilateur et inclut une logique pour sélectionner la syntaxe appropriée. La documentation de visibilité GCC comprend des instructions étape par étape pour ajouter une visibilité de symbole explicite à une bibliothèque « produisant le code de la plus haute qualité avec les plus grandes réductions de taille binaire, de charge heures et heures de liaison ». Un en-tête nommé visibility_control.h peut être placé dans le dossier includes pour chaque bibliothèque, comme indiqué dans l’exemple ci-dessous. L’exemple ci-dessous montre comment un en-tête de contrôle de visibilité serait ajouté pour une bibliothèque my_lib avec une classe appelée example_class. Ajoutez un en-tête de visibilité au dossier d’inclusion de la bibliothèque. La logique de plaque de chaudière est utilisée avec le nom de bibliothèque utilisé dans la macro pour le rendre unique dans le projet. Dans une autre bibliothèque, MY_LIB serait remplacé par le nom de la bibliothèque.

#ifndef MY_LIB__VISIBILITY_CONTROL_H_
#define MY_LIB__VISIBILITY_CONTROL_H_
#if defined _WIN32 || defined __CYGWIN__
#ifdef __GNUC__
   #define MY_LIB_EXPORT __attribute__ ((dllexport))
   #define MY_LIB_IMPORT __attribute__ ((dllimport))
#else
   #define MY_LIB_EXPORT __declspec(dllexport)
   #define MY_LIB_IMPORT __declspec(dllimport)
#endif
#ifdef MY_LIB_BUILDING_LIBRARY
   #define MY_LIB_PUBLIC MY_LIB_EXPORT
#else
   #define MY_LIB_PUBLIC MY_LIB_IMPORT
#endif
#define MY_LIB_PUBLIC_TYPE MY_LIB_PUBLIC
#define MY_LIB_LOCAL
#else
 // Linux visibility settings
#define MY_LIB_PUBLIC_TYPE
#endif
#endif  // MY_LIB__VISIBILITY_CONTROL_H_

Pour un exemple complet de cet en-tête, voir rviz_rendering.

Pour utiliser la macro, ajoutez MY_LIB_PUBLIC avant les symboles qui doivent être visibles pour les bibliothèques externes. Par exemple:

Class MY_LIB_PUBLIC example_class {}

MY_LIB_PUBLIC void example_function (){}

Afin de construire votre bibliothèque avec des symboles correctement exportés, vous devrez ajouter ce qui suit à votre fichier CMakeLists.txt :

target_compile_definitions(${PROJECT_NAME}
  PRIVATE "MY_LIB_BUILDING_LIBRARY")

Propriété cible WINDOWS_EXPORT_ALL_SYMBOLS

CMake implémente la propriété WINDOWS_EXPORT_ALL_SYMBOLS sous Windows, qui entraîne l’exportation automatique des symboles de fonction. Vous trouverez plus de détails sur son fonctionnement dans la documentation WINDOWS_EXPORT_ALL_SYMBOLS CMake. La propriété peut être implémentée en ajoutant ce qui suit au fichier CMakeLists :

set_target_properties(${LIB_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)

S’il y a plus d’une bibliothèque dans un fichier CMakeLists, vous devrez appeler set_target_properties sur chacune d’elles séparément.

Notez qu’un binaire sous Windows ne peut exporter que 65 536 symboles. Si un binaire exporte plus que cela, vous obtiendrez une erreur et devrez utiliser les en-têtes visibilité_control. Il existe une exception à cette méthode dans le cas des symboles de données globales. Par exemple, un membre de données statique global comme celui ci-dessous.

class Example_class
{
public:
static const int Global_data_num;

Dans ces cas, dllimprot/dllexport doit être appliqué explicitement. Cela peut être fait en utilisant generate_export_header comme décrit dans l’article suivant : Create dlls on Windows without declspec() using new CMake export all feature.

Enfin, il est important que le fichier d’en-tête qui exporte les symboles soit inclus dans au moins un des fichiers .cpp du paquet afin que les macros soient développées et placées dans le binaire résultant. Sinon, les symboles ne seront toujours pas appelables.

Versions de débogage

Lors de la construction en mode débogage sous Windows, plusieurs choses très importantes changent. La première est que toutes les DLL obtiennent _d automatiquement ajouté au nom de la bibliothèque. Ainsi, si la bibliothèque s’appelle libfoo.dll, en mode Debug, ce sera libfoo_d.dll. L’éditeur de liens dynamique sous Windows sait également rechercher des bibliothèques de cette forme, il ne trouvera donc pas de bibliothèques sans le préfixe _d. De plus, Windows active un ensemble complet de vérifications au moment de la compilation et de l’exécution en mode débogage qui est beaucoup plus strict que les versions Release. Pour ces raisons, il est judicieux d’exécuter une version de débogage Windows et de tester sur de nombreuses demandes d’extraction.

Barre oblique contre barre oblique inverse

Sous Windows, le séparateur de chemin par défaut est une barre oblique inverse (\), qui diffère de la barre oblique (/) utilisée sous Linux et macOS. La plupart des API Windows peuvent traiter l’un ou l’autre comme séparateur de chemin, mais ce n’est pas universellement vrai. Par exemple, le shell cmd.exe ne peut effectuer de tabulation qu’en utilisant le caractère barre oblique inverse, pas la barre oblique. Pour une compatibilité maximale sous Windows, une barre oblique inverse doit toujours être utilisée comme séparateur de chemin sous Windows.

Correctif des packages du fournisseur

Lors de la vente d’un package dans ROS 2, il est souvent nécessaire d’appliquer un correctif pour corriger un bogue, ajouter une fonctionnalité, etc. La façon typique de le faire est de modifier l’appel ExternalProject_add pour ajouter un PATCH` `, en utilisant l'exécutable ``patch. Malheureusement, l’exécutable patch fourni par chocolatey nécessite un accès administrateur pour s’exécuter. La solution consiste à utiliser git apply-patch lors de l’application de correctifs à des projets externes.

git apply-patch a ses propres problèmes en ce sens qu’il ne fonctionne correctement que lorsqu’il est appliqué à un référentiel git. Pour cette raison, les projets externes doivent toujours utiliser la méthode GIT pour obtenir le projet, puis utiliser la PATCH_COMMAND pour invoquer git apply-patch.

Un exemple d’utilisation de tout ce qui précède ressemble à :

ExternalProject_Add(mylibrary-${version}
  GIT_REPOSITORY https://github.com/lib/mylibrary.git
  GIT_TAG ${version}
  GIT_CONFIG advice.detachedHead=false
  # Suppress git update due to https://gitlab.kitware.com/cmake/cmake/-/issues/16419
  # See https://github.com/ament/uncrustify_vendor/pull/22 for details
  UPDATE_COMMAND ""
  TIMEOUT 600
  CMAKE_ARGS
    -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}_install
    ${extra_cmake_args}
    -Wno-dev
  PATCH_COMMAND
    ${CMAKE_COMMAND} -E chdir <SOURCE_DIR> git apply -p1 --ignore-space-change --whitespace=nowarn ${CMAKE_CURRENT_SOURCE_DIR}/install-patch.diff
)

Minuteries lentes de Windows (lenteur en général)

Les logiciels fonctionnant sous Windows sont, en général, beaucoup plus lents que ceux fonctionnant sous Linux. Cela est dû à un certain nombre de facteurs, à partir de la tranche de temps par défaut (toutes les 20 ms, selon la documentation) , au nombre de processus antivirus et anti-malware en cours d’exécution, au nombre de processus d’arrière-plan en cours d’exécution. À cause de tout cela, les tests ne doivent jamais s’attendre à un timing serré sous Windows. Tous les tests doivent avoir des délais d’attente généreux et ne s’attendre qu’à ce que des événements se produisent éventuellement (cela empêchera également les tests d’être flakey sous Linux).

Coquilles

Il existe deux principaux shells de ligne de commande sous Windows : le vénérable cmd.exe et PowerShell.

cmd.exe est le shell de commande qui émule le plus l’ancien shell DOS, mais avec des capacités grandement améliorées. Il est entièrement basé sur du texte et ne comprend que les fichiers batch DOS/Windows.

PowerShell est le nouveau shell basé sur des objets que Microsoft recommande pour la plupart des nouvelles applications. Il comprend les fichiers ps1 pour la configuration.

ROS 2 prend en charge à la fois cmd.exe et PowerShell, donc toute modification (en particulier des choses comme ament ou colcon) doit être testée sur les deux.