Lecture des traces de pile (StackTraces)

Une erreur inattendue s'est produite.

Lorsque le code de votre robot rencontre une erreur inattendue, vous verrez ce message s’afficher dans certaines sorties de la console (Driver Station ou RioLog). Vous remarquerez probablement aussi que votre robot s’arrête brusquement, ou ne bouge peut-être jamais. Ces erreurs inattendues sont appelées exceptions non gérées.

Lorsqu’une exception non gérée se produit, cela signifie que votre code contient un ou plusieurs bogues qui doivent être corrigés.

Cet article explorera certains des outils et techniques impliqués dans la recherche et la correction de ces bogues.

Qu’est-ce qu’une «trace de pile»?

Le message une erreur inattendue s'est produite est un signal qu’une trace de pile a été imprimée.

In Java and C++, the call stack data structure is used to store information about which function or method is currently being executed.

Une trace de pile imprime des informations sur ce qui se trouvait sur cette pile lorsque l’exception non gérée s’est produite. Cela vous indique les lignes de code qui s’exécutaient juste avant que le problème ne se produise. Bien que cela ne vous indique pas toujours la cause principale exacte de votre problème, c’est généralement le meilleur endroit pour commencer à chercher.

Qu’est-ce qu’une «exception non gérée»?

Une erreur irrécupérable est une condition qui survient dans laquelle le processeur ne peut pas continuer à exécuter du code. Cela implique presque toujours que, même si le code a été compilé et a commencé à s’exécuter, il n’est plus logique que l’exécution se poursuive.

Dans presque tous les cas, la cause première d’une exception non gérée est un code qui n’est pas correctement implémenté. Cela n’implique presque jamais qu’un matériel a mal fonctionné.

Alors, comment puis-je résoudre mon problème ?

Lire la trace de la pile

Pour commencer, recherchez au-dessus de unexpected error has occurred la trace de la pile.

En Java, cela devrait ressembler à ceci :

Error at frc.robot.Robot.robotInit(Robot.java:24): Unhandled exception: java.lang.NullPointerException
         at frc.robot.Robot.robotInit(Robot.java:24)
         at edu.wpi.first.wpilibj.TimedRobot.startCompetition(TimedRobot.java:94)
         at edu.wpi.first.wpilibj.RobotBase.runRobot(RobotBase.java:335)
         at edu.wpi.first.wpilibj.RobotBase.lambda$startRobot$0(RobotBase.java:387)
         at java.base/java.lang.Thread.run(Thread.java:834)

Il y a quelques éléments importants à retenir ici :

  • Il y a eu une Erreur

  • L’erreur était due à une Exception non gérée (Unhandled Exception)

  • L’exception était une java.lang.NullPointerException

  • L’erreur s’est produite lors de l’exécution de la ligne 24 à l’intérieur de Robot.java

    • robotInit était le nom de la méthode en cours d’exécution lorsque l’erreur s’est produite.

  • robotInit est une fonction du package frc.robot.Robot (AKA, le code de votre équipe)

  • robotInit a été appelé à partir d’un certain nombre de fonctions du package edu.wpi.first.wpilibj (AKA, les bibliothèques WPILib)

La liste des lignes en retrait commençant par le mot at représente l’état de la pile au moment où l’erreur s’est produite. Chaque ligne représente une méthode, qui a été appelée par la méthode juste en dessous.

Par exemple, si l’erreur s’est produite profondément dans votre base de code, vous pourriez voir plus d’entrées sur la pile:

Error at frc.robot.Robot.buggyMethod(TooManyBugs.java:1138): Unhandled exception: java.lang.NullPointerException
         at frc.robot.Robot.buggyMethod(TooManyBugs.java:1138)
         at frc.robot.Robot.barInit(Bar.java:21)
         at frc.robot.Robot.fooInit(Foo.java:34)
         at frc.robot.Robot.robotInit(Robot.java:24)
         at edu.wpi.first.wpilibj.TimedRobot.startCompetition(TimedRobot.java:94)
         at edu.wpi.first.wpilibj.RobotBase.runRobot(RobotBase.java:335)
         at edu.wpi.first.wpilibj.RobotBase.lambda$startRobot$0(RobotBase.java:387)
         at java.base/java.lang.Thread.run(Thread.java:834)

Dans ce cas : robotInit appelé fooInit, qui à son tour appelé barInit, qui à son tour appelé buggyMethod. Ensuite, lors de l’exécution de buggyMethod, l”NullPointerException s’est produite.

Java produira généralement des traces de pile automatiquement lorsque les programmes rencontrent des problèmes. C++ nécessitera plus de fouilles pour extraire les mêmes informations. Habituellement, un débogueur en une seule étape devra être connecté au programme du robot en cours d’exécution.

Les traces de pile peuvent être trouvées dans l’onglet du débogueur de VS Code:

Emplacement de trace de la pile VS Code

Les traces de pile en C++ ressembleront généralement à ceci:

Trace de pile associée à une erreur liée à la valeur NULL

Il y a quelques éléments importants à retenir ici :

  • L’exécution du code est actuellement en pause.

  • La raison pour laquelle il s’est arrêté était un thread ayant une exception

  • L’erreur s’est produite lors de l’exécution de la ligne 20 à l’intérieur de Robot.cpp

    • RobotInit était le nom de la méthode en cours d’exécution lorsque l’erreur s’est produite.

  • RobotInit est une fonction dans l’espace de noms Robot :: (AKA, le code de votre équipe)

  • RobotInit a été appelé à partir d’un certain nombre de fonctions de l’espace de noms frc:: (AKA, les bibliothèques WPILib)

Cette fenêtre « call stack » représente l’état de la pile au moment où l’erreur s’est produite. Chaque ligne représente une méthode, qui a été appelée par la méthode juste en dessous.

Les exemples de cette page supposent que vous exécutez des exemples de code en simulation, avec le débogueur connecté et surveillant les erreurs inattendues. Des techniques similaires devraient s’appliquer lors de l’exécution sur un vrai robot.

Effectuer une analyse de code

Une fois que vous avez trouvé la trace de la pile et trouvé les lignes de code qui déclenchent l’exception non gérée, vous pouvez commencer le processus de détermination de la cause première.

Souvent, le simple fait de regarder dans (ou à proximité) l’emplacement problématique dans le code sera fructueux. Vous remarquerez peut-être des choses que vous avez oubliées ou des lignes qui ne correspondent pas à un exemple auquel vous faites référence.

Note

Les développeurs qui ont beaucoup d’expérience avec le code auront souvent plus de chance d’examiner le code que les nouveaux. C’est bon, ne vous découragez pas ! L’expérience viendra avec le temps.

Une stratégie clé pour analyser le code consiste à poser les questions suivantes :

  • When was the last time the code « worked » (I.e., didn’t have this particular error)?

  • Qu’est-ce qui a changé dans le code entre la dernière version de travail et maintenant?

Des tests fréquents et des modifications minutieuses du code contribuent à rendre cette stratégie particulière plus efficace.

Exécuter le débogueur en une seule étape

Parfois, il ne suffit pas de regarder le code pour détecter le problème. Le débogueur en une seule étape est une excellente option dans ce cas - il vous permet d’inspecter la série d’événements menant à l’exception non gérée.

Rechercher plus d’informations

Google is a phenomenal resource for understanding the root cause of errors. Searches involving the programming language and the name of the exception will often yield good results on more explanations for what the error means, how it comes about, and potential fixes.

Chercher de l’aide extérieure

Si tout le reste échoue, vous pouvez demander des conseils et de l’aide aux autres (en personne et en ligne). Lorsque vous travaillez avec des personnes qui ne connaissent pas votre base de code, il est très important de fournir les informations suivantes:

  • Accès à votre code source, (Ex: on github.com)

  • Le texte complet de l’erreur, y compris la trace de la pile complète.

Exemples et modèles courants

Il existe un certain nombre de problèmes courants qui entraînent des exceptions d’exécution.

Pointeurs nuls et références

C++ et Java ont tous deux le concept de « null » - ils l’utilisent pour indiquer quelque chose qui n’a pas encore été initialisé, et ne fait référence à rien de significatif.

La manipulation d’une référence « null » produira une erreur d’exécution.

Par exemple, considérons le code suivant:

19PWMSparkMax armMotorCtrl;
20
21@Override
22public void robotInit() {
23      armMotorCtrl.setInverted(true);
24}
17class Robot : public frc::TimedRobot {
18   public:
19      void RobotInit() override {
20         motorRef->SetInverted(false);
21      }
22
23   private:
24      frc::PWMVictorSPX m_armMotor{0};
25      frc::PWMVictorSPX* motorRef;
26};

Lors de l’exécution, vous verrez une sortie qui ressemble à ceci:

********** Robot program starting **********
Error at frc.robot.Robot.robotInit(Robot.java:23): Unhandled exception: java.lang.NullPointerException
        at frc.robot.Robot.robotInit(Robot.java:23)
        at edu.wpi.first.wpilibj.TimedRobot.startCompetition(TimedRobot.java:107)
        at edu.wpi.first.wpilibj.RobotBase.runRobot(RobotBase.java:373)
        at edu.wpi.first.wpilibj.RobotBase.startRobot(RobotBase.java:463)
        at frc.robot.Main.main(Main.java:23)

Warning at edu.wpi.first.wpilibj.RobotBase.runRobot(RobotBase.java:388): The robot program quit unexpectedly. This is usually due to a code error.
  The above stacktrace can help determine where the error occurred.
  See https://wpilib.org/stacktrace for more information.
Error at edu.wpi.first.wpilibj.RobotBase.runRobot(RobotBase.java:395): The startCompetition() method (or methods called by it) should have handled the exception above.

En lisant la trace de la pile, vous pouvez voir que le problème s’est produit à l’intérieur de la fonction robotInit(), à la ligne 23, et que l’exception impliquait « Null Pointer ».

En allant à la ligne 23, vous pouvez voir qu’il n’y a qu’une seule chose qui pourrait être nulle - armMotorCtrl. En regardant plus haut, vous pouvez voir que l’objet armMotorCtrl est déclaré, mais jamais instancié.

Alternativement, vous pouvez parcourir les lignes de code avec le débogueur en une seule étape et vous arrêter lorsque vous atteignez la ligne 23. L’inspection de l’objet armMotorCtrl à ce stade montrerait qu’il est nul.

Exception has occurred: W32/0xc0000005
Unhandled exception thrown: read access violation.
this->motorRef was nullptr.

Dans Simulation, cela apparaîtra dans une fenêtre de débogueur qui pointe vers la ligne 20 dans le code bogué ci-dessus.

Vous pouvez afficher la trace complète de la pile en cliquant sur l’onglet du débogueur dans VS Code:

Trace de pile associée à une erreur liée à la valeur NULL

L’erreur est spécifique - notre variable membre motorRef a été déclarée, mais n’a jamais été affectée à une valeur. Par conséquent, lorsque nous essayons de l’utiliser pour appeler une méthode à l’aide de l’opérateur ->, l’exception se produit.

L’exception indique que son type était nullptr.

Résoudre les problèmes d’objets nuls

En règle générale, vous voudrez vous assurer que chaque référence a été initialisée avant de l’utiliser. Dans ce cas, il manque une ligne de code pour instancier le armMotorCtrl avant d’appeler la méthode setInverted().

Une implémentation fonctionnelle pourrait ressembler à ceci:

19PWMSparkMax armMotorCtrl;
20
21@Override
22public void robotInit() {
23      armMotorCtrl = new PWMSparkMax(0);
24      armMotorCtrl.setInverted(true);
25}
17class Robot : public frc::TimedRobot {
18   public:
19      void RobotInit() override {
20         motorRef = &m_armMotor;
21         motorRef->SetInverted(false);
22      }
23
24   private:
25      frc::PWMVictorSPX m_armMotor{0};
26      frc::PWMVictorSPX* motorRef;
27};

Division par zéro

Il n’est généralement pas possible de diviser un nombre entier par zéro et d’attendre des résultats raisonnables. La plupart des processeurs (y compris le roboRIO) lèveront une exception non gérée.

Par exemple, considérons le code suivant:

18int armLengthRatio;
19int elbowToWrist_in = 39;
20int shoulderToElbow_in = 0; //TODO
21
22@Override
23public void robotInit() {
24   armLengthRatio = elbowToWrist_in / shoulderToElbow_in;
25}
17class Robot : public frc::TimedRobot {
18   public:
19   void RobotInit() override {
20      armLengthRatio = elbowToWrist_in / shoulderToElbow_in;
21   }
22
23   private:
24      int armLengthRatio;
25      int elbowToWrist_in = 39;
26      int shoulderToElbow_in = 0; //TODO
27
28};

Lors de l’exécution, vous verrez une sortie qui ressemble à ceci:

********** Robot program starting **********
Error at frc.robot.Robot.robotInit(Robot.java:24): Unhandled exception: java.lang.ArithmeticException: / by zero
        at frc.robot.Robot.robotInit(Robot.java:24)
        at edu.wpi.first.wpilibj.TimedRobot.startCompetition(TimedRobot.java:107)
        at edu.wpi.first.wpilibj.RobotBase.runRobot(RobotBase.java:373)
        at edu.wpi.first.wpilibj.RobotBase.startRobot(RobotBase.java:463)
        at frc.robot.Main.main(Main.java:23)

Warning at edu.wpi.first.wpilibj.RobotBase.runRobot(RobotBase.java:388): The robot program quit unexpectedly. This is usually due to a code error.
  The above stacktrace can help determine where the error occurred.
  See https://wpilib.org/stacktrace for more information.
Error at edu.wpi.first.wpilibj.RobotBase.runRobot(RobotBase.java:395): The startCompetition() method (or methods called by it) should have handled the exception above.

En regardant la trace de la pile, nous pouvons voir une exception java.lang.ArithmeticException: / by zero s’est produite à la ligne 24. Si vous regardez les deux variables qui sont utilisées à droite du `` =``, vous remarquerez peut-être que l’un d’entre eux a été initialisé à zéro. On dirait que quelqu’un a oublié de le mettre à jour ! De plus, la variable de valeur nulle est utilisée dans le dénominateur d’une opération de division. Par conséquent, l’erreur de division par zéro se produit.

Alternativement, en exécutant le débogueur en une seule étape et en vous arrêtant à la ligne 24, vous pouvez inspecter la valeur de toutes les variables pour découvrir que shoulderToElbow_in a une valeur de 0.

Exception has occurred: W32/0xc0000094
Unhandled exception at 0x00007FF71B223CD6 in frcUserProgram.exe: 0xC0000094: Integer division by zero.

Dans Simulation, cela apparaîtra dans une fenêtre de débogueur qui pointe vers la ligne 20 dans le code bogué ci-dessus.

Vous pouvez afficher la trace complète de la pile en cliquant sur l’onglet du débogueur dans VS Code:

Trace de pile associée à une erreur de division par zéro

En regardant le message, nous voyons que l’erreur est décrite comme Integer division by zero. Si vous regardez les deux variables qui sont utilisées à droite de l’opérateur = à la ligne 20, vous remarquerez peut-être que l’une d’entre elles a été initialisée à zéro. On dirait que quelqu’un a oublié de la mettre à jour! De plus, la variable de valeur nulle est utilisée dans le dénominateur d’une opération de division. Par conséquent, l’erreur de division par zéro se produit.

Notez que les messages d’erreur peuvent être légèrement différents sur le roboRIO ou sur un système d’exploitation autre que Windows.

Résoudre les problèmes de division par zéro

Divide By Zero issues can be fixed in a number of ways. It’s important to start by thinking about what a zero in the denominator of your calculation means. Is it plausible? Why did it happen in the particular case you saw?

Parfois, il vous suffit d’utiliser un nombre différent de 0.

Une implémentation fonctionnelle pourrait ressembler à ceci:

18int armLengthRatio;
19int elbowToWrist_in = 39;
20int shoulderToElbow_in = 3;
21
22@Override
23public void robotInit() {
24
25   armLengthRatio = elbowToWrist_in / shoulderToElbow_in;
26
27}
17class Robot : public frc::TimedRobot {
18   public:
19   void RobotInit() override {
20      armLengthRatio = elbowToWrist_in / shoulderToElbow_in;
21   }
22
23   private:
24      int armLengthRatio;
25      int elbowToWrist_in = 39;
26      int shoulderToElbow_in = 3
27
28};

Alternativement, si zéro est une valeur valide, l’ajout d’instructions if/else autour du calcul peut vous aider à définir un comportement alternatif pour éviter que le processeur effectue une division par zéro.

Enfin, changer les types de variables en float ou double peut vous aider à contourner le problème - les nombres à virgule flottante ont des valeurs spéciales comme NaN pour représenter les résultats d’une division par zéro opération. Cependant, vous devrez peut-être toujours gérer cela dans le code qui utilise la valeur de ce calcul.

Ressource HAL déjà allouée

A very common FRC-specific error occurs when the code attempts to put two hardware-related entities on the same HAL resource (usually, roboRIO IO pin).

Par exemple, considérons le code suivant:

19PWMSparkMax leftFrontMotor;
20PWMSparkMax leftRearMotor;
21
22@Override
23public void robotInit() {
24   leftFrontMotor = new PWMSparkMax(0);
25   leftRearMotor = new PWMSparkMax(0);
26}
17class Robot : public frc::TimedRobot {
18   public:
19      void RobotInit() override {
20         m_frontLeftMotor.Set(0.5);
21         m_rearLeftMotor.Set(0.25);
22      }
23
24   private:
25      frc::PWMVictorSPX m_frontLeftMotor{0};
26      frc::PWMVictorSPX m_rearLeftMotor{0};
27
28   };

Lors de l’exécution, vous verrez une sortie qui ressemble à ceci:

********** Robot program starting **********
Error at frc.robot.Robot.robotInit(Robot.java:25): Unhandled exception: edu.wpi.first.hal.util.AllocationException: Code: -1029
PWM or DIO 0 previously allocated.
Location of the previous allocation:
        at frc.robot.Robot.robotInit(Robot.java:24)
        at edu.wpi.first.wpilibj.TimedRobot.startCompetition(TimedRobot.java:107)
        at edu.wpi.first.wpilibj.RobotBase.runRobot(RobotBase.java:373)
        at edu.wpi.first.wpilibj.RobotBase.startRobot(RobotBase.java:463)
        at frc.robot.Main.main(Main.java:23)

Location of the current allocation:
        at edu.wpi.first.hal.PWMJNI.initializePWMPort(Native Method)
        at edu.wpi.first.wpilibj.PWM.<init>(PWM.java:66)
        at edu.wpi.first.wpilibj.motorcontrol.PWMMotorController.<init>(PWMMotorController.java:27)
        at edu.wpi.first.wpilibj.motorcontrol.PWMSparkMax.<init>(PWMSparkMax.java:35)
        at frc.robot.Robot.robotInit(Robot.java:25)
        at edu.wpi.first.wpilibj.TimedRobot.startCompetition(TimedRobot.java:107)
        at edu.wpi.first.wpilibj.RobotBase.runRobot(RobotBase.java:373)
        at edu.wpi.first.wpilibj.RobotBase.startRobot(RobotBase.java:463)
        at frc.robot.Main.main(Main.java:23)

Warning at edu.wpi.first.wpilibj.RobotBase.runRobot(RobotBase.java:388): The robot program quit unexpectedly. This is usually due to a code error.
  The above stacktrace can help determine where the error occurred.
  See https://wpilib.org/stacktrace for more information.
Error at edu.wpi.first.wpilibj.RobotBase.runRobot(RobotBase.java:395): The startCompetition() method (or methods called by it) should have handled the exception above.

Cette trace de pile montre qu’une edu.wpi.first.hal.util.AllocationException s’est produite. Il donne également le message utile: PWM or DIO 0 previously allocated. ou PWM ou DIO préalablement alloué.

Looking at our stack trace, we see two stack traces. The first stack trace shows that the first allocation occurred in Robot.java:25. The second stack trace shows that the error actually happened deep within WPILib. However, we should start by looking in our own code. Halfway through the stack trace, you can find a reference to the last line of the team’s robot code that called into WPILib: Robot.java:25.

Taking a peek at the code, we see line 24 is where the first motor controller is declared and line 25 is where the second motor controller is declared. We can also note that both motor controllers are assigned to PWM output 0. This doesn’t make logical sense, and isn’t physically possible. Therefore, WPILib purposely generates a custom error message and exception to alert the software developers of a non-achievable hardware configuration.

En C++, vous ne verrez pas spécifiquement de trace de pile de ce problème. Au lieu de cela, vous recevrez des messages qui ressemblent à ce qui suit :

Error at PWM [C::31]: PWM or DIO 0 previously allocated.
Location of the previous allocation:
        at frc::PWM::PWM(int, bool) + 0x50 [0xb6f01b68]
        at frc::PWMMotorController::PWMMotorController(std::basic_string_view<char, std::char_traits<char> >, int) + 0x70 [0xb6ef7d50]
        at frc::PWMVictorSPX::PWMVictorSPX(int) + 0x3c [0xb6e9af1c]
        at void frc::impl::RunRobot<Robot>(wpi::priority_mutex&, Robot**) + 0xa8 [0x13718]
        at int frc::StartRobot<Robot>() + 0x3d4 [0x13c9c]
        at __libc_start_main + 0x114 [0xb57ec580]

Location of the current allocation:: Channel 0
        at  + 0x5fb5c [0xb6e81b5c]
        at frc::PWM::PWM(int, bool) + 0x334 [0xb6f01e4c]
        at frc::PWMMotorController::PWMMotorController(std::basic_string_view<char, std::char_traits<char> >, int) + 0x70 [0xb6ef7d50]
        at frc::PWMVictorSPX::PWMVictorSPX(int) + 0x3c [0xb6e9af1c]
        at void frc::impl::RunRobot<Robot>(wpi::priority_mutex&, Robot**) + 0xb4 [0x13724]
        at int frc::StartRobot<Robot>() + 0x3d4 [0x13c9c]
        at __libc_start_main + 0x114 [0xb57ec580]

Error at RunRobot: Error: The robot program quit unexpectedly. This is usually due to a code error.
  The above stacktrace can help determine where the error occurred.
  See https://wpilib.org/stacktrace for more information.

        at void frc::impl::RunRobot<Robot>(wpi::priority_mutex&, Robot**) + 0x1c8 [0x13838]
        at int frc::StartRobot<Robot>() + 0x3d4 [0x13c9c]
        at __libc_start_main + 0x114 [0xb57ec580]

terminate called after throwing an instance of 'frc::RuntimeError'
  what():  PWM or DIO 0 previously allocated.
Location of the previous allocation:
        at frc::PWM::PWM(int, bool) + 0x50 [0xb6f01b68]
        at frc::PWMMotorController::PWMMotorController(std::basic_string_view<char, std::char_traits<char> >, int) + 0x70 [0xb6ef7d50]
        at frc::PWMVictorSPX::PWMVictorSPX(int) + 0x3c [0xb6e9af1c]
        at void frc::impl::RunRobot<Robot>(wpi::priority_mutex&, Robot**) + 0xa8 [0x13718]
        at int frc::StartRobot<Robot>() + 0x3d4 [0x13c9c]
        at __libc_start_main + 0x114 [0xb57ec580]

Location of the current allocation:: Channel 0

La chose clé à noter ici est la chaîne de caractères,``PWM or DIO 0 previously allocated.``. Cette chaîne est votre principal indice que quelque chose dans le code a incorrectement « doublement assigné » l’utilisation de la broche 0.

L’exemple de message ci-dessus a été généré sur un roboRIO. Si vous l’exécutez en simulation, cela peut sembler différent.

Résoudre les problèmes de ressources HAL déjà allouées

HAL : Resource already allocated sont quelques-unes des erreurs les plus simples à corriger. Passez juste un peu de temps à regarder le câblage électrique du robot et comparez-le à ce qui est dans le code.

In the example, the left motor controllers are plugged into PWM ports 0 and 1. Therefore, corrected code would look like this:

19PWMSparkMax leftFrontMotor;
20PWMSparkMax leftRearMotor;
21
22@Override
23public void robotInit() {
24
25   leftFrontMotor = new PWMSparkMax(0);
26   leftRearMotor = new PWMSparkMax(1);
27
28}
:lineno-start: 17

class Robot : public frc::TimedRobot {
   public:
      void RobotInit() override {
         m_frontLeftMotor.Set(0.5);
         m_rearLeftMotor.Set(0.25);
      }

   private:
      frc::PWMVictorSPX m_frontLeftMotor{0};
      frc::PWMVictorSPX m_rearLeftMotor{1};

   };

gradlew n’est pas reconnu…

gradlew n'est pas reconnu comme une commande interne ou externe est une erreur courante qui peut se produire lorsque le projet ou le répertoire dans lequel vous vous trouvez actuellement ne contient pas de fichier gradlew. Cela se produit généralement lorsque vous ouvrez le mauvais répertoire.

Image indiquant que la barre latérale gauche de VS Code ne contient pas gradlew

Dans la capture d’écran ci-dessus, vous pouvez voir que la barre latérale de gauche ne contient pas beaucoup de fichiers. Au minimum, VS Code a besoin de quelques fichiers pour créer et déployer correctement votre projet.

  • gradlew

  • build.gradle

  • gradlew.bat

Si vous ne voyez aucun des fichiers ci-dessus dans votre répertoire de projet, alors vous avez deux causes possibles.

  • Un projet corrompu ou mauvais.

  • Vous êtes dans le mauvais répertoire.

La correction de gradlew n’est pas reconnue…

gradlew n'est pas reconnu... est un problème assez facile à résoudre. Identifiez d’abord la source du problème :

Êtes-vous dans le mauvais répertoire ? - Vérifiez que le répertoire du projet est le bon répertoire et ouvrez-le.

Votre projet manque-t-il des fichiers essentiels ? - Ce problème est plus complexe à résoudre. La solution recommandée est de recréer votre projet et de copier manuellement le code nécessaire.