La route jusqu'à présent
Il y a un an, Chrome a annoncé la prise en charge initiale pour le débogage natif de WebAssembly dans les outils pour les développeurs Chrome.
Nous avons présenté la prise en charge de la progression de base et évoqué les opportunités offertes par l'utilisation d'informations DWARF au lieu de cartes sources à l'avenir :
- Résoudre les noms de variables
- Types d'impression élégante
- Évaluer des expressions dans les langues sources
- ... et bien plus !
Aujourd'hui, nous sommes ravis de présenter les fonctionnalités promises et les progrès réalisés par les équipes Emscripten et Chrome DevTools au cours de cette année, en particulier pour les applications C et C++.
Avant de commencer, veuillez noter qu'il s'agit encore d'une version bêta de la nouvelle interface, vous devez utiliser la dernière version de tous les outils à vos propres risques et, si vous rencontrez des problèmes, veuillez les signaler à https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.
Commençons par le même exemple C simple que la dernière fois:
#include <stdlib.h>
void assert_less(int x, int y) {
if (x >= y) {
abort();
}
}
int main() {
assert_less(10, 20);
assert_less(30, 20);
}
Pour le compiler, nous utilisons la dernière version d'Emscripten et transmettons un indicateur -g
, comme dans le post d'origine, pour inclure des informations de débogage :
emcc -g temp.c -o temp.html
Nous pouvons maintenant diffuser la page générée à partir d'un serveur HTTP localhost (par exemple, avec serve) et l'ouvrir dans la dernière version de Chrome Canary.
Cette fois, nous aurons également besoin d'une extension d'assistance qui s'intègre aux outils de développement Chrome et l'aide à comprendre toutes les informations de débogage encodées dans le fichier WebAssembly. Veuillez l'installer en accédant à ce lien : goo.gle/wasm-debugging-extension.
Vous devez également activer le débogage WebAssembly dans les outils de développement Tests : Ouvrez les outils pour les développeurs Chrome, cliquez sur l'icône en forme de roue dentée ⚙ en haut à droite du volet des outils pour les développeurs, accédez au panneau Tests et cochez WebAssembly Debugging: Enable DWARF support (Débogage WebAssembly : activer la prise en charge de DWARF).
Lorsque vous fermez Settings (Paramètres), les outils de développement vous suggèrent de les recharger pour appliquer les paramètres. C'est ce que nous allons faire. C'est tout pour cette session ponctuelle configuration.
Nous pouvons maintenant revenir au panneau Sources, activer Mettre en pause en cas d'exception (icône ⏸), puis cocher Mettre en pause en cas d'exception détectée et actualiser la page. Les outils de développement devraient être suspendus sur une exception :
Par défaut, il s'arrête sur un code de liaison généré par Emscripten, mais à droite, vous pouvez voir une vue Call Stack (Pile d'appels) représentant la trace de la pile de l'erreur et accéder à la ligne C d'origine qui a appelé abort
:
Maintenant, si vous regardez dans la vue Scope, vous pouvez voir les noms d'origine
et les valeurs des variables dans le code C/C++,
ce que signifient les noms déchiffrés comme $localN
et comment ils sont liés au
le code source que vous avez écrit.
Cela s'applique non seulement aux valeurs primitives telles que les entiers, mais aussi aux valeurs comme les structures, les classes, les tableaux, etc.
Compatibilité avec les types enrichis
Prenons un exemple plus complexe pour illustrer ces cas de figure. Cette fois, nous allons dessiner un fractal de Mandelbrot avec le code C++ suivant :
#include <SDL2/SDL.h>
#include <complex>
int main() {
// Init SDL.
int width = 600, height = 600;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window;
SDL_Renderer* renderer;
SDL_CreateWindowAndRenderer(width, height, SDL_WINDOW_OPENGL, &window,
&renderer);
// Generate a palette with random colors.
enum { MAX_ITER_COUNT = 256 };
SDL_Color palette[MAX_ITER_COUNT];
srand(time(0));
for (int i = 0; i < MAX_ITER_COUNT; ++i) {
palette[i] = {
.r = (uint8_t)rand(),
.g = (uint8_t)rand(),
.b = (uint8_t)rand(),
.a = 255,
};
}
// Calculate and draw the Mandelbrot set.
std::complex<double> center(0.5, 0.5);
double scale = 4.0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
std::complex<double> point((double)x / width, (double)y / height);
std::complex<double> c = (point - center) * scale;
std::complex<double> z(0, 0);
int i = 0;
for (; i < MAX_ITER_COUNT - 1; i++) {
z = z * z + c;
if (abs(z) > 2.0)
break;
}
SDL_Color color = palette[i];
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
SDL_RenderDrawPoint(renderer, x, y);
}
}
// Render everything we've drawn to the canvas.
SDL_RenderPresent(renderer);
// SDL_Quit();
}
Vous pouvez constater que cette application est encore assez petite. Il s'agit d'un seul fichier contenant 50 lignes de code. Toutefois, cette fois, j'utilise également des API externes, comme la bibliothèque SDL pour les graphiques, ainsi que les nombres complexes de la bibliothèque standard C++.
Je vais la compiler avec le même indicateur -g
que ci-dessus pour inclure
informations de débogage. Je demande aussi à Emscripten de fournir le fichier SDL2
bibliothèque et autorisent une mémoire de taille arbitraire:
emcc -g mandelbrot.cc -o mandelbrot.html \ -s USE_SDL=2 \ -s ALLOW_MEMORY_GROWTH=1
Lorsque j'accède à la page générée dans le navigateur, je vois avec des couleurs aléatoires:
Lorsque j'ouvre DevTools, je peux à nouveau voir le fichier C++ d'origine. Cette fois, cependant, il n'y a pas d'erreur dans le code (ouf !). Nous allons donc définir un point d'arrêt au début de notre code.
Lorsque nous actualisons à nouveau la page, le débogueur se met en pause dans notre source C++ :
Nous pouvons déjà voir toutes nos variables à droite, mais seules width
et height
sont initialisées pour le moment. Il n'y a donc pas grand-chose à inspecter.
Définissons un autre point d'arrêt dans notre boucle principale Mandelbrot, puis reprenons l'exécution pour avancer un peu.
À ce stade, notre palette
a été rempli de couleurs aléatoires. Nous pouvons développer le tableau lui-même, ainsi que les structures SDL_Color
individuelles, et inspecter leurs composants pour vérifier que tout est correct (par exemple, que le canal "alpha" est toujours défini sur une opacité complète). De même, nous pouvons développer et vérifier les parties réelle et imaginaire du nombre complexe stocké dans la variable center
.
Si vous souhaitez accéder à une propriété profondément imbriquée qui est autrement difficile à atteindre via la vue Champ d'application, vous pouvez également utiliser l'évaluation de la console. Notez toutefois que les expressions C++ plus complexes ne sont pas encore prises en charge.
Reprenons l'exécution plusieurs fois pour voir comment la x
interne est
ou en consultant à nouveau la vue Portée, en ajoutant
le nom de la variable à la liste de surveillance, en l'évaluant dans la console ou en
en pointant sur la variable dans le code source:
À partir de là, nous pouvons entrer ou passer les instructions C++ et observer comment d'autres variables changent également:
Tout fonctionne parfaitement lorsqu'une information de débogage est disponible, mais que se passe-t-il si nous voulons déboguer un code qui n'a pas été compilé avec les options de débogage ?
Débogage WebAssembly brut
Par exemple, nous avons demandé à Emscripten de nous fournir une bibliothèque SDL précompilée au lieu de la compiler nous-mêmes à partir de la source. Par conséquent, le débogueur ne peut pas trouver les sources associées, du moins pour le moment.
Revenons à l'étape suivante pour accéder à SDL_RenderDrawColor
:
Nous revenons à l'expérience de débogage WebAssembly brute.
Cela semble un peu effrayant, et la plupart des développeurs Web à résoudre, mais il peut arriver que vous souhaitiez déboguer est créée sans informations de débogage, que ce soit parce qu'il s'agit d'une bibliothèque tierce sur laquelle vous n'avez aucun contrôle, ou parce que rencontrer l’un de ces bugs qui ne se produit qu’en production.
Pour vous aider dans ces cas, nous avons également apporté des améliorations à l'expérience de débogage de base.
Tout d'abord, si vous avez déjà utilisé le débogage WebAssembly brut, vous remarquerez peut-être que l'intégralité du désassemblage est désormais affichée dans un seul fichier. Vous n'avez plus à deviner à quelle fonction une entrée wasm-53834e3e/
wasm-53834e3e-7
Sources peut correspondre.
Nouveau schéma de génération de nom
Nous avons également amélioré les noms dans la vue de démontage. Auparavant, vous ne voyiez que des indices numériques ou, dans le cas des fonctions, aucun nom du tout.
Nous générons maintenant des noms de la même manière
que d'autres outils de démontage,
à l'aide des indications de la section des noms WebAssembly
les chemins d'importation/exportation et, enfin, si tout le reste échoue, générer
en fonction du type et de l'index de l'élément, par exemple $func123
. Vous pouvez
comme le montre la capture d'écran ci-dessus, cela permet déjà d'obtenir
des traces de pile et un démontage plus lisibles.
Lorsqu'aucune information de type n'est disponible, il peut être difficile d'inspecter Toutes les valeurs autres que les primitives. Par exemple, les pointeurs s'affichent. comme des entiers normaux, sans aucun moyen de savoir ce qui est stocké derrière eux dans mémoire.
Inspection de la mémoire
Auparavant, vous ne pouviez développer que l'objet de mémoire WebAssembly, représenté par env.memory
dans la vue Scope (Champ d'application) pour rechercher
octets individuels. Cela fonctionnait dans certains scénarios triviaux, mais n'était pas particulièrement pratique à développer et ne permettait pas de réinterpréter les données dans des formats autres que les valeurs d'octet. Nous avons ajouté une nouvelle
fonctionnalité pour vous aider
avec ceci aussi: un inspecteur de mémoire linéaire.
Si vous effectuez un clic droit sur env.memory
, une nouvelle option appelée Inspecter la mémoire devrait s'afficher :
Lorsque vous cliquez dessus, un outil d'inspection de mémoire s'affiche. que vous pouvez inspecter la mémoire WebAssembly dans les vues hexadécimales et ASCII, accéder à des adresses spécifiques, et interpréter les données différents formats:
Scénarios avancés et mises en garde
Profiler du code WebAssembly
Lorsque vous ouvrez les outils de développement, le code WebAssembly est "hiérarchisé" à un
version non optimisée pour activer le débogage. Cette version est beaucoup plus lente, ce qui signifie que vous ne pouvez pas vous fier à console.time
, performance.now
et à d'autres méthodes de mesure de la vitesse de votre code lorsque DevTools est ouvert, car les chiffres que vous obtenez ne représentent pas du tout les performances réelles.
Utilisez plutôt le panneau "Performances" de DevTools, qui exécute le code à pleine vitesse et vous fournit une répartition détaillée du temps passé dans différentes fonctions :
Vous pouvez également exécuter votre application avec les outils pour les développeurs fermés, puis les ouvrir une fois terminé pour inspecter la console.
Nous améliorerons les scénarios de profilage à l'avenir, mais pour le moment, il s'agit mise en garde à prendre en compte. Pour en savoir plus sur les scénarios de hiérarchisation WebAssembly, consultez notre documentation sur le pipeline de compilation WebAssembly.
Compiler et déboguer sur différentes machines (y compris Docker / hôte)
Lorsque vous effectuez une compilation dans un Docker, une machine virtuelle ou sur un serveur de compilation distant, vous rencontrerez probablement des situations où les chemins d'accès aux fichiers sources utilisés lors de la compilation ne correspondent pas aux chemins de votre propre système de fichiers où les outils de développement Chrome s'exécutent. Dans ce cas, les fichiers apparaissent Sources, mais son chargement échoue.
Pour résoudre ce problème, nous avons implémenté une fonctionnalité de mappage de chemin d'accès dans les options d'extension C/C++. Vous pouvez l'utiliser pour remapper des chemins arbitraires et pour aider les outils de développement à localiser les sources.
Par exemple, si le projet de votre machine hôte se trouve sous un chemin d'accès
C:\src\my_project
, mais a été créée dans un conteneur Docker où
ce chemin était représenté par /mnt/c/src/my_project
, vous pouvez le remapper
lors du débogage en spécifiant ces chemins d'accès en tant que préfixes:
Le premier préfixe correspondant "gagne". Si vous connaissez d'autres débogueurs C++, cette option est semblable à la commande set substitute-path
dans GDB ou à un paramètre target.source-map
dans LLDB.
Déboguer des builds optimisés
Comme pour les autres langages, le débogage fonctionne mieux si les optimisations sont désactivées. Les optimisations peuvent intégrer des fonctions les unes aux autres, réorganiser le code ou supprimer complètement des parties du code. Tout cela peut prêter à confusion pour le débogueur et, par conséquent, pour vous en tant qu'utilisateur.
Si vous n'êtes pas gêné par une expérience de débogage plus limitée et que vous souhaitez toujours déboguer un build optimisé, la plupart des optimisations fonctionneront comme prévu, à l'exception de l'intégration de fonction. Nous prévoyons de résoudre les problèmes restants à l'avenir, mais pour l'instant, veuillez utiliser -fno-inline
pour le désactiver lors de la compilation avec des optimisations de niveau -O
, par exemple :
emcc -g temp.c -o temp.html \ -O3 -fno-inline
Séparer les informations de débogage
Les informations de débogage conservent de nombreux détails sur votre code, les types définis, les variables, les fonctions, les portées et les emplacements, tout ce qui peut être utile au débogueur. Il est donc souvent plus volumineux que le code lui-même.
Pour accélérer le chargement et la compilation du module WebAssembly, vous pouvez
diviser ces informations de débogage dans un composant WebAssembly distinct
. Pour le faire dans Emscripten, transmettez un indicateur -gseparate-dwarf=…
avec
le nom de fichier souhaité:
emcc -g temp.c -o temp.html \ -gseparate-dwarf=temp.debug.wasm
Dans ce cas, l'application principale ne stocke qu'un nom de fichier temp.debug.wasm
, et l'extension d'assistance peut le localiser et le charger lorsque vous ouvrez DevTools.
Associée aux optimisations décrites ci-dessus, cette fonctionnalité peut même les utiliser pour envoyer des versions de production presque optimisées application, puis les déboguer plus tard avec un fichier secondaire local. Dans ce cas, nous devons également remplacer l'URL stockée pour que l'extension Recherchez le fichier secondaire, par exemple:
emcc -g temp.c -o temp.html \ -O3 -fno-inline \ -gseparate-dwarf=temp.debug.wasm \ -s SEPARATE_DWARF_URL=file://[local path to temp.debug.wasm]
À suivre...
Ouf, c'est beaucoup de nouvelles fonctionnalités !
Avec toutes ces nouvelles intégrations, les outils pour les développeurs Chrome deviennent un débogueur viable et puissant, non seulement pour JavaScript, mais aussi pour les applications C et C++. Il est ainsi plus facile que jamais de prendre des applications, conçues dans diverses technologies, et de les transférer vers un Web partagé et multiplate-forme.
Cependant, notre voyage n'est pas encore terminé. Voici quelques-unes des choses sur lesquelles nous allons travailler à l'avenir :
- Nettoyer les ébauches de l'expérience de débogage.
- Ajout de la prise en charge des formateurs de type personnalisés.
- Amélioration du profilage pour les applications WebAssembly.
- Ajout de la prise en charge de la couverture de code pour faciliter la recherche code inutilisé.
- Amélioration de la compatibilité avec les expressions dans l'évaluation de la console.
- Prise en charge de plus de langues.
- Et bien d'autres…
En attendant, veuillez nous aider en essayant la version bêta actuelle sur votre propre code et en signalant les problèmes détectés sur https://issues.chromium.org/issues/new?noWizard=true&template=0&component=1456350.
Télécharger les canaux de prévisualisation
Vous pouvez utiliser la version Canary, Dev ou Bêta de Chrome comme navigateur de développement par défaut. Ces canaux de prévisualisation vous donnent accès aux dernières fonctionnalités de DevTools, vous permettent de tester les API de plates-formes Web de pointe et vous aident à détecter les problèmes sur votre site avant vos utilisateurs.
Contacter l'équipe des outils pour les développeurs Chrome
Utilisez les options suivantes pour discuter des nouvelles fonctionnalités, des mises à jour ou de tout autre élément lié aux outils de développement.
- Envoyez-nous vos commentaires et vos demandes de fonctionnalités sur crbug.com.
- Signalez un problème dans les outils de développement à l'aide du bouton . Autres options > Aide > Signalez un problème dans les outils de développement.
- Envoyez un tweet à @ChromeDevTools.
- Laissez vos commentaires sur les vidéos YouTube sur les nouveautés dans les outils de développement ou sur les vidéos YouTube de conseils sur les outils de développement.